JAVA JNA WindowProc 实现

发布于 2024-10-12 05:55:42 字数 363 浏览 7 评论 0原文

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

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

提前感谢您的回答。

加博尔。

I'm trying to write a simple application in Java that will communicate with an USB device. The USB device is made by me using a Microchip Microcontroller. The communication is rather simple, since the USB device is from the HID Class, arrays of 64 bytes are exchanged between the computer and the device.
My program finds the device based on the product ID and the vendor ID, can write and read 64 bytes, but now I would like to detect when the device is connected or disconnected from the computer.

As I've seen in a C# program provided by Microchip as an example application, the WndProc method is overriden and the WM_DEVICECHANGE message is handled. My question is how can this be done in Java using JNA, how can I override the WindowProc Method and handle messages, if this is possible at all :), but I hope it is :D

Thanks in advance for the answers.

Gabor.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

半暖夏伤 2024-10-19 05:55:42

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

首先按以下方式扩展 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 通信编写的整个代码感兴趣,请询问,我将非常乐意提供帮助:)

干杯,
加博尔。

I finally managed to solve the problem :) And I found the following solution:

First extend the User32 interface in the following way

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

Then extend the WinUser interface with the Windows Message code that you need, in my case this is the WM_DEVICECHANGE, because I want to check I the USB Device was attached or detached from the computer.

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

Then create an interface with the callback function, which will actually be my WndProc function.

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

And then somewhere in the code of the JFrame where you initialize things add the new address for the window procedure with the SetWindowLong function:

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

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

This code works nicely, but I have some doubts regarding one thing. I'm not sure if the return value of the callback function is correct. I've read in the MSDN that after handling a WM_DEVICECHANGE message the callback function should return true and I'm not sure that the value i'm currently returning is the one expected by the system, so any suggestions are welcome.

If anyone is interested in the whole code I've written for the HID communication just ask, I would be more than happy to help :)

Cheers,
Gabor.

脸赞 2024-10-19 05:55:42

如果您没有现有的窗口句柄,则必须首先创建自己的窗口。当您创建新窗口时,您还必须管理其消息泵。以下是有关如何执行此操作的示例。 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);
        }
    }
}

If you don't have an existing window handle you have to create your own window first. And when you create a new window you also have to manage its message pump. Here's an example on how you can do this. JNA's own example code could also be very useful.

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);
        }
    }
}
念﹏祤嫣 2024-10-19 05:55:42

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

使用 JACOB OR JCOM

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

You can create COM DLL or OCX of your C# program and use it in the java code. If you create application.

Use JACOB OR JCOM

It will be a bridge between Java and COM Object. Other option is you can use JNI to communicate with DLL and OCX.

和影子一齐双人舞 2024-10-19 05:55:42

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

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

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

希望这会有所帮助。

The solution I posted previously has some problems, unfortunately :(

Since it overrides the WndProc of the window, the controls I added to my Frame weren't working (not surprisingly, because no paint, repaint, etc. messages were handled). Then I realised that instead of returning LRESULT(1) I should call the default window proc (as it is used in Win32 C++ programs), but this still didn't solve the problem, the frame was painted but the buttons weren't working, although I was able to update labels... So I had to abandon this solution too.

After searching some more on the internet I've found a great article here (edit: link is dead, original article can be found here), where a static hidden window is created to handle windows messages. I managed to code it for my application and it works great. (I had to further extend the classes from JNA because several functions were not included. I can post my code if someone is interested.)

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文