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

时间:2014-08-07 08:57:35

标签: java jna

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

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

UINT cbSize是RAWINPUTDEVICELIST结构的大小,以字节为单位。如何在JNA中了解它? 我不小心发现16是正确的值。

结构如下:

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

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

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

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

}

当我获取PointerByReference值以获取指针时它是null,那有什么问题? 设备数量正确无法正确获取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" });
            }

        }
    }

}

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

以下是technomage的回答后的最终代码:

使用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);

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

    }
}