Search code examples
javaandroidandroid-ndkjava-native-interfacejna

How to pass a com.sun.jna.Structure from Java to struct in C, using JNA


I'm going off of this example of how to pass a com.sun.jna.Structure containing a com.sun.jna.StringArray from Java into native C code using JNA, and having trouble obtaining the Structure contents successfully in the C code.

Note that I can pass a struct from the C code to a Structure in Java successfully, but I'm having trouble creating a Structure in the Java code and successfully sending it to the C code as a struct.

This is the code in question:

String[] user_name_array = new String[3];
user_name_array[0] = "test_user_1";
user_name_array[1] = "test_user_2";
user_name_array[2] = "test_user_3";
StringList.ByReference members = new StringList.ByReference();
members.length = 3;
members.strings = new StringArray(user_name_array);
MyNativeLibrary.myMethod(members);

Seems simple enough, but it's not working.

It gets into the C code successfully as expected, but the Pointer in the Structure is empty, and the length is zero.

Here is the StringList Structure in the Java:

public static class StringList extends Structure {
    public volatile long length;
    public volatile Pointer strings;
    public static class ByValue extends StringList implements Structure.ByValue {}
    public static class ByReference extends StringList implements Structure.ByReference {
        public ByReference() { }
        public ByReference(Pointer p) { super(p); read(); }
    }
    public StringList() { }
    public StringList(Pointer p) { super(p); read(); }
}

Here is the corresponding struct in the C code:

typedef struct string_list {
    uint64_t length;
    const char **strings;
} string_list;

And here is the method definition in the C code:

const char* my_method(struct string_list *members)
{
   //.................
}

Using ndk-gdb, and breaking into this function, this is what it shows:

(gdb) break my_method
(gdb) cont 
Continuing.

Breakpoint 1, my_method (members=0x9bee77b0) at ../app/my_code_file.c:368
(gdb) p *members
$1 = {length = 0, strings = 0x0}

It seems like it should work, so why aren't the values making it into the C code? What am I missing?

Also note that I can successfully send a StringArray directly to the C code from the Java code if it's not inside a Structure:

Java:

//This works!
StringList members = MyNativeLib.myTestFunction(3, new StringArray(user_name_array));

C:

//This works!
string_list* my_test_function(uint64_t length, const char **strings)
{
    //......
}

It seems that in this case, JNA works as expected. So, why doesn't it work with a Structure as the documentation states it should?


Solution

  • Don't mark the fields as volatile. When you do that, JNA won't write to them unless you do an explicit Structure.writeField().