7

我正在尝试用 Java 编写一个与 USB 设备通信的简单应用程序。USB 设备是我使用 Microchip 微控制器制作的。通信相当简单,因为 USB 设备属于 HID 类,在计算机和设备之间交换 64 字节的数组。我的程序根据产品 ID 和供应商 ID 找到设备,可以读写 64 个字节,但现在我想检测设备何时与计算机连接或断开连接。

正如我在 Microchip 作为示例应用程序提供的 C# 程序中看到的那样,WndProc 方法被覆盖并处理 WM_DEVICECHANGE 消息。我的问题是如何使用 JNA 在 Java 中完成此操作,如果可能的话,我如何覆盖 WindowProc 方法并处理消息:),但我希望它是 :D

提前感谢您的答案。

加博。

4

4 回答 4

8

我终于设法解决了这个问题:) 我找到了以下解决方案:

首先通过如下方式扩展User32接口

public interface MyUser32 extends User32 {

    public static final MyUser32 MYINSTANCE = (MyUser32) Native.loadLibrary("user32", MyUser32.class, W32APIOptions.UNICODE_OPTIONS);

    /**
     * Sets a new address for the window procedure (value to be set).
     */
    public static final int GWLP_WNDPROC = -4;

    /**
     * Changes an attribute of the specified window
     * @param   hWnd        A handle to the window
     * @param   nIndex      The zero-based offset to the value to be set.
     * @param   callback    The callback function for the value to be set.
     */
    public int SetWindowLong(WinDef.HWND hWnd, int nIndex, Callback callback);
}

然后使用您需要的 Windows 消息代码扩展 WinUser 界面,在我的情况下,这是 WM_DEVICECHANGE,因为我想检查 USB 设备是否已与计算机连接或分离。

public interface MyWinUser extends WinUser {
    /**
     * Notifies an application of a change to the hardware configuration of a device or the computer.
     */
    public static final int WM_DEVICECHANGE = 0x0219;
}

然后用回调函数创建一个接口,这实际上就是我的 WndProc 函数。

//Create the callback interface 
public interface MyListener extends StdCallCallback {

    public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
}

public MyListener listener = new MyListener()
{
    public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam)
    {
        if (uMsg == MyWinUser.WM_DEVICECHANGE)
        {
            // TODO Check If my device was attached or detached
            return new LRESULT(1);
        }
        return new LRESULT(0);
    }
};

然后在您初始化事物的 JFrame 代码中的某处使用 SetWindowLong 函数添加窗口过程的新地址:

    // Get Handle to current window
    HWND hWnd = new HWND();
    hWnd.setPointer(Native.getWindowPointer(this));

    MyUser32.MYINSTANCE.SetWindowLong(hWnd, MyUser32.GWLP_WNDPROC, listener);

这段代码运行良好,但我对一件事有一些疑问。我不确定回调函数的返回值是否正确。我在 MSDN 中读到,在处理 WM_DEVICECHANGE 消息后,回调函数应该返回 true,我不确定我当前返回的值是否是系统预期的值,因此欢迎提出任何建议。

如果有人对我为 HID 通信编写的整个代码感兴趣,请询问,我将非常乐意提供帮助 :)

干杯,加博尔。

于 2011-01-14T12:58:52.623 回答
2

如果您没有现有的窗口句柄,则必须先创建自己的窗口。当您创建一个新窗口时,您还必须管理它的消息泵。这是一个有关如何执行此操作的示例。JNA 自己的示例代码也可能非常有用。

Thread thread;
HWND hWnd;
static final int WM_NCCREATE = 0x0081;

void start() {
    thread = new Thread(this::myThread);
    thread.start();
}

void stop() {
    User32.INSTANCE.PostMessage(hWnd, User32.WM_QUIT, null, null);
}

WindowProc callback = new WindowProc() {
    @Override
    public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) {
        switch (uMsg) {
        case WM_NCCREATE:
            return new LRESULT(1);

        case User32.WM_DEVICECHANGE:
            return new LRESULT(1);

        default:
            return new LRESULT(0);
        }
    }
};

void myThread() {
    WString className = new WString("myclass");

    WNDCLASSEX wx = new WNDCLASSEX();
    wx.clear();
    wx.lpszClassName = className;
    wx.lpfnWndProc = callback;

    if (User32.INSTANCE.RegisterClassEx(wx).intValue() != 0) {
        hWnd = User32.INSTANCE.CreateWindowEx(0, className, null, 0, 0, 0, 0, 0, null, null, null, null);

        WinUser.MSG msg = new WinUser.MSG();
        msg.clear();

        while (User32.INSTANCE.GetMessage(msg, hWnd, 0, 0) > 0) {
            User32.INSTANCE.TranslateMessage(msg);
            User32.INSTANCE.DispatchMessage(msg);
        }
    }
}
于 2015-02-24T10:37:24.067 回答
1

您可以创建 C# 程序的 COM DLL 或 OCX 并在 java 代码中使用它。如果您创建应用程序。

使用 JACOB 或JCOM

它将成为 Java 和 COM 对象之间的桥梁。其他选项是您可以使用 JNI 与 DLL 和 OCX 进行通信。

于 2011-01-13T09:10:16.480 回答
1

我之前发布的解决方案有一些问题,不幸的是:(

因为它覆盖了窗口的 WndProc,所以我添加到 Frame 中的控件不起作用(不足为奇,因为没有处理任何绘制、重绘等消息)。然后我意识到LRESULT(1)我应该调用默认的窗口过程而不是返回(因为它在 Win32 C++ 程序中使用),但这仍然没有解决问题,框架被绘制但按钮不起作用,虽然我是能够更新标签......所以我也不得不放弃这个解决方案。

在互联网上搜索了更多内容后,我在这里找到了一篇很棒的文章 (编辑:链接已失效,原始文章可以在这里找到,其中创建了一个静态隐藏窗口来处理 Windows 消息。我设法为我的应用程序编写了代码,并且效果很好。(我不得不进一步扩展 JNA 的类,因为没有包含几个函数。如果有人感兴趣,我可以发布我的代码。)

希望这可以帮助。

于 2011-01-25T07:39:50.983 回答