Search code examples
javadllstructurepass-by-referencejna

Pass Structure by reference as argument in JNA


I have a dynamic link library (DLL) written in c++. In my DLL I have a function like this:

void anpr_set_params(byte instance, SLPRParams* params);

Where SLPRParams is a Structure containing byte, int, float and array of them.

Now, I want to use my DLL in Java. I'm using JNA to call native code in my java project. I tried get help from this site to get the address of my structure in java and pass it to my dll, and I defined my signature function in Java like this:

void anpr_set_params(byte instance, long slpr_params);

But the address i get in c++ is different from the address i sent in Java.

Then I looked for another solution and read the this JNA FAQ entry.

I tested all types but every time I get a runtime error.


Solution

  • You can just pass the Structure directly as an argument.

    As explained in JNA Structures and Unions,

    When a function requires a pointer to a struct, a Java Structure should be used.

    Also, the javadoc for Structure says:

    When used as a function parameter or return value, this class corresponds to struct*. When used as a field within another Structure, it corresponds to struct. The tagging interfaces Structure.ByReference and Structure.ByValue may be used to alter the default behavior.

    Passing a pointer to a structure like SLPRParams* params is the most common way that DLLs expect structures, and that ByReference type is the default behavior. Only if the full structure is passed inline would you need to use the ByValue tag on it.

    A nested Structure inside another Structure works the opposite way; it is ByValue by default and would need the ByReference tag if it was declared as a pointer.

    The examples in the JNA FAQ (which you also linked) may make more sense once you understand this distinction. The relevant example is this one:

    void myfunc(simplestruct* data); // use Structure
    

    In your case the correct mapping is

    void anpr_set_params(byte instance, SLPRParams slpr_params);
    

    The mapping with long might appear to work on 64-bit non-Windows operating systems if you extracted the structure's pointer's peer value (Pointer.nativeValue(params.getPointer()). But it wouldn't be portable. Just pass the Structure and JNA handles the rest.