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

Alg*_*gok 1 java jna

我正在尝试在 JNA 中使用以下 Windows API:

UINT WINAPI GetRawInputDeviceList(
  _Out_opt_  PRAWINPUTDEVICELIST pRawInputDeviceList,
  _Inout_    PUINT puiNumDevices,
  _In_       UINT cbSize
);
Run Code Online (Sandbox Code Playgroud)

UINT cbSize 是 RAWINPUTDEVICELIST 结构的大小,以字节为单位。如何在JNA中知道它?我偶然发现 16 是一个正确的值。

结构如下:

typedef struct tagRAWINPUTDEVICELIST {
  HANDLE hDevice;
  DWORD  dwType;
} RAWINPUTDEVICELIST, *PRAWINPUTDEVICELIST;
Run Code Online (Sandbox Code Playgroud)

pRawInputDeviceList 是一个 RAWINPUTDEVICELIST 结构数组,因此在 JNA 中我声明了以下签名:

UINT GetRawInputDeviceList(PointerByReference pRawInputDeviceList, IntByReference puiNumDevices, UINT cbSize);
Run Code Online (Sandbox Code Playgroud)

这是我在 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" });
    }

}
Run Code Online (Sandbox Code Playgroud)

当我获取 PointerByReference 值以获取指针时,它为空,这有什么问题?设备数量正确,但我无法正确获取 RawInputDeviceList 数组。

这是完整的测试代码:

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" });
            }

        }
    }

}
Run Code Online (Sandbox Code Playgroud)

tec*_*age 5

  1. 使用Structure.toArray().创建一个连续分配的结构数组。
  2. 将该数组的第一个元素传递给您的本机函数。在这种情况下,struct*等价于struct[](native types),因此使用RawInputDeviceList作为参数类型而不是PointerByReference。我不确定为什么他们将单个结构称为“列表”,但那是适合您的窗口。
  3. 将数组的大小传递给puiNumDevices,这可能是本机函数将随着实际填充的计数进行更新。
  4. 本机函数将填充内存,JNA 将Structure在函数返回时将本机内存同步到 Java 。
  5. cbSize可以通过调用获得Structure.size()