JAVA JNA WindowProc实现

时间:2011-01-13 08:57:45

标签: java jna wndproc

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

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

提前感谢您的答案。

的Gabor。

4 个答案:

答案 0 :(得分: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通信编写的整个代码感兴趣,那么我会非常乐意提供帮助:)

干杯, 的Gabor。

答案 1 :(得分:2)

如果您没有现有的窗口句柄,则必须先创建自己的窗口。当您创建新窗口时,您还必须管理其消息泵。以下是有关如何执行此操作的示例。 JNA's own example code也非常有用。

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

答案 2 :(得分:1)

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

使用JACOB OR JCOM

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

答案 3 :(得分:1)

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

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

在互联网上搜索了一些内容后,我发现了一篇很棒的文章here (编辑:链接已死,original article can be found here,其中创建了一个静态隐藏窗口处理Windows消息。我设法为我的应用程序编写代码,它工作得很好。 (我不得不进一步扩展JNA中的类,因为没有包含几个函数。如果有人感兴趣,我可以发布我的代码。)

希望这有帮助。