Reputation: 125
Why do I have an empty buffer after calling the winapi function and how do I fix it?
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);
}
Upvotes: 0
Views: 79
Reputation: 9121
The problem is that you haven't read the native (C) memory into the Java Memory
buffer. When you allocate new Memory(256)
you get the Java object's memory as well as a 256-byte buffer on the native side, with a pointer which you pass to C. When you execute GetVersionExA()
using that pointer, you fill (a part of) that native buffer with data (Specifically, the first 148 bytes will get the five 4-byte values and the 128-byte value, and leave the other 108 bytes with whatever random bytes happened to be in that memory). But what you are not doing is reading the bytes from that native buffer into the bytes of the Java Memory
object.
While you could work around this by calling a.read()
to copy the native memory into your buffer, doing anything with those bytes involves manual manipulation of byte-level information, which isn't very readable code. (And dangerous if you don't watch the bounds of the 148 bytes you know about.)
The root of the problem is your mappings: You have put a Pointer
for the argument when in fact the documentation for GetVersionExA()
says that it returns a OSVERSIONINFOA
structure. This structure is already mapped in JNA.
As far as getting only 148 bytes, no need to do math, JNA's Structure
does that automatically for you. Structures also automatically call the read()
method when used in functions and you'll have all your data ready for easy retrieval.
So get rid of your memory allocation and byte buffer, and just call this method with a new structure of type WinNT.OSVERSIONINFOEX
.
Also, JNA has already mapped GetVersionEx()
as well (and automatically chooses the A or W version using a function mapper). So you don't even need to define that yourself. Your code simplifies to:
OSVERSIONINFOEX info = new OSVERSIONINFOEX();
Kernel32.INSTANCE.GetVersionEx(info);
int majorVersion = info.dwMajorVersion.intValue(); // etc.
Upvotes: 2