Search code examples
javacjna

How to pass array of structures to function in order to get results in JNA


I have the following function in C:

EXPORT int GetInfo(MyObject* &myObjects);

typedef struct MyObject
{
    char info1[1025];
    unsigned long sizeF;
    char info2[20];
};

Then I invoke:

MyObject* list1;
int count = GetInfo(list1);

and iterate list1 in order to get information from each MyObject object (count -> number of elements in list1).

Now, I'm trying to make the counterpart in JNA. Thus, I have:

int GetInfo(PointerByReference myObjets);

public class MyObject extends Structure {

   public static class ByReference extends MyObject implements Structure.ByReference {
   }
   public String info1;
   public NativeLong sizeF;
   public String info2;

   public MyObject() {
   }

   public MyObject(Pointer pointer) {
      super(pointer);
   }

   @Override
   protected List getFieldOrder() {
      return Arrays.asList(new String[]{"info1", "sizeF", "info2"});
   }
}

Then:

PointerByReference ptrRef = new PointerByReference();
int count = myLib.GetInfo(ptrRef);
if (count > 0) {
   Pointer pointer = ptrRef.getValue();
   MyObject myObject = new MyObject(pointer);
   MyObject[] myObjects = (MyObject[]) myObject.toArray(count);
}

Unfortunately, all fields in myObjects have default values (null/0). I also tried:

int GetInfo(MyObject.ByReference myObjets);
MyObject.ByReference byRef = new PointerByReference();
int count = myLib.GetInfo(byRef);
if (count > 0) {
   MyObject[] myObjects = (MyObject[]) byRef.toArray(count);
}

In this case, only the first field in first element of myObjects array was filled. The rest had default values.

What should I do in order to get an array of MyObjects with filled all fields.


Solution

  • Some time ago I found the solution. I don't know if it is wise, but it worked for me. So if someone will have a similar problem, then here you go:

    In MyObject class I added 2 methods:

    static MyObject[] fromArrayPointer(Pointer pointer, int numberResults) {
        MyObject[] arr = new MyObject[numberResults];
        int offset = 0;
        for (int i = 0; i < numberResults; i++) {
            arr[i] = fromPointer(pointer, offset);
            offset += <size of structure>;
        }
        return arr;
    }
    
    static MyObject fromPointer(Pointer pointer, int offset) {  
        MyObject inst = new MyObject();
        inst.info1= pointer.getString(offset);
        offset += 1025;
        inst.sizeF = pointer.getNativeLong(offset);
        offset += 4; // long but 4 bytes because of machine
        inst.info2 = pointer.getString(offset);
        offset += 20;
        return inst;
    }
    

    Honestly, you have to experiment with those numbers and size of structure. Remember about data aligment problem here.

    Then, you have:

    if (count > 0) {
       MyObject[] myObjects = MyObject.fromArrayPointer(ptrRef.getValue(), count);
    }