What to use instead of LPTSTR in java JNA?

那年仲夏 提交于 2020-01-06 17:58:06

问题


I am adding User32Ext methods to JNI. In particular, I extended the original UserExt class:

 package sirius.core;

 import com.sun.jna.Native;
 import com.sun.jna.Pointer;
 import com.sun.jna.platform.win32.Kernel32;
 import com.sun.jna.platform.win32.WinDef;
 import com.sun.jna.platform.win32.WinNT;
 import com.sun.jna.win32.W32APIOptions;

 public abstract interface Kernel32Ext
   extends Kernel32
 {
   public static final Kernel32Ext INSTANCE = (Kernel32Ext)Native.loadLibrary("kernel32.dll", Kernel32Ext.class, W32APIOptions.DEFAULT_OPTIONS);

   public abstract Pointer VirtualAllocEx(WinNT.HANDLE paramHANDLE, Pointer paramPointer, int paramInt, WinDef.DWORD paramDWORD1, WinDef.DWORD paramDWORD2);
   public abstract boolean VirtualFreeEx(WinNT.HANDLE paramHANDLE, Pointer paramPointer, int paramInt, WinDef.DWORD paramDWORD);
 }

I want to add the GetModuleFileNameEx function.

I'd write it like this:

public abstract DWORD getModuleFileName(WinNT.HANDLE hProcess, WinNT.HMODULE hModule, WinNT.LPTSTR pathString, WinNT.DWORD pathStringLength);

But WinNT.LPTSTR is not defined. It's apparently supposed to be a pointer (to char I guess?). So, how do I finish this?


回答1:


First of all, I am sorry for my incorrect answer for you

So, I've tested your code right after receiving your question again. I have to make my own class for this issue.

Let's look at the prototype of the GetModuleFileName

DWORD WINAPI GetModuleFileName(
  _In_opt_ HMODULE hModule,
  _Out_    LPTSTR  lpFilename,
  _In_     DWORD   nSize
);

Your prototype is for the GetModuleFileNameEx not for the GetModuleFileName. link

The main point i missed is the lpFilename argument that must be muttable object.

It can be any muttable objects like array of char or array of bytes as a prameter.

I think we can not use the String class as a parameter because it's an immutable class.

I figured that the GetModuleFileName is recommended than the GetModuleFileNameEx from the msdn site.

You can find at the middle of the article they say,

To retrieve the name of a module in the current process, use the GetModuleFileName function. This is more efficient and more reliable than calling GetModuleFileNameEx with a handle to the current process

There are two conditions here. First, My OS is Windows 7 Ultimate 64-bit Second, you and i have a different developer environment.

I downloaded the latest jna.jar and jna-platform.jar from the original site.

I have tested four different methods..one of them is failed.

My entry point is as following

public static void main(String[] args) {
        testCopyFile();
                printProcesses();
        testAllocFree(PROCESSID);
        testAllocFree2(PROCESSID);
        testModuleFileName(PROCESSID);
        testModuleFileName2(PROCESSID);
    }

The testCopyFile method just copy some text file with a different approach to yours.

private static void testCopyFile() {
        Function copyFunc = Function.getFunction("kernel32", "CopyFileA");
        Object[] params = new Object[3];
        params[0] = "C:\\DEV\\temp\\_info.txt";
        params[1] = "C:\\DEV\\temp\\_info2.txt";
        params[2] = false;
        copyFunc.invoke(params);
    }

The Function class, Object as parameters and invoke method of the Function class are needed by implementing the same function.

Next one is to find process id for the test.

private static void printProcesses()
    {
        Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();

        HANDLE snapshot = Kernel32Me.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS,
                new DWORD(0));
        try {
            while (Kernel32Me.INSTANCE.Process32Next(snapshot, processEntry)) {
                System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile));
            }
        } finally {
            Kernel32Me.INSTANCE.CloseHandle(snapshot);
        }
    }

Just pick the one of them displayed on the screen. For convenient reason, I first tested two methods with common functions, VirtualAllocEx and VirtualFreeEx.

I tested it successfully done..

