【问题标题】:What to use instead of LPTSTR in java JNA?java JNA中用什么代替LPTSTR?
【发布时间】:2017-05-06 15:17:39
【问题描述】:

我正在向 JNI 添加 User32Ext 方法。特别是,我扩展了原来的 UserExt 类:

 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 ?)。那么,我该如何完成呢?

【问题讨论】:

  • 使用String类检查其他人的答案stackoverflow.com/questions/5308655/…
  • @tommybee 字符串类无法通过引用接收值。我试过char[],但没用。
  • 调用Unicode接口,LPTSTR为wchar_t*
  • LPTSTRTCHAR*,如果 UNICODE 被定义,TCHARwchar_t,如果没有定义 char。 (具体来说,如果定义了UNICODE,则为LPWSTRWCHAR*,其中WCHARwchar_t),否则为LPSTRCHAR*,其中CHARchar)。 ) 因此,您可能可以以此为基础定义您的定义。 [参考:Windows Data Types (MSDN).]

标签: java c++ winapi java-native-interface jna


【解决方案1】:

首先,很抱歉我给你的回答不正确

所以,我在再次收到您的问题后立即测试了您的代码。 我必须为这个问题创建自己的课程。

我们看一下GetModuleFileName

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

您的原型是为 GetModuleFileNameEx 而不是 GetModuleFileNamelink

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

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

我认为我们不能使用 String 类作为参数,因为它是一个不可变类。

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

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

要检索当前进程中的模块名称,请使用 GetModuleFileName 函数。这样更高效、更可靠 而不是使用当前进程的句柄调用 GetModuleFileNameEx

这里有两个条件。 首先,我的操作系统是 Windows 7 Ultimate 64-bit 其次,你我有不同的开发环境。

我从原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类,Object作为参数,Function类的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: 查找函数时出错 'GetModuleFileName' java.lang.UnsatisfiedLinkError:查找错误 函数'GetModuleFileNameEx'

我必须在不久的将来的某个时间深入挖掘这些错误。

最后一个...这是一个主要的原型类

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

您需要使用字符数组而不是字节数组以避免字符编码问题。

我的导入语句是,

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

希望对你有帮助

附言

最后,我对这个问题有了自己的答案...... 可以用 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

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

【讨论】:

  • 嗯,简短的回答是可以使用char[],但感谢您发布所有这些。感谢所有这些使用 winapi 的示例,我相信这将对我将来有所帮助!
猜你喜欢
  • 2020-03-20
  • 1970-01-01
  • 2020-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
相关资源
最近更新 更多