2

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?

Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • Possible duplicate of [passing string array from java to C with JNI](http://stackoverflow.com/questions/5972207/passing-string-array-from-java-to-c-with-jni) – Doug Stevenson Apr 15 '16 at 00:17
  • 2
    @DougStevenson It looks like that is a solution for how to pass a StringArray, not for how to pass a Structure containing a StringArray, so not a good dupe target.... – Daniel Nugent Apr 15 '16 at 00:23
  • 1
    You won't get automatic mapping of java structures to C structures. You'll have to programmatically pull the members of interest out of a passed jobject object using JNI, with string arrays being the most taxing thing to process. It's kind of a pain. – Doug Stevenson Apr 15 '16 at 00:25
  • Maybe this is more helpful. http://stackoverflow.com/questions/3923299/how-to-pass-c-structs-back-and-forth-to-java-code-in-jni – Doug Stevenson Apr 15 '16 at 00:28
  • Yeah, I think the function needs to accept a jobject and be mapped to the implementation of a java 'native' method. You can generate headers for the C-side of a java native method using the javah command line. There is a whole lot of ceremony involved in passing data around. It might also be worthwhile to look at SWIG which cuts a lot of that out. – Doug Stevenson Apr 15 '16 at 00:40
  • @DougStevenson Thanks for the info. Shouldn't JNA take care of the data mapping though? The documentation seems to suggest that: http://jna.java.net/nonav/javadoc/overview-summary.html#structures If that documentation is correct, it seems that the example I'm going from should be correct, right? – Daniel Nugent Apr 15 '16 at 03:47
  • If you build jna, include it, and specifically call through it on the Java side, sure. I haven't done this myself, but again, it's not going to jump in for free. – Doug Stevenson Apr 15 '16 at 04:02
  • @DougStevenson What's interesting is that if I use `StringArray` directly as a parameter, it does jump in for free! Going to just go with that for now since it works, but still interested in figuring out how to make it work with a Structure. Thanks again! – Daniel Nugent Apr 15 '16 at 04:05
  • 2
    Don't mark the fields as `volatile`. When you do that, JNA won't write to them unless you do an explicit `Structure.writeField()`. – technomage Apr 15 '16 at 15:24

1 Answers1

3

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

technomage
  • 9,861
  • 2
  • 26
  • 40