The following two different methods, testAllocFree and testAllocFree2 functions result the same output.

private static void testAllocFree(final int processId) {
        SIZE_T dwSize = new SIZE_T(1024);

        DWORD  flAllocationType = new DWORD(Kernel32Me.MEM_RESERVE | Kernel32Me.MEM_COMMIT);
        DWORD  flProtect = new DWORD(Kernel32Me.PAGE_READWRITE);
        Pointer allocPoint = null;
        boolean ret = false;
        DWORD options 
            = new DWORD(
                Kernel32Me.PROCESS_VM_OPERATION | 
                Kernel32Me.PROCESS_VM_WRITE | 
                Kernel32Me.PROCESS_VM_READ | 
                Kernel32Me.PROCESS_CREATE_THREAD | 
                Kernel32Me.PROCESS_QUERY_INFORMATION);

        DWORD procs = new DWORD(processId);

        HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);

        if(null == hProcess)
        {
            System.err.println("Can't have a handle for you..sorry");
            return;
        }

        try
        {
            allocPoint = Kernel32Me.INSTANCE.VirtualAllocEx(hProcess, null, dwSize, flAllocationType, flProtect);

            if(allocPoint==null)
            {
                System.err.println("Can't get a memory resource for you..sorry");
                int c = Kernel32Me.INSTANCE.GetLastError();
                System.out.println("\t>>" + c);
                //c = Native.getLastError();
                //System.out.println("\t" + c);
            }

            if (allocPoint != null) {
                dwSize = new SIZE_T(0);
                DWORD freeType = new DWORD(Kernel32Me.MEM_RELEASE);
                System.err.println("allocPoint >>==> " + allocPoint.toString());
                ret = Kernel32Me.INSTANCE.VirtualFreeEx(hProcess, allocPoint, dwSize, freeType);

                if(!ret)
                {
                    int c = Kernel32Me.INSTANCE.GetLastError();
                    System.out.println("\t" + c);
                    c = Native.getLastError();
                    System.out.println("\t" + c);
                }
                else
                {
                    System.out.println("\t Free success");
                }
            }
        }
        finally
        {
            Kernel32Me.INSTANCE.CloseHandle(hProcess);
        }


    }

And,

private static void testAllocFree2(final int processId) {
        Function allocFunc = Function.getFunction("kernel32", "VirtualAllocEx");
        Function freeFunc = Function.getFunction("kernel32", "VirtualFreeEx");
        DWORD  flAllocationType = new DWORD(Kernel32Me.MEM_RESERVE | Kernel32Me.MEM_COMMIT);
        DWORD  flProtect = new DWORD(Kernel32Me.PAGE_READWRITE);
        SIZE_T dwSize = new SIZE_T(1024);

        DWORD freeType = new DWORD(Kernel32Me.MEM_RELEASE);
        DWORD options 
            = new DWORD(
                Kernel32Me.PROCESS_VM_OPERATION | 
                Kernel32Me.PROCESS_VM_WRITE | 
                Kernel32Me.PROCESS_VM_READ | 
                Kernel32Me.PROCESS_CREATE_THREAD | 
                Kernel32Me.PROCESS_QUERY_INFORMATION);

        DWORD procs = new DWORD(processId);

        Pointer allocPoint = null;

        HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);

        if(null == hProcess)
        {
            System.err.println("Can't have a handle for you..sorry");
            return;
        }

        Object[] inArgs = new Object[5];
        inArgs[0] = hProcess;
        inArgs[1] = null;
        inArgs[2] = dwSize;
        inArgs[3] = flAllocationType;
        inArgs[4] = flProtect;

        allocPoint = (Pointer) allocFunc.invoke(Pointer.class, inArgs);

        try
        {
            if(allocPoint==null)
            {
                System.err.println("Can't get a memory resource for you..sorry");
                int c = Kernel32Me.INSTANCE.GetLastError();
                System.out.println("\t>>" + c);
                //c = Native.getLastError();
                //System.out.println("\t" + c);
            }

            if (allocPoint != null) {
                Object[] inArgs2 = new Object[4];
                inArgs2[0] = hProcess;
                inArgs2[1] = allocPoint;
                inArgs2[2] = new SIZE_T(0);
                inArgs2[3] = freeType;
                System.err.println("allocPoint ==> " + allocPoint.toString());
                freeFunc.invoke(inArgs2);
            }
        }
        finally
        {
            Kernel32Me.INSTANCE.CloseHandle(hProcess);
        }
    }

