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,之前用该方法没成功实现,用该方法时未注册消息。

要在Qt中实现USB检测,可以使用QDeviceWatcher类。QDeviceWatcher是一个用于监测设备入和移除事件的类。 首先,确保在项目文件(.pro)中添加以下内容以启用Qt的udev库: ```cpp LIBS += -ludev ``` 然后,可以按照以下步骤在Qt中实现USB检测: 1. 在头文件中包含必要的头文件: ```cpp #include <QObject> #include <QDeviceWatcher> ``` 2. 创建一个类并继承自QObject: ```cpp class USBWatcher : public QObject { Q_OBJECT public: explicit USBWatcher(QObject *parent = nullptr); private slots: void deviceAdded(const QString &devPath); void deviceRemoved(const QString &devPath); private: QDeviceWatcher *m_deviceWatcher; }; ``` 3. 在实现文件中定义构造函数,并在构造函数中初始化QDeviceWatcher对象,并连接相应的槽函数: ```cpp USBWatcher::USBWatcher(QObject *parent) : QObject(parent) { m_deviceWatcher = new QDeviceWatcher(this); connect(m_deviceWatcher, SIGNAL(deviceAdded(QString)), this, SLOT(deviceAdded(QString))); connect(m_deviceWatcher, SIGNAL(deviceRemoved(QString)), this, SLOT(deviceRemoved(QString))); m_deviceWatcher->start(); } ``` 4. 实现设备入和移除的槽函数: ```cpp void USBWatcher::deviceAdded(const QString &devPath) { // 处理设备入事件 qDebug() << "Device added: " << devPath; } void USBWatcher::deviceRemoved(const QString &devPath) { // 处理设备移除事件 qDebug() << "Device removed: " << devPath; } ``` 5. 在你的应用程序中实例化USBWatcher对象,并将其保持活动状态: ```cpp int main(int argc, char *argv[]) { QApplication app(argc, argv); USBWatcher usbWatcher; return app.exec(); } ``` 通过以上步骤,你现在可以在`deviceAdded()`和`deviceRemoved()`槽函数中处理设备入和移除事件。你可以根据需求来执行一些自定义的操作,比如更新UI或者执行特定的任务。 请注意,USB检测需要在具有相应权限的操作系统上运行,如Linux。在不同的操作系统和平台上,可能需要使用不同的方法来实现设备监测
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值