在 java JNA 中用什么代替 LPTSTR?

What to use instead of LPTSTR in java JNA?

我正在向 JNI 添加 User32Ext 方法。特别是,我扩展了原来的 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);
 }

我想添加GetModuleFileNameEx功能。

我会这样写:

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

但是WinNT.LPTSTR没有定义。它显然应该是一个指针(我猜是指向 char?)。那么,我该如何完成呢?

首先,对于我给您错误的回答,我深表歉意

所以,我再次收到您的问题后立即测试了您的代码。 我必须为这个问题制作自己的class。

我们来看看GetModuleFileName

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

您的原型适用于 GetModuleFileNameEx,不适用于 GetModuleFileNamelink

我错过的要点是必须是可变对象的 lpFilename 参数。

它可以是任何可变对象,例如 char 数组或字节数组作为参数。

我认为我们不能使用字符串 class 作为参数,因为它是一个 不可变的 class.

我认为 GetModuleFileName 比 msdn 中的 GetModuleFileNameEx 更推荐 site

你可以在文章中间找到他们说的,

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

这里有两个条件。 首先,我的 OS 是 Windows 7 Ultimate 64 位 其次,你我的开发环境不同。

我从原来的site下载了最新的jna.jarjna-platform.jar .

我测试了四种不同的方法..其中一种失败了。

我的切入点如下

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

testCopyFile 方法只是用与您不同的方法复制一些文本文件。

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);
    }

Function class, 对象作为参数和Function class 的invoke 方法需要实现相同的功能。

下一步是为测试查找进程ID。

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);
        }
    }

只需选择屏幕上显示的其中一项即可。 为了方便起见,我先测试了VirtualAllocEx和VirtualFreeEx这两个功能通用的方法。

我测试成功了..

以下两种不同的方法,testAllocFree 和 testAllocFree2 函数产生相同的输出。

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);
        }


    }

而且,

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);
        }
    }

最后,下面测试的GetModuleFileName和GetModuleFileNameA函数

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);
        }
    }

我有两个原型,一个是字节数组,另一个是代码中使用的字符数组。

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

第三个没有像我在开始时提到的那样工作,它告诉我 UnsatisfiedLinkError.. 不知道为什么..

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

另一个实现也是一样的..看代码

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);
        }


    }

我发现这两种方法最终都不起作用。

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

显示未找到程序消息...

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

我必须在不久的将来对这些错误进行更多挖掘。

最后一个...这是主要原型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();
    }

输出可能如下所示

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':

您需要使用 char 数组而不是 byte 数组来避免字符编码问题。

我的导入语句是,

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;

您可以依次使用以下方法。

printProcesses(); testModuleFileName(PROCESSID);

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

希望对您有所帮助

P.S

终于,我对这个问题有了自己的答案... 可以用Psapi接口来完成... 这是我最终的测试方法...

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);
    }
}

我打开了一个 notepad.exe 并得到了它的进程 ID

然后,我调用了这个方法。