Finally, the GetModuleFileName and GetModuleFileNameA function tested below

private static void testModuleFileName(final int processId)
    {
        DWORD nSize = new DWORD(256);
        char lpFilename[] = new char[256];
        byte bFilename[] = new byte[256];
        String strFileName = new String();
        DWORD options = new DWORD(Kernel32Me.PROCESS_VM_READ | Kernel32Me.PROCESS_QUERY_INFORMATION);
        DWORD procs = new DWORD(processId);

        HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options,false, procs);

        if(null == hProcess)
        {
            System.err.println("Can't have a handle for you..sorry");
            return;
        }

        try
        {
            Kernel32Me.INSTANCE.GetModuleFileName(null, lpFilename, nSize);
            System.err.println("module path is " + new String(lpFilename));

            Kernel32Me.INSTANCE.GetModuleFileName(null, bFilename, nSize);
            System.err.println("module path is " + new String(bFilename));

            Kernel32Me.INSTANCE.GetModuleFileNameEx(hProcess, null, strFileName, nSize);
            System.err.println("module path is " + strFileName);

        }
        finally
        {
            Kernel32Me.INSTANCE.CloseHandle(hProcess);
        }
    }

I have two prototypes, one is array bytes and another is array of chars used in the code.

DWORD GetModuleFileName(HMODULE hModule, char[] lpFilename, DWORD nSize);
DWORD GetModuleFileName(HMODULE hModule, byte[] lpFilename, DWORD nSize);

The third one didn't working as i mentioned at the start which told me the UnsatisfiedLinkError.. I don't know why..

DWORD GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, String lpFilename, DWORD nSize);

Another implementation is also the same..look at the code

private static void testModuleFileName2(final int processId)
    {
        Function allocFunc = Function.getFunction("kernel32", "GetModuleFileName");

        DWORD nSize = new DWORD(256);
        char[] lpFilename = new char[256];

        DWORD procs = new DWORD(processId);
        DWORD options 
            = new DWORD(
                Kernel32Me.PROCESS_VM_READ | 
                Kernel32Me.PROCESS_QUERY_INFORMATION);

        HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);

        if(null == hProcess)
        {
            System.err.println("Can't have a handle for you..sorry");
            return;
        }

        try
        {
            Object[] inArgs = new Object[3];
            inArgs[0] = null;
            inArgs[1] = lpFilename;
            inArgs[2] = nSize;
            allocFunc.invoke(inArgs);
            System.err.println("module path is " + new String(lpFilename));
        }
        finally
        {
            Kernel32Me.INSTANCE.CloseHandle(hProcess);
        }


    }

I found both methods not working finally.

Function allocFunc = Function.getFunction("kernel32", "GetModuleFileName");
Function allocFunc = Function.getFunction("kernel32", "GetModuleFileNameEx");

show me the not found procedure message...

java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileName' java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileNameEx'

I have to dig it more about these errors at some time near future.

Last one...Here is a main prototype class

public interface Kernel32Me extends StdCallLibrary {
        final Kernel32Me INSTANCE 
            = (Kernel32Me) Native.loadLibrary("kernel32.dll", Kernel32Me.class, W32APIOptions.DEFAULT_OPTIONS);

        //https://msdn.microsoft.com/en-us/library/windows/desktop/aa366890(v=vs.85).aspx
        int PROCESS_CREATE_THREAD = 0x0002;
        int PAGE_EXECUTE_READWRITE = 0x40;
        int PROCESS_QUERY_INFORMATION = 0x0400;
        int PROCESS_VM_OPERATION = 0x0008;
        int PROCESS_VM_WRITE = 0x0020;
        int PROCESS_VM_READ = 0x0010;
        int PAGE_READWRITE = 0x04;
        int MEM_RESERVE = 0x00002000;
        int MEM_COMMIT = 0x00001000;
        int MEM_RESET = 0x00080000;
        int MEM_DECOMMIT = 0x4000;
        int MEM_RELEASE = 0x8000;


