Search code examples
jna

how to get JNA read back function's string result


public interface Kernel32 extends StdCallLibrary {

    int GetComputerNameW(Memory lpBuffer, IntByReference lpnSize);
}

public class Kernel32Test {

    private static final String THIS_PC_NAME = "tiangao-160";

    private static Kernel32 kernel32;

    @BeforeClass
    public static void setUp() {
    System.setProperty("jna.encoding", "GBK");
    kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    }

    @AfterClass
    public static void tearDown() {
    System.setProperty("jna.encoding", null);
    }

    @Test
    public void testGetComputerNameW() {
        final Memory lpBuffer = new Memory(1024);
        final IntByReference lpnSize = new IntByReference();

        final int result = kernel32.GetComputerNameW(lpBuffer, lpnSize);

        if (result != 0) {
            throw new IllegalStateException(
            "calling 'GetComputerNameW(lpBuffer, lpnSize)'failed,errorcode:" + result);
        }

        final int bufferSize = lpnSize.getValue();
        System.out.println("value of 'lpnSize':" + bufferSize);
        Assert.assertEquals(THIS_PC_NAME.getBytes().length + 1, bufferSize);

        final String name = lpBuffer.getString(0);
        System.out.println("value of 'lpBuffer':" + name);
        Assert.assertEquals(THIS_PC_NAME, name);
   }
}

The offical instructions says use byte[]、char[]、Memory or NIO Buffer for mapping char pointer in c native function.But I tried all of above, and String、WString、StringArrays、class extends PointType etc, all of them are no use.

Out parameter 'lpnSize' can return the corret buffer size,but 'lpBuffer' return 'x>'(i think it's random memory) or nothing no matter I mapping any java type.If i wrote someting to the 'lpBuffer' memory first, it would read the same things after calling native function.

How can I solve the problem?


Solution

  • You need to use Pointer.getString(0, true) to extract the unicode string returned by GetComputerNameW.

    EDIT

    You'll also need to call GetComputerNameW again with the length parameter initialized before the function will fill in the result. Either pass back the same IntByReference to a second call, or initialize the IntByReference to the size of your Memory buffer to have the buffer written to in the first call.