调用winapi函数后清空缓冲区

时间:2019-09-12 20:58:03

标签: java winapi jna

为什么调用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);
}

1 个答案:

答案 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.