        Pointer VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);

        boolean VirtualFreeEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, DWORD dwFreeType);

        DWORD GetModuleFileName(HMODULE hModule, char[] lpFilename, DWORD nSize);
        DWORD GetModuleFileName(HMODULE hModule, byte[] lpFilename, DWORD nSize);
        DWORD GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, String lpFilename, DWORD nSize);

        HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID);

        boolean Process32First(HANDLE hSnapshot, PROCESSENTRY32 lppe);

        boolean Process32Next(HANDLE hSnapshot, PROCESSENTRY32 lppe);

        HANDLE OpenProcess(DWORD dwDesiredAccess, boolean bInheritHandle, DWORD dwProcessId);

        boolean CloseHandle(HANDLE hObject);

        int GetLastError();
    }

The output might look like below

0   [System Process]
4   System
280 smss.exe
444 csrss.exe
536 wininit.exe
544 csrss.exe
7860    chrome.exe
8132    chrome.exe
7808    chrome.exe
7516    chrome.exe
6176    chrome.exe
8156    chrome.exe
7120    chrome.exe
7476    chrome.exe
8016    chrome.exe
5616    devmonsrv.exe
1644    chrome.exe
6548    chrome.exe
5960    chrome.exe
5636    chrome.exe
8260    chrome.exe
3440    notepad.exe
8844    chrome.exe
9416    chrome.exe
6744    chrome.exe
6032    chrome.exe
9724    javaw.exe
     Free success
allocPoint >>==> native@0x34d0000
allocPoint ==> native@0x34d0000
module path is C:\DEV\COMP\Java\jdk1.7\bin\javaw.exe
module path is C.... <== The output is strange...
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileNameEx':

You need to use array of char than array of byte avoiding character encoding problem.

My import statements are,

import com.sun.jna.Function;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.Tlhelp32.PROCESSENTRY32;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

You can use the methods below in turn.

printProcesses(); testModuleFileName(PROCESSID);

private static final int PROCESSID = 3440; // the process id from printProcesses();
    public static void main(String[] args) {
            printProcesses();
            testModuleFileName(PROCESSID);
        }

I hope this may help you

P.S

Finally, I've got my own answer for this issue... It can be done with Psapi interface... Here is my final test method...

private static void testModuleFileName2(final int processId) {
    DWORD nSize = new DWORD(260);
    char lpFilename[] = new char[260];
    byte bFilename[] = new byte[260];

    DWORD options = new DWORD(Kernel32Me.PROCESS_VM_READ | Kernel32Me.PROCESS_QUERY_INFORMATION);
    DWORD procs = new DWORD(processId);

    HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);

    if (null == hProcess) {
        System.err.println("Can't have a handle for you..sorry");
        return;
    }

    HMODULE handle = Kernel32.INSTANCE.GetModuleHandle("kernel32.dll");

    if (null == handle) {
        System.err.println("Can't have a handle for you..sorry");
        return;
    }

    try {
        Kernel32Me.INSTANCE.GetModuleFileName(handle, lpFilename, nSize);
        System.err.println("2> module path is " + new String(lpFilename));

        Psapi.INSTANCE.GetModuleFileNameExA(hProcess, handle, bFilename, 260);
        System.err.println("2> module path is " + new String(bFilename));

        Psapi.INSTANCE.GetModuleFileNameExW(hProcess, null, lpFilename, 260);
        System.err.println("2> module path is " + new String(lpFilename));

    } finally {
        Kernel32Me.INSTANCE.CloseHandle(hProcess);
    }
}

I opened a notepad.exe and got a its process id

Then, I called this method.



来源:https://stackoverflow.com/questions/43822087/what-to-use-instead-of-lptstr-in-java-jna

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!