Qt USB设备拔插监测

环境

Windows 系统
Qt5.4
c++语言

目的

让程序运行过程中能监测某一USB设备的拔插状态,当设备被拔出时进行相关处理。

方法

MSDN Device Messages 说明:

For each device event, the system broadcasts a WM_DEVICECHANGE message to all applications. In this message, the wParam parameter identifies the device event type and the lParam parameter is a pointer to event-specific data.

然而, WM_DEVICECHANGE 消息只会通知给TOP窗口,见 Detecting Media Insertion or Removal说明:

Windows sends all top-level windows a set of default WM_DEVICECHANGE messages when new devices or media (such as a CD or DVD) are added and become available, and when existing devices or media are removed.

但软件运行过程中TOP窗口并不固定,因此,选择一个软件开启到退出都会一直存在,不会析构的窗口注册消息来获取想要的消息通知。

注册消息用到函数是 RegisterDeviceNotification:

例如 软件加密狗检测,类CCheckSoftDog用来初始化加密狗,检测加密狗是否正常,处理加密狗拔出后进行弹框提示,则在 CCheckSoftDog 中 注册消息,那么不管软件处于什么界面,都能接受到消息,一旦检测到usb设备拔插,那么检测加密狗是否存在,不存在则弹框提示,不能继续使用软件。

/*
winuser.h 头文件定义:如果是 unicode 编码,
则用 RegisterDeviceNotificationW,
其他则用 RegisterDeviceNotificationA
*/
HDEVNOTIFY RegisterDeviceNotificationW(
  HANDLE hRecipient, //指向窗口或服务的句柄
  LPVOID NotificationFilter, //接受设备通知句柄
  DWORD  Flags //说明 hRecipient 是用的窗口句柄还是设备服务句柄
);

NotificationFilter:
A pointer to a block of data that specifies the type of device for which notifications should be sent. This block always begins with the DEV_BROADCAST_HDR structure. The data following this header is dependent on the value of the dbch_devicetype member, which can be DBT_DEVTYP_DEVICEINTERFACE or DBT_DEVTYP_HANDLE.
 
DBT_DEVTYP_DEVICEINTERFACE:
Class of devices. This structure is a DEV_BROADCAST_DEVICEINTERFACE structure.

MSDN 例子中 NotificationFilter 参数用的是 DEV_BROADCAST_DEVICEINTERFACE 结构体,指明设备类型为设备接口类 DBT_DEVTYP_DEVICEINTERFACE 以及用来注册消息的 device interface class GUID。不同GUID说明见USB设备的插入检测

Flags:
DEVICE_NOTIFY_WINDOW_HANDLE: hRecipient is a windows handle
DEVICE_NOTIFY_SERVICE_HANDLE: hRecipient is a service status handle

例子

//注册消息需要添加头文件
#include <Dbt.h>
#include <windows.h>
...
//注册消息 CCheckSoftDog 继承QWidget 或 QWindow,无界面
bool CCheckSoftDog::RegisterHIVDeviceNotification()
{
    HDEVNOTIFY hDeviceNotify;
    /*
     *这里注册的设备是  Human Interface Devices (HID) 类
     *GUID_DEVINTERFACE_HID = {4D1E55B2-F16F-11CF-88CB-001111000030}
    */
    GUID  guid_hiv = {0x4D1E55B2, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30};
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    /*
    * WId QWidget::winId() const:
    *  Returns the window system identifier of the widget.
    *  This value may change at run-time.
    * WId QWindow::winId() const:
    *  Returns the window's platform id.
    */
    HWND hWnd = (HWND)(this->winId()); //获取当前窗口句柄
    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    NotificationFilter.dbcc_classguid = guid_hiv;
    hDeviceNotify = RegisterDeviceNotification (hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
    return (hDeviceNotify != NULL); //true 注册消息成功
}

//处理接受到的消息
// nativeEvent 是重载的虚函数
bool CCheckSoftDog::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
    Q_UNUSED(eventType); //未用该参数
    Q_UNUSED(result); //未用该参数
    MSG *msg = reinterpret_cast<MSG*>(message);
    //消息类型是 设备改变 且为 设备拔出
    if (msg->message == WM_DEVICECHANGE && msg->wParam == DBT_DEVICEREMOVECOMPLETE)
    {
        checkSoftDog(); //检测加密狗
    }
    return false; 
}

用 nativeEventFilter 处理消息

参考: Qt: usb热插拔检测(windows) 里介绍方法,用 nativeEventFilter 来处理消息,在主程序main.cpp中安装事件过滤器 installNativeEventFilter。

实现函数 nativeEventFilter 的类需要继承 QAbstractNativeEventFilter,之前用该方法没成功实现,用该方法时未注册消息。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值