How to pass array of structure containing character array to native function

1,232 views
Skip to first unread message

rob stew

unread,
May 23, 2013, 5:08:41 PM5/23/13
to Java Native Access
typedef struct sample1{

char temp1[100];
char temp2[100]

}S1
...
int manipulateTemp(S1 s1Arr[]);

JNA interface looks like this

public interface Add extends Library
{
Add INSTANCE = (Add) Native.loadLibrary("add", Add.class);

public static class S1 extends Structure {
public Pointer temp1
public Pointer temp2
public static class ByReference extends S1 implements
Structure.ByReference {

};
//Constructor
Sample1(){
temp1 = new Memory(100)
temp2 = new Memory(100)
};

int manipulateTemp(S1[] smaple1Arr);
}

//in main method
Add lib = Add.INSTANCE;
Add.S1.ByReference s1Ref = new Add.S1.ByReference();
Add.S1[] s1Arr = (Add.S1[])s1Ref.toArray(10);
//array of structure initialization code here..
for(int i =0;i<s1Arr.length;i++){
s1Arr[i].temp1=new Memory(100);
s1Arr[i].temp2 = new Memory(100);
}
char[] buff = new char[100];
buff = "ABC-DEF-GHI".toCharArray();
s1Arr[0].temp1.write(0, buff, 0, buff.length);
....similar to temp2
s1Arr[1]...... same
//call the function
lib.manipulateTemp(s1Arr)

--
After execution it gives me - It goes into infinite loop --
program does not exit / or sometimes exits with JVM failure.

Timothy Wall

unread,
May 23, 2013, 6:09:08 PM5/23/13
to jna-...@googlegroups.com
Array fields within a structure take up as much space as the size of the array.

Pointer fields within a structure take up the size of the pointer.

You can see how these two things are not the same.
> --
> You received this message because you are subscribed to the Google Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

rob stew

unread,
May 24, 2013, 8:28:57 AM5/24/13
to jna-...@googlegroups.com
Agreed..but when tried to use byte array for char array, it gives me error saying invalid memory access. I even tried to use System.Arraycopy () as suggested help on internet but it failed with invalid memory access error.
 
 

Timothy Wall

unread,
May 24, 2013, 1:52:04 PM5/24/13
to jna-...@googlegroups.com
I'm not sure we agree on what "Agreed" means.

Your native structure is defined to take up 200 bytes of memory in size.  You JNA structure is defined to take up 8 or 16 bytes in size, depending on your architecture.  Can you follow how your native code might get confused?  If you don't make the native and JNA structure definitions match *exactly*, you're going to fail.

Imagine you build a garage to fit a car which is exactly 3m square.  You pick up the car and realize it's 4m square.  You drive it into the garage anyway.  Hilarity ensues.

Or you pick up the car and it's 3ft square.  Hilarity ensues as you try to get in it.

rob stew

unread,
May 24, 2013, 3:37:12 PM5/24/13
to jna-...@googlegroups.com
Thanks.. Here is my updated code, but still errors persist.
 
     typedef struct S1{

     
     char temp1[100];
     char temp2[100];
     }S1
     ...
     int manipulateTemp(S1 s1Arr[] );
    
     JNA interface looks like this
    
     public interface Add extends Library
     {
         Add INSTANCE = (Add) Native.loadLibrary("add", Add.class);
        
         public static  class S1 extends Structure {
         public byte[] temp1 = new byte[100];
         public byte[] temp2 = new byte[100];

         public static class ByReference extends S1 implements Structure.ByReference {
          
         };
        
       };
       int manipulateTemp( S1[]);
     }
     //
     public static byte[] toByteArray(char[] a ,Charset c){
         CharBuffer cBuffer = CharBuffer.wrap(a);
         ByteBuffer bBuffer = c.encode(cBuffer);
         return bBuffer.array;

     }
     //in main method
    
