I'm using JNA to call into a C library from Java.
In my C code I have:
void printStructArray( SomeStruct **someStruct, int arraySize );
This expects an array of pointers to struct, ie the method does this:
void printStructArray( SomeStruct **someStruct, int arraySize ) {
for( int i = 0; i < arraySize; i++ ) {
cout << "someStruct: " << someStruct[i]->aLong << " " << someStruct[i]->aString << " " << someStruct[i]->aDouble << endl;
}
}
It's just a toy example, but I have an actual library I want to talk to which needs the same type of argument, but I think using a toy example is easier to explain here?
I've tried all sorts of things, but I'm not sure how to (i) declare this function in JNA (ii) call this function in JNA.
My latest (failed) attempt is:
SomeStruct.byReference[] structs = new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) };
PointerByReference pointerByReference = new PointerByReference(structs[0].getPointer());
JniTest.instance.printStructArray(pointerByReference, 3);
This causes a SIGSEGV.
Alternatively:
SomeStruct.byReference[] structs = (SomeStruct.byReference[]) new SomeStruct().toArray( new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) } );
PointerByReference pointerByReference = new PointerByReference(structs[0].getPointer());
JniTest.instance.printStructArray(pointerByReference, 3);
This causes an ArrayStoreException
Tried this also:
SomeStruct.byReference[] structs = new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) }; JniTest.instance.printStructArray(structs, 3);
With method declared as:
void printStructArray(SomeStruct.byReference[] someStructarray, int num);
This gives '0' as the output from the function, although the good point is it doesn't crash, but it's not giving correct behavior either.
Thoughts?
It's sufficient to pass your array of Structure.ByReference; the address of the array is passed to the native code. JNA automatically allocates the space for the array of pointers, which goes out of scope after the function call.
PointerByReference is intended to pass a pointer value by reference (i.e. the callee may alter the value). It is not appropriate in this case.
I've just found a solution that works quite nicely, which is to use BridJ instead of JNA. Maybe there is a way to get JNA working, but it doesn't seem obvious. BridJ is really easy to use:
Declaration:
public static native void printStructArray(Pointer<Pointer<SomeStruct > > someStruct, int arraySize);
Usage:
Pointer<Pointer<SomeStruct>> pointers = Pointer.allocatePointers(SomeStruct.class, 3);
pointers.set(0, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
pointers.set(1, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
pointers.set(2, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
JnitestLibrary.printStructArray(pointers, 3 );
It seems they dont support structures by value, but I dont have any structures by value in my current interface, so that's not a problem for me right now. Apparently performance is ok, but I haven't tested performance personally.
Note that I'm still open to JNA solutions, and will tick anyone who can give me a working JNA solution to the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With