Home > Net >  How to call C function through JNA with 2d pointer?
How to call C function through JNA with 2d pointer?

Time:06-02

Here is the signature of my C function :

typedef struct myitem_s {
    int a;
    int b;
} myitem_t;

int get_items(myitem_t** items);

The usage in a C program is::

myitem_t* items = NULL;
int n = = get_items(&items);

for (int i = 0; i < n;   i) {
    myitem_t* item = &items[i];
}

items is allocated in the get_items() function and contains one or more myitem_t elements.

From Java code I have succeeded in doing this:

Memory itemsPtr = new Memory(Native.POINTER_SIZE);
Pointer p = itemsPtr.getPointer(0);
int n = CLibrary.INSTANCE.get_items(p);

The n value is valid, itemsPtr is updated so I suggest value is good also. Now I have no idea of how to use it. Is there another way of doing it?

CodePudding user response:

Your code works but you're using a lot of lower level functions when JNA has some higher level constructs.

First, the C struct can be represented by a JNA Structure.

@FieldOrder({ "a", "b" })
class MyitemT extends Structure {
    public int a;
    public int b;
}

Since the native code is handling the memory allocation, all you need is the pointer to it. Rather than a pointer-sized memory allocation, you probably want a PointerByReference.

PointerByReference pbr = new PointerByReference();

The key methods you want from this are getPointer() (the pointer to the pointer) and getValue() (the pointed-to value).

Given the above, pass the pointer-to-the-pointer to the method, which will allocate the memory and populate the value.

Using the mapping you already have (not shown but inferred):

int n = CLibrary.INSTANCE.get_items(pbr.getPointer());

However, you should actually map get_items() to take a PointerByReference argument and then you can just pass items directly.

At this point, items.getValue() is a Pointer to the start of your array of structures. Additional items would be at offsets of the pointer value based on the size of the structure (item.size()). There are multiple ways of getting at that.

In your case since you know you just have pairs of ints, you could skip the whole "structure" part and just use items.getValue().getInt(0) and items.getValue().getInt(4) for the first pair; 8 and 12 for the second pair, etc. But even better, just items.getValue().getIntArray(0,n*2); fetches an array of integers, just pull them out by pairs.

But that takes advantage of internal details. Probably the most JNA-ish choice is to use Structure.toArray() to create an array of your MyitemT structures. If you include a pointer constructor and create the initial structure using that pointer, Structure.toArray() uses that existing mapping. You can then read() into your array:

MyItemT item = new MyItemT(pbr.getValue());
MyItemT[] items = (MyItemT[]) item.toArray(n);
for (int i = 0; i < n; i  ) { 
    items[i].read();
    // now you can see items[i].a and items[i].b
}

Don't forget to eventually release the native-allocated memory however the API tells you to!

  • Related