【问题标题】:Empty buffer after calling the winapi function调用winapi函数后清空缓冲区
【发布时间】:2019-09-12 20:58:03
【问题描述】:

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

【问题讨论】:

  • 是什么让你觉得它是空的? GetVersionExA() 是返回真还是假?顺便说一句,b = new byte[256] 是多余的,可以删除:byte[] b = a.getByteArray(0,256);
  • @RemyLebeau 我明白了,我的意思是返回零缓冲区

标签: java winapi jna


【解决方案1】:

问题是您没有将本机 (C) 内存读入 Java Memory 缓冲区。当您分配new Memory(256) 时,您将获得Java 对象的内存以及本机端的256 字节缓冲区,并带有一个传递给C 的指针。当您使用该指针执行GetVersionExA() 时,您填充( ) 带有数据的本机缓冲区(具体来说,前 148 个字节将获得五个 4 字节值和 128 字节值,而其余 108 个字节则与该内存中碰巧出现的任何随机字节一起保留)。但是您没有做的是从本机缓冲区读取字节到 Java Memory 对象的字节中。

虽然您可以通过调用 a.read() 将本机内存复制到缓冲区中来解决此问题,但对这些字节进行任何操作都涉及手动操作字节级信息,这不是可读的代码。 (如果你不注意你所知道的 148 字节的边界,那就很危险了。)

问题的根源在于您的映射:您为参数添加了Pointer,而实际上GetVersionExA() 的文档说它返回OSVERSIONINFOA 结构。这个结构在 JNA 中是 already mapped

只要获得 148 字节,无需进行数学运算,JNA 的Structure 会自动为您完成。结构体在函数中使用时也会自动调用read() 方法,您将准备好所有数据以方便检索。

所以摆脱您的内存分配和字节缓冲区,只需使用WinNT.OSVERSIONINFOEX 类型的新结构调用此方法。

此外,JNA 也已经映射了GetVersionEx()(并使用函数映射器自动选择 A 或 W 版本)。所以你甚至不需要自己定义。您的代码简化为:

OSVERSIONINFOEX info = new OSVERSIONINFOEX();
Kernel32.INSTANCE.GetVersionEx(info);
int majorVersion = info.dwMajorVersion.intValue(); // etc.

【讨论】:

    猜你喜欢
    • 2019-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    相关资源
    最近更新 更多