     Add lib = Add.INSTANCE;
     Add.S1.ByReference s1Ref = new Add.S1.ByReference();
     Add.S1[] s1Arr = (Add.S1[])s1Ref.toArray(10);
     s1Ref.clear();
     //initialize array
     for(int i =0;i<s1Arr.lenth ;i++){
       byte[] data = toByteArray("myString1".toCharArray,Charset.defaultCharSet
       System.arrarycopy(data,0, s1Arr[i].temp1,0,data.length);
        data = toByteArray("myString2".toCharArray,Charset.defaultCharSet
       System.arrarycopy(data,0, s1Arr[i].temp2,0,data.length);
     }
    
    
     // calling native function
     lib.manipulateTemp(s1Arr[]);
    
     After execution
     Exception in thread "main" java.lang.Error: Invalid memory access
 at com.sun.jna.Function.invokeInt(Native Method)
 at com.sun.jna.Function.invoke(Function.java:344)
 at com.sun.jna.Function.invoke(Function.java:276)
 at com.sun.jna.Library$Handler.invoke(Library.java:216)
 at com.sun.proxy.$Proxy0.manipulateTemp((Unknown Source)
 at LoanTest.newTestCalc.main(newTestCalc.java:288)
     I even checked print memory dump,
     structures are seems to be allocated stored correctly.Structure size is also correct = 200 bytes
     Any clues about this error?

Timothy Wall

unread,
May 24, 2013, 9:17:02 PM5/24/13
to jna-...@googlegroups.com
Are you certain your native code works? I'm not.

rob stew

unread,
May 28, 2013, 8:40:42 AM5/28/13
to jna-...@googlegroups.com
I think so..as it is third party dll distributed to us

Timothy Wall

unread,
May 28, 2013, 12:18:28 PM5/28/13
to jna-...@googlegroups.com
Pass Structure[] if your native code is expecting an array of struct.

Pass Structure.ByReference[] if your native code is expecting an array of struct*.

It looks like your native code is expecting the former and you're passing the latter.

rob stew

unread,
May 28, 2013, 1:03:05 PM5/28/13
to jna-...@googlegroups.com
Tried both ..in first case it gave me invalid memory access 

in thread "main" java.lang.Error: Invalid memory access

at com.sun.jna.Function.invokeInt - native method )
 
In second case - program goes into infinite loop and never exits..
 
Isn't it in both cases base address of the structure is getting passed ?

Timothy Wall

unread,
May 28, 2013, 2:52:34 PM5/28/13
to jna-...@googlegroups.com
No, they're not the same, and randomly trying permutations will at best get you something that doesn't crash, not necessarily get you something that is correct.

If you don't know what your native code is expecting, say so.  Otherwise please say what it *is* expecting, preferably with the actual function declaration.

An array of struct looks like this in code:  struct MyStruct struct_array[ARRAY_SIZE]; // also "malloc(ARRAY_SIZE*sizeof(struct MyStruct))"
It looks like this in memory (assuming a struct of 4 bytes in size).  All structs are contiguously allocated, and a pointer to the first is your starting point:

0x0000: 00 00 00 00 <- first struct, at address 0x0
0x0004: 00 00 00 00 <- second struct, at address 0x4
... (and so on)

An array of struct* looks like this in code: struct MyStruct* struct_ptr_array[ARRAY_SIZE];
It looks like this in memory:
0x0000: 01 02 03 04 <- first element is a pointer with value 0x01020304
0x0004: 01 02 10 10 <- second element is a pointer with value 0x01020308

And if you look the address of the first pointer:
0x01020304: 00 00 00 00 <- actual contents of first struct
...
0x01021010: 00 00 00 00 <- actual contents of second struct

rob stew

unread,
May 28, 2013, 5:12:57 PM5/28/13
to jna-...@googlegroups.com
Thanks for making things clear. Then in my case c definition looks int manipulateTemp(S1 s1Arr[]); It takes array of structure as parameter.
 
My native function call is

Add.S1.ByReference s1Ref = new Add.S1.ByReference();
Add.S1[] s1Arr = (Add.S1[])s1Ref.toArray(10);
int i =  lib.manipulateTemp(s1Arr);
 
-- invalid memory access error..at com.sun.jna.Function.invokeInt - native method

Timothy Wall

unread,
May 28, 2013, 9:31:55 PM5/28/13
to jna-...@googlegroups.com
So when you take a "struct *" and make an array of them, you have an array of "struct *", which is *not* the same thing as an array of struct. Therefore crash.

rob stew

unread,
May 29, 2013, 3:22:03 PM5/29/13
to jna-...@googlegroups.com
 

Array-of-Structure Arguments

To pass an array of structures, simply use a Java array of the desired structure type. If the array is uninitialized, it will be auto-initialized prior to the function call.

// Original C code
void get_devices(struct Device[], int size);

// Equivalent JNA mapping
int size = ...
Device[] devices = new Device[size];
lib.get_devices(devices, devices.length);
Alternatively, you can reallocate a single Structure instance into an array as follows:
Device dev = new Device();
// As an array of Structure
Structure[] structs = dev.toArray(size);
// As an array of Device
Device[] devices = (Device[])dev.toArray(size);
 
When used first approach it gives me null pointer memory exception although I have written constructor with allocatememory(size);The second approach is what I used in program, but failed.

I dont think Structure.ByValue.toArray() makes any sense here.

Timothy Wall

unread,
May 29, 2013, 9:11:38 PM5/29/13
to jna-...@googlegroups.com
If your application is expecting a pointer to an array of struct, *do not* use Structure.ByReference.

Use Structure, and Structure.toArray(). You can pass either Structure[] or the first element, depending on your method signature.

I repeat, *do not* use Structure.ByReference (nor should you use Structure.ByValue).

Structure.ByReference is provided so that you can tell JNA, "Use a pointer here, always".
Structure.ByValue is provided so that you can tell JNA, "This argument or return value is *not* a pointer".

By default JNA treats arguments and return values as "struct *", and fields within a struct as "struct".

Structure.ByReference[] will give you an array of pointers (struct *).
Structure[] will give you an array of struct.

If you find some nugget of information here that makes you go "AHA!" that wasn't in the original documentation, or could be stated more clearly, please feel free to improve on the documentation.

rob stew

unread,
May 31, 2013, 10:02:08 AM5/31/13
to jna-...@googlegroups.com
I am using 32 bit dll on 64 bit machine with 32 bit JVM, do you think it might be causing problems as my program does not exit..
Reply all
Reply to author
Forward
0 new messages