java - 调用winapi函数后清空缓冲区

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

最佳答案

问题是您尚未将 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/

相关文章:

java - Android Studio中调用jar库

Delphi Dll函数中的Java JNA映射

java - Jaxb 复杂的 xml 解码

java - 具有历史 API 的 Wicket AjaxEventBehavior

java - Android - openCV,获取图像的一部分 - 奇怪的行为

java - 使用 JNA 创建 COM 对象的对象,我没有 .class

java - 从java中的c++/c#程序读取共享内存

c - 如何用C/C++实现键盘缓冲窗口无阻塞

c++ - 将Win32对话框中的图标设置为默认图标

c++ - WndProc 的类方法