简体   繁体   English

如何在JNA中填充结构数组?

[英]How to fill an array of structures in JNA?

I am trying to use the following windows API in JNA : 我正在尝试在JNA中使用以下Windows API:

UINT WINAPI GetRawInputDeviceList(
  _Out_opt_  PRAWINPUTDEVICELIST pRawInputDeviceList,
  _Inout_    PUINT puiNumDevices,
  _In_       UINT cbSize
);

UINT cbSize is the size of a RAWINPUTDEVICELIST structure, in bytes. UINT cbSize是RAWINPUTDEVICELIST结构的大小,以字节为单位。 How to know it in JNA? 如何在JNA中知道它? I had accidentally found that 16 is a correct value. 我偶然发现16是正确的值。

The structure is the following: 结构如下:

typedef struct tagRAWINPUTDEVICELIST {
  HANDLE hDevice;
  DWORD  dwType;
} RAWINPUTDEVICELIST, *PRAWINPUTDEVICELIST;

pRawInputDeviceList is An array of RAWINPUTDEVICELIST structures so in JNA I'm declaring the following signature : pRawInputDeviceList是RAWINPUTDEVICELIST结构的数组,因此在JNA中,我声明以下签名:

UINT GetRawInputDeviceList(PointerByReference pRawInputDeviceList, IntByReference puiNumDevices, UINT cbSize);

And here is my structurre in JNA : 这是我在JNA中的结构:

public static class RawInputDeviceList extends Structure {

    public HANDLE hDevice;
    public DWORD dwType;

    public RawInputDeviceList() {
            // required for toArray()
    }

    public RawInputDeviceList(Pointer pointer) {
        super(pointer);
        read();
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList(new String[] { "hDevice", "dwType" });
    }

}

When i'm getting the PointerByReference value to get the pointer it is null, what is wrong with that? 当我获取PointerByReference值来获取指针时,它为null,那是什么问题呢? The number of devices is correct bu i can't get the RawInputDeviceList array correctly. 设备数量正确,但无法正确获取RawInputDeviceList数组。

Here is the full test code: 这是完整的测试代码:

public class TestRawInput {

    public static void main(String[] args) {
        PointerByReference lRawInputDevicesReference = new PointerByReference();
        IntByReference lNumDevices = new IntByReference();

        UINT lRes = WindowsRawInput.INSTANCE.GetRawInputDeviceList(lRawInputDevicesReference, lNumDevices, new UINT(16));

        Pointer lRawInputDevicePointer = lRawInputDevicesReference.getValue();
        WindowsRawInput.RawInputDeviceList lRawInputDevice = new WindowsRawInput.RawInputDeviceList(lRawInputDevicePointer);
        WindowsRawInput.RawInputDeviceList[] lDevices = (WindowsRawInput.RawInputDeviceList[]) lRawInputDevice.toArray(lNumDevices.getValue());

        System.out.println("devices deteced=" + lNumDevices.getValue());
        for (int i=0;i<lDevices.length;i++) {
            System.out.println("device type: " + lDevices[i].dwType);
        }
    }

    public interface WindowsRawInput extends StdCallLibrary {

        WindowsRawInput INSTANCE = (WindowsRawInput) Native.loadLibrary("user32", WindowsRawInput.class, W32APIOptions.DEFAULT_OPTIONS);

        UINT GetRawInputDeviceList(PointerByReference pRawInputDeviceList,
            IntByReference puiNumDevices, UINT cbSize);

        public static class RawInputDeviceList extends Structure {

            public HANDLE hDevice;
            public DWORD dwType;

            public RawInputDeviceList() {
                // required for toArray()
            }

            public RawInputDeviceList(Pointer pointer) {
                super(pointer);
                read();
            }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[] { "hDevice", "dwType" });
            }

        }
    }

}
  1. Create an array of continguously-allocated structures using Structure.toArray() . 使用Structure.toArray()创建一个连续分配的结构数组。
  2. Pass the first element of that array to your native function. 将该数组的第一个元素传递给您的本机函数。 In this case, struct* is equivalent to struct[] (native types), so use RawInputDeviceList as the argument type instead of PointerByReference . 在这种情况下, struct*等效于struct[] (本机类型),因此请使用RawInputDeviceList作为参数类型,而不是PointerByReference I'm not sure why they call the individual structure a "list", but that's windows for you. 我不确定为什么他们将单个结构称为“列表”,但这就是您的窗口。
  3. Pass the size of your array in puiNumDevices , which presumably the native function will update with the count actually filled in. puiNumDevices传递数组的大小,大概是本机函数将使用实际填写的计数进行更新。
  4. The native function will fill in the memory, and JNA will sync the native memory to Java Structure on function return. 本机函数将填充内存,并且JNA将在函数返回时将本机内存同步到Java Structure
  5. cbSize may be obtained by calling Structure.size() . cbSize可以通过调用Structure.size()

Here is the final code after technomage's answer : 这是技术答案后的最终代码:

using JNA and native library : 使用JNA和本机库:

    IntByReference lNumDevices = new IntByReference();
    WindowsRawInput.RAWINPUTDEVICELIST lRawInputDevice = new WindowsRawInput.RAWINPUTDEVICELIST();
    int lRawInputSize = lRawInputDevice.size();

    // getting the size of devices to get and setting the structure size
    WindowsRawInput.INSTANCE.GetRawInputDeviceList(null, lNumDevices, lRawInputSize);

    // creating the device list
    WindowsRawInput.RAWINPUTDEVICELIST[] lDevices = (WindowsRawInput.RAWINPUTDEVICELIST[]) lRawInputDevice.toArray(lNumDevices.getValue());

    WindowsRawInput.INSTANCE.GetRawInputDeviceList(lDevices[0], lNumDevices, lRawInputSize);

Here is the JNA interface and structure : 这是JNA接口和结构:

public interface WindowsRawInput extends StdCallLibrary { 

    WindowsRawInput INSTANCE = (WindowsRawInput) Native.loadLibrary("user32", WindowsRawInput.class, W32APIOptions.DEFAULT_OPTIONS);

    UINT GetRawInputDeviceList(RAWINPUTDEVICELIST pRawInputDeviceList, IntByReference puiNumDevices, int cbSize);

    public static class RAWINPUTDEVICELIST extends Structure {

        public HANDLE hDevice;
        public DWORD dwType;

        public RAWINPUTDEVICELIST() { }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList(new String[] { "hDevice", "dwType" });
        }

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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