为什么调用 winapi 函数后缓冲区为空,如何修复?
public interface Kernel32 extends Library {
public boolean GetVersionExA(Pointer lpBuffer);
}
public func(){
Kernel32 lib = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
Pointer a = new Memory(256);
lib.GetVersionExA(a);
byte[] b=new byte[256];
b = a.getByteArray(0,256);
}
最佳答案
问题是您尚未将 native (C) 内存读入 Java Memory
缓冲区。当您分配new Memory(256)
时,您将获得Java对象的内存以及 native 端的256字节缓冲区,并带有传递给C的指针。当您执行GetVersionExA时()
使用该指针,您可以用数据填充该 native 缓冲区(的一部分)(具体来说,前 148 个字节将获取 5 个 4 字节值和 128 字节值,并保留其他 108 字节)与该内存中发生的任何随机字节一起)。但是您没有做的是将 native 缓冲区中的字节读取到 Java Memory
对象的字节中。
虽然您可以通过调用 a.read()
将 native 内存复制到缓冲区中来解决此问题,但对这些字节执行任何操作都涉及手动操作字节级信息,这不是非常可读的代码。 (如果你不注意你所知道的 148 字节的边界,那就很危险了。)
问题的根源在于您的映射:您为参数放置了一个Pointer
,而实际上 GetVersionExA()
的文档说它返回 OSVERSIONINFOA
结构。这个结构是already mapped在 JNA。
只要获取 148 字节,无需进行数学计算,JNA 的 Structure
会自动为您完成此操作。在函数中使用时,结构还会自动调用 read()
方法,并且您将准备好所有数据以便轻松检索。
因此,摆脱内存分配和字节缓冲区,只需使用 WinNT.OSVERSIONINFOEX
类型的新结构调用此方法即可。
此外,JNA 已经映射 GetVersionEx()
以及(并使用函数映射器自动选择 A 或 W 版本)。所以你甚至不需要自己定义它。您的代码简化为:
OSVERSIONINFOEX info = new OSVERSIONINFOEX();
Kernel32.INSTANCE.GetVersionEx(info);
int majorVersion = info.dwMajorVersion.intValue(); // etc.
关于java - 调用winapi函数后清空缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57914400/