Qt中对USB设备的插拔,可使用nativeEvent系统消息处理函数进行处理,但该函数仅支持当前窗口下的USB设备的监控,当需要在生成的动态链接库中监控系统消息事件,需要使用nativeEventFilter。在需要使用时,工程中使用qApp->installNativeEventFilter()的方式安装事件过滤器。
对于USB的设备获取VID,PID,还需要对硬件GUID进行注册,由于是库中注册,需要传入界面对应的WinId。相关代码:
头文件qtkeyapi.h:
#ifndef QTKEYAPI_H
#define QTKEYAPI_H
#include "qtkeyapi_global.h"
#include <QAbstractNativeEventFilter>
#include <QWidget>
#include <QDebug>
#include <QObject>
#include "Windows.h"
#include "Dbt.h"
#pragma execution_character_set("utf-8")
class QTKEYAPISHARED_EXPORT QtKeyApi : public QWidget,public QAbstractNativeEventFilter
{
Q_OBJECT
public:
QtKeyApi(QWidget* parent = nullptr);
void registerDevice(WId wid);//注册USB设备
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override;//事件过滤
signals:
void deviceIn(QString VID,QString PID);//USB设备插入
void deviceOut(QString VID,QString PID);//USB设备拔出
};
#endif // QTKEYAPI_H
qtkeyapi_global.h:
#ifndef QTKEYAPI_GLOBAL_H
#define QTKEYAPI_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(QTKEYAPI_LIBRARY)
# define QTKEYAPISHARED_EXPORT Q_DECL_EXPORT
#else
# define QTKEYAPISHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // QTKEYAPI_GLOBAL_H
源文件qtkeyapi.cpp:
#include "qtkeyapi.h"
QtKeyApi::QtKeyApi(QWidget *parent):QWidget (parent)
{
}
void QtKeyApi::registerDevice(WId wid)//注册usb设备到系统
{
const GUID GUID_DEVINTERFACE =
{ 0xa5dcbf10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED }};
HDEVNOTIFY hDevNotify;
DEV_BROADCAST_DEVICEINTERFACE NotifacationFiler;
ZeroMemory(&NotifacationFiler,sizeof(DEV_BROADCAST_DEVICEINTERFACE));
NotifacationFiler.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotifacationFiler.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotifacationFiler.dbcc_classguid = GUID_DEVINTERFACE;
for (int i = 0; i < sizeof(GUID_DEVINTERFACE)/sizeof(GUID); i++) {
hDevNotify = RegisterDeviceNotification((HANDLE)wid, &NotifacationFiler, DEVICE_NOTIFY_WINDOW_HANDLE);
if (!hDevNotify) {
qDebug()<<"注册设备失败!";
}else{
qDebug()<<"注册成功!";
}
}
}
bool QtKeyApi::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType);
Q_UNUSED(result);
MSG* msg = reinterpret_cast<MSG*>(message);
int msgType = static_cast<int>(msg->message);
if(msgType == WM_DEVICECHANGE){
PDEV_BROADCAST_DEVICEINTERFACE lpdb = reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(msg->lParam);
switch (msg->wParam) {
case DBT_DEVICEARRIVAL:
{
if(lpdb != nullptr && lpdb->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE){
wchar_t* c = lpdb->dbcc_name;
QString loginStr = QString::fromWCharArray(c).toUpper();
QString sign = loginStr.split("#")[1];
QString VID = sign.split("&")[0];
QString PID = sign.split("&")[1];
emit deviceIn(VID,PID);
}
break;
}
case DBT_DEVICEREMOVECOMPLETE:{
if(lpdb != nullptr && lpdb->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE){
wchar_t* c = lpdb->dbcc_name;
QString loginStr = QString::fromWCharArray(c).toUpper();
QString sign = loginStr.split("#")[1];
QString VID = sign.split("&")[0];
QString PID = sign.split("&")[1];
emit deviceOut(VID,PID);
}
break;
}
default:
break;
}
}
return false;
}
将以上代码生成库文件后,在需要的工程中动态链接该库文件,在工程界面文件中添加热插拔监控,并将信号连接到对应槽函数中:
Load::Load(QWidget *parent) :QWidget(parent),ui(new Ui::Load)
{
ui->setupUi(this);
QtKeyApi* k = new QtKeyApi(this);
k->registerDevice(this->winId());//注册USB设备,传入当前界面WinId
qApp->installNativeEventFilter(k);//安装事件过滤器
connect(k,SIGNAL(deviceIn(QString,QString)),this,SLOT(onDeviceIn(QString,QString)));
connect(k,SIGNAL(deviceOut(QString,QString)),this,SLOT(onDeviceOut(QString,QString)));
}
void Load::onDeviceIn(QString VID, QString PID)
{
qDebug()<<"设备已插入"<<"VID:"<<VID<<"PID:"<<PID;
}
void Load::onDeviceOut(QString VID, QString PID)
{
qDebug()<<"设备已拔出"<<"VID:"<<VID<<"PID:"<<PID;
}
动态链接库成功后即可看到输出信息: