简体   繁体   中英

JNA : Get value from a pointer to a pointer to a structure

I'm getting trouble with JNA about pointer to pointer problem.

Example structure:

typedef struct _A {
    unsigned int num;
    struct _A *next;
} A, *PA;

C method:

void test(PA *a) {
    PA current = (PA) malloc(sizeof(A));
    current->num = 123321;

    PA next = (PA) malloc(sizeof(A));
    next->num = 456;
    current->next = next;

    *a = current;
}

A simple test in C:

int main() {
    PA a = NULL;
    test(&a);

    printf("%d\n", a->num);
    printf("%d", a->next->num);
}

JNA code

public interface DLLLibrary extends Library {
    ......

    void test(PointerByReference a);
}

public class A extends Structure {
    public int num;
    public ByReference next;
    public A() {
        super();
    }
    protected List<String> getFieldOrder() {
        return Arrays.asList("num", "next");
    }

    public A(Pointer peer) {
        super(peer);
    }
    public static class ByReference extends A implements Structure.ByReference { }
    public static class ByValue extends A implements Structure.ByValue { }
}

Finally, I am trying to get the structure fields that was updated in C, but get "Invalid memory access"

public static void main(String[] args) {
    PointerByReference pointer = new PointerByReference();
    DLLLibrary.INSTANCE.test(pointer);

    assert pointer.getValue().getInt(0) == 123321; //this works
    A a = new A(pointer.getValue());
    //assert a.next.num == 456;  //excepted action
    a.read(); //java.lang.Error: Invalid memory access
}

Any mistakes in my steps?

When you get an "Invalid memory access" error you should start looking at when native memory allocations are done. Usually the API documents that (and tells you how to free it) and when not, you know it's your responsibility. In this case you can see in the C code you've posted, the allocation is done inside the test method:

PA current = (PA) malloc(sizeof(A));

and

PA next = (PA) malloc(sizeof(A));

The problem here is that the Java side doesn't know about that allocation so you have to do it manually.

Your mapping of the function using a PointerByReference looks fine. While you can use getInt(0) on the return, you'd probably be better off at this point just instantiating the A structure from the returned pointer as you've done:

A a = new A(pointer.getValue());

Then a.num should be your expected 123321. Then you have to take the returned pointer (to the native-allocated link) and use that to create another Java-side structure:

A b = new A(a.next);

(You may want to just use a Pointer in the structure to make that part easy. If you use ByReference or A.ByReference then use getPointer() at this part.)

At this point, I believe b.num should give you 456.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM