为什么调用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);
}
答案 0 :(得分:2)
问题是您尚未将本机(C)内存读取到Java Memory
缓冲区中。分配new Memory(256)
时,您将获得Java对象的内存以及本机端的256字节缓冲区,并带有传递给C的指针。当使用该指针执行GetVersionExA()
时,将填充(带有该数据的本机缓冲区的一部分)(具体地说,前148个字节将获得5个4字节的值和128个字节的值,而其余108个字节将保留该内存中的任何随机字节)。但是,您没有做的就是从该本地缓冲区中将字节读取到Java Memory
对象的字节中。
虽然您可以通过调用a.read()
来将本机内存复制到缓冲区中来解决此问题,但是使用这些字节进行任何操作都涉及对字节级信息的手动操作,这不是很容易理解的代码。 (如果您不注意所知道的148个字节的范围,那将很危险。)
问题的根源是您的映射:实际上,GetVersionExA()
的文档说它返回了OSVERSIONINFOA
结构时,您在参数上放置了Pointer
。此结构在JNA中为already mapped。
JNA的Structure
仅需要148个字节,而无需进行数学运算,它会自动为您完成。在函数中使用结构时,结构还会自动调用read()
方法,您将准备好所有数据以方便检索。
因此摆脱您的内存分配和字节缓冲区,只需使用WinNT.OSVERSIONINFOEX
类型的新结构调用此方法即可。
此外,JNA还已经映射了GetVersionEx()
(并使用函数映射器自动选择了A或W版本)。因此,您甚至不需要自己定义。您的代码可简化为:
OSVERSIONINFOEX info = new OSVERSIONINFOEX();
Kernel32.INSTANCE.GetVersionEx(info);
int majorVersion = info.dwMajorVersion.intValue(); // etc.