基本思路

创建隐藏window
实现 winproc函数
注册设备通知,调用winproc处理

引入依赖

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.6.0</version>
</dependency>

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.6.0</version>
</dependency>

代码实现

package com.cares.vip.front.service;

import com.sun.jna.platform.win32.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;

import static com.sun.jna.platform.win32.WinUser.WM_DEVICECHANGE;

/**
 * 监听串口设备拔出、插入
 */
@Slf4j
public class SpDeviceChangeService implements WinUser.WindowProc, InitializingBean {

    private SerialportService serialportService;

    public void setup() {

        serialportService.openSerialPort();

        // define new window class
        String windowClass = "MyWindowClass";
        WinDef.HMODULE hInst = Kernel32.INSTANCE.GetModuleHandle("");

        WinUser.WNDCLASSEX wClass = new WinUser.WNDCLASSEX();
        wClass.hInstance = hInst;
        wClass.lpfnWndProc = this;
        wClass.lpszClassName = windowClass;

        // register window class
        User32.INSTANCE.RegisterClassEx(wClass);
        getLastError();

        // create new window
        WinDef.HWND hWnd = User32.INSTANCE
                .CreateWindowEx(
                        User32.WS_EX_TOPMOST,
                        windowClass,
                        "hidden window to catch the windows events",
                        0, 0, 0, 0, 0,
                        null, // WM_DEVICECHANGE contradicts parent=HWND_MESSAGE
                        null, hInst, null);

        getLastError();
        log.info("window sucessfully created! window hwnd: " + hWnd.getPointer().toString());

        Wtsapi32.INSTANCE.WTSRegisterSessionNotification(hWnd,
                Wtsapi32.NOTIFY_FOR_THIS_SESSION);

        /* this filters for all usb device classes */
        DBT.DEV_BROADCAST_DEVICEINTERFACE notificationFilter = new DBT.DEV_BROADCAST_DEVICEINTERFACE();
        notificationFilter.dbcc_size = notificationFilter.size();
        notificationFilter.dbcc_devicetype = DBT.DBT_DEVTYP_PORT;
        notificationFilter.dbcc_classguid = DBT.GUID_DEVINTERFACE_HID;

        WinUser.HDEVNOTIFY hDevNotify = User32.INSTANCE.RegisterDeviceNotification(
                hWnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE);

        getLastError();
        if (hDevNotify != null)
            log.info("RegisterDeviceNotification was sucessfully!");

        WinUser.MSG msg = new WinUser.MSG();
        while (User32.INSTANCE.GetMessage(msg, hWnd, 0, 0) != 0) {
            User32.INSTANCE.TranslateMessage(msg);
            User32.INSTANCE.DispatchMessage(msg);
        }

        User32.INSTANCE.UnregisterDeviceNotification(hDevNotify);
        Wtsapi32.INSTANCE.WTSUnRegisterSessionNotification(hWnd);
        User32.INSTANCE.UnregisterClass(windowClass, hInst);
        User32.INSTANCE.DestroyWindow(hWnd);

        log.info("program exit!");
    }

    /**
     * 实现 WinUser.WindowProc 的callback 接口
     */
    public WinDef.LRESULT callback(WinDef.HWND hwnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) {
        switch (uMsg) {
            case WM_DEVICECHANGE: {
                WinDef.LRESULT lResult = this.onDeviceChange(wParam, lParam);
                return lResult != null ? lResult :
                        User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam);
            }
            default:
                return User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
    }

    public int getLastError() {
        int rc = Kernel32.INSTANCE.GetLastError();

        if (rc != 0)
            log.error("error: " + rc);

        return rc;
    }

    protected WinDef.LRESULT onDeviceChange(WinDef.WPARAM wParam, WinDef.LPARAM lParam) {
        switch (wParam.intValue()) {
            case DBT.DBT_DEVICEARRIVAL: {

                return onDeviceChangeArrival(lParam);
            }
            case DBT.DBT_DEVICEREMOVECOMPLETE: {

                return onDeviceChangeRemoveComplete(lParam);
            }
            case DBT.DBT_DEVNODES_CHANGED: {
                return onDeviceChangeNodesChanged();
            }
            default:
                log.info("Message WM_DEVICECHANGE message received, value unhandled.");
        }
        return null;
    }

    protected WinDef.LRESULT onDeviceChangeArrivalOrRemoveComplete(WinDef.LPARAM lParam, String action) {
        DBT.DEV_BROADCAST_HDR bhdr = new DBT.DEV_BROADCAST_HDR(lParam.longValue());
        switch (bhdr.dbch_devicetype) {
            case DBT.DBT_DEVTYP_DEVICEINTERFACE: {
                DBT.DEV_BROADCAST_DEVICEINTERFACE bdif = new DBT.DEV_BROADCAST_DEVICEINTERFACE(bhdr.getPointer());
                log.info("BROADCAST_DEVICEINTERFACE: " + action);
                log.info("dbcc_devicetype: " + bdif.dbcc_devicetype);
                log.info("dbcc_name: " + bdif.getDbcc_name());
                log.info("dbcc_classguid: "
                        + bdif.dbcc_classguid.toGuidString());
                if ("insert".equals(action)) {
                    serialportService.openSerialPort();

                }
                break;
            }
            case DBT.DBT_DEVTYP_PORT: {
                if ("insert".equals(action)) {
                    serialportService.openSerialPort();

                }
                log.info("BROADCAST_PORT: " + action);
                break;
            }
            default:
                return null;
        }
        return new WinDef.LRESULT(1);
    }

    protected WinDef.LRESULT onDeviceChangeArrival(WinDef.LPARAM lParam) {
        return onDeviceChangeArrivalOrRemoveComplete(lParam, "insert");
    }

    protected WinDef.LRESULT onDeviceChangeRemoveComplete(WinDef.LPARAM lParam) {
        return onDeviceChangeArrivalOrRemoveComplete(lParam, "remove");
    }

    protected WinDef.LRESULT onDeviceChangeNodesChanged() {
        log.info("Message DBT_DEVNODES_CHANGED");
        return new WinDef.LRESULT(1);
    }

    public void setSerialportService(SerialportService serialportService) {
        this.serialportService = serialportService;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setup();
    }
}


硬件      jna 监听设备插拔

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!