Abraham Putra Prakasa
Abraham Putra Prakasa

Reputation: 608

Java JNA Linkedlist declaration

I need to access native C++ code .dll from Java application. native int function works well, but for Linkedlist Struct I cannot find any reference on the Internet how to declare the java interface

this C++ code

struct usb_relay_device_info
{
    unsigned char *serial_number;
    char *device_path;
    usb_relay_device_type type;
    usb_relay_device_info* next;
};

int EXPORT_API usb_relay_init(void);
struct usb_relay_device_info EXPORT_API * usb_relay_device_enumerate(void);
int EXPORT_API  usb_relay_device_open(struct usb_relay_device_info* device_info);

This is the java part

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

public static class usb_relay_device_info extends Structure {
    public static class DeviceInfo extends usb_relay_device_info implements Structure.ByValue {
    }

    public byte[] serial_number = new byte[1024];
    public String device_path;
    public int type;
}


int usb_relay_init();
usb_relay_device_info.DeviceInfo usb_relay_device_enumerate();
int usb_relay_device_open(usb_relay_device_info.DeviceInfo deviceInfo);

}

I already created just the struct at the java code (NOT the Linkedlist Struct). So when I call the function the values are not showing up because it supposed to be a list (linkedlist in C++)

Upvotes: 0

Views: 161

Answers (1)

Daniel Widdis
Daniel Widdis

Reputation: 9091

You say "I cannot find any reference on the Internet how to declare the java interface" but there are plenty of references, including JNA's Overview, linked to the main project page.

There you will find that char * is a C String and should be mapped to Java's String.

The usb_relay_device_type mapping has to be referenced in the API that you're mapping. In this case it is an enum type, which is an integer, so int is probably appropriate here. (There are cases where it can be a smaller integer value like short or byte but those are rare.)

As for the pointer to the next device, that is also referenced on the overview page under struct*. The link (or explicitly) links to Structure.ByReference. That may not be obvious, but the JNA FAQ, also linked on the main JNA project page, amplifies. If it's still not clear, here's a summary:

  • By default, Structures listed as fields inside a Structure are treated "By Value", that is, the full structure and its fields are inserted in line. To get this behavior you can simply declare the structure name.
  • If you want the opposite behavior (By Reference) then you must explicitly state that, and JNA will map a pointer to the structure elsewhere. This is the case you have, and the correct structure mapping is usb_relay_device_info.ByReference. (You'll also need to change the structure declaration to implement ByReference -- the JNA overview, linked above, has an example of this.)
  • When used in function arguments, such as usb_relay_device_open(), the opposite is true: the "By Reference" is the default, and you only need to explicity specify "By Value" if that's relevant. In this case, it's not -- the native declaration includes the pointer: (usb_relay_device_info*) so you want the ByReference behavior. You can just put usb_relay_device_info device_info there and the ByReference will be implicit. Or, if you prefer (it's not needed) you could do usb_relay_device_info.ByReference device_info and it would just be redundant.

So in summary your structure mapping should be:

class usb_relay_device_info extends Structure {
    public static class ByReference extends usb_relay_device_info implements Structure.ByReference { }

    public String serial_number;
    public String device_path;
    public int type;
    public usb_relay_device_info.ByReference next;
};

You'll need to add the FieldOrder, preferably using an annotation.

Upvotes: 1

Related Questions