首页 > 技术 > 内容

获取USB设备信息的方式介绍

时间:2026-01-25  作者:Diven  阅读:0

1 需求描述

实现USB设备的热插拔状态检测;

可识别USB设备信息,例如PID、VID、设备序列号等。

2 设计思路

2.1 获取USB设备信息的方式?

经过查询,Qt可通过本地事件获取到设备相关信息,用到的的事件函数原型为:

bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)

官方说明:这个特殊的事件处理程序可以在子类中重新实现,以接收在消息参数中传递的由eventType标识的本机平台事件。在这个函数的重新实现中,如果您想要停止Qt正在处理的事件,请返回true并设置result,结果参数仅在Windows上有意义。如果返回false,此本机事件将被传递回Qt,Qt将该事件转换为Qt事件并将其发送给窗口。

注意:只有当窗口具有本地窗口句柄时,事件才会交付给此事件处理程序。

很容易理解吧,对于widget窗口而言,这个事件是源头,Qt封装好的事件都从这里来,如果直接返回true界面将无法显示,有兴趣的朋友可以试试。另外,发现没有这个事件是QWidget的,所以只有窗口界面才有,窗口的句柄可以通过QWidget::winId获取到,这个后面注册设备时会用到。

2.2 准备工作?

如果只是重写nativeEvent是不够的,并不能获取到设备信息,只能识别热插拔状态。要识别USB设备信息需要用到GUID,先定义设备的GUID,再注册设备,注册完成后才能获取对应设备的本地事件,从而通过事件获取到设备信息。

GUID(全称:Globally Unique Identifier)全局唯一标识符,在windows上使用GUID来管理设备,驱动,总线,类型,块设备,电源等。

2.3 常用硬件设备GUID

 

IdentifierClass GUID
GUID_DEVINTERFACE_USB_DEVICE{A5DCBF10-6530-11D2-901F-00C04FB951ED}
GUID_DEVINTERFACE_USB_HOST_CONTROLLER{A5DCBF10-6530-11D2-901F-00C04FB951ED}
GUID_DEVINTERFACE_USB_HUB{F18A0E88-C30C-11D0-8815-00A0C906BED8}
GUID_DEVINTERFACE_NET{CAC88484-7515-4C03-82E6-71A87ABAC361}
GUID_DEVINTERFACE_DISK{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
GUID_DEVINTERFACE_CDROM{53F56308-B6BF-11D0-94F2-00A0C91EFB8B}
GUID_DEVINTERFACE_KEYBOARD{884B96C3-56EF-11D1-BC8C-00A0C91405DD}
GUID_DEVINTERFACE_MOUSE{378DE44C-56EF-11D1-BC8C-00A0C91405DD}
GUID_DEVINTERFACE_IMAGE{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}
GUID_BTHPORT_DEVICE_INTERFACE{0850302A-B344-4fda-9BE9-90576B8D46F0}
太多了,网上可以搜到,这里就不一一列出。 

 

3 代码实现

windows提供了接口向系统注册设备,注册后当有U盘插拔(或其volume增删)的时候,会向注册的窗口发送WM_DEVICECHANGE消息:
HDEVNOTIFY WINAPI RegisterDeviceNotification(
__in HANDLE hRecipient, // 可以是窗口句柄或者服务句柄
__in LPVOID NotificationFilter,
__in DWORD Flags // 制定hRecipient是窗口句柄,还是服务句柄
);

先注册设备,这样才能接收到消息,代码如下:

 

void Dialog::registerDevice(){ const GUID GUID_DEVINTERFACE_LIST[] = { { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }, //USB设备的GUID { 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } }}; 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; for (int i = 0; i < sizeof(GUID_DEVINTERFACE_LIST)/sizeof(GUID); i++)  {        NotifacationFiler.dbcc_classguid = GUID_DEVINTERFACE_LIST[i];        hDevNotify = RegisterDeviceNotification((HANDLE)this->winId(), &NotifacationFiler, DEVICE_NOTIFY_WINDOW_HANDLE); if (!hDevNotify) { qCritical() << QStringLiteral("注册失败!"); } }}

 

 

通过本地事件获取消息并解析,代码如下:

 

bool Dialog::nativeEvent(const QByteArray &eventType, void *message, long *result){ Q_UNUSED(eventType); Q_UNUSED(result); MSG *msg = reinterpret_cast(message); int msgType = msg->message; if (WM_DEVICECHANGE == msgType) { PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam; switch (msg->wParam) { case DBT_DEVICEARRIVAL: { if (DBT_DEVTYP_VOLUME == lpdb->dbch_devicetype) { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; if (0 == lpdbv->dbcv_flags) { //优盘 QString USBDisk = QString(this->firstDriveFromMask(lpdbv ->dbcv_unitmask)); ui->labelShowMsg->setText(QString(QStringLiteral("已检测到USB设备插入--盘符:<%1>")).arg(USBDisk)); } else if (DBTF_MEDIA == lpdbv->dbcv_flags) { qDebug() << "CD_Arrived.";                }            } else if (DBT_DEVTYP_DEVICEINTERFACE == lpdb->dbch_devicetype) { PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb; QString name = QString::fromWCharArray(pDevInf->dbcc_name); if (!name.isEmpty()) { if (name.contains("USBSTOR")) { QStringList listAll = name.split('#'); QStringList listInfo = listAll.at(1).split('&'); m_usbInfoList.append(listInfo.at(1).mid(4)); //设备制造商 3 m_usbInfoList.append(listInfo.at(2).mid(5)); //设备型号 4 m_usbInfoList.append(listInfo.at(3).mid(4)); //设备版本 5 } else { m_usbInfoList.clear(); QStringList listAll = name.split('#'); QStringList listID = listAll.at(1).split('&'); m_usbInfoList.append(listID.at(0).right(4)); //vid 0 m_usbInfoList.append(listID.at(1).right(4)); //pid 1 m_usbInfoList.append(listAll.at(2)); //设备序列号 2 } } display(); } } break; case DBT_DEVICEREMOVECOMPLETE: { if (DBT_DEVTYP_VOLUME == lpdb->dbch_devicetype) { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; if (0 == lpdbv->dbcv_flags) { ui->labelShowMsg->setText(QString(QStringLiteral("USB设备已拔出!"))); QTimer::singleShot(1000, ui->labelShowMsg, SLOT(clear())); } if (DBTF_MEDIA == lpdbv->dbcv_flags) { ui->labelShowMsg->setText("CD_Removed."); } } } break; } } return false;}

 

折叠

补充下,获取到的USB设备信息原始数据如下,通过上边的代码进行解析,然后显示到界面上。

 

"\\?\USB#VID_0951&PID_1666#E0D55EA574B4F371679B1A6D#{a5dcbf10-6530-11d2-901f-00c04fb951ed}""\\?\USBSTOR#Disk&Ven_Kingston&Prod_DataTraveler_3.0&Rev_#E0D55EA574B4F371679B1A6D&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}"
发现没有,这个GUID和我们注册的是不是一模一样,有感觉了吧。如果还想获取其设备的相关信息,注册少不了,不然就获取不到。再有一个就是,设备信息并不是一个事件就获取完的,从上可以看出,这里用了两次事件才将信息获取完整,即注册过的两个设备,可以尝试将GUID_DEVINTERFACE_LIST列表移除一个GUID,结果是USB设备信息获取不完整了。

3

通过注册设备、接收本地事件、解析事件消息,最终可获取到设备信息。如果想进一步实现特殊功能,比如自定义无边框拉伸、移动等,也可以通过本地事件实现,这需要对windows消息机制进一步学习才行。当然也可以使用Qt封装好的事件进行处理,都是事件,能玩出什么花样就得看自己的能耐了。到这里对windows消息机制应该会有个初步的了解,还是那句话,有个好的开端总是很重要的。

编辑:黄飞

猜您喜欢


电路保护成为保证设备安全运行的重要环节。作为电子保护元件的自恢复保险丝,因其独特的保护功能和高可靠性,受到众多厂商和用户的青睐。本文将以知名品牌SCHURTER...
2023-10-30 23:59:30
贴片电阻,也叫片式电阻或芯片电阻,是指以矩形或圆柱形的陶瓷为基体,在其表面涂敷一层金属膜或金属氧化膜而制成的电子元件。别看它身材小巧,却在电子电路中扮演着至关重...
2025-04-14 15:02:20
随着新能源汽车和储能行业的蓬勃发展,电池作为其核心部件,其安全性和使用寿命备受关注。电池管理系统(BMS)作为电池的大脑,是很重要的配件。在中国,一批优秀的BM...
2024-07-20 00:00:00
贴片电阻上的「221」并不是直接表示欧姆值,而是一种编码方式。它代表的是22乘以10的1次方,最终结果是220欧姆。这种编码方式通常用于三位数表示的贴片电阻。前...
2024-11-26 11:29:27
保险丝作为保护电路安全的重要元件,受到了越来越多用户的关注。均璞作为知名的一次性保险丝品牌,其电流参数及性能受到市场认可。本文将详细介绍均璞一次性保险丝的电流参...
2020-05-23 03:04:30
还在为繁琐的贴片电阻计算而烦恼吗?现在,一款便捷的贴片电阻计算器手机版来帮您!完全免费下载,让您随时随地轻松计算电阻值。这款计算器操作简单,界面直观,即使您不是...
2025-04-14 15:02:34
你是否曾经被桌面上杂乱的电源线困扰?想象一下,只需要一根网线,就能同时传输数据和电力,让你的桌面更加简洁清爽。这就是以太网供电(Power over Ether...
2024-08-17 00:00:00
在现代社会,安保设备的种类繁多,各自具有不同的功能和特点。监控摄像头是最常见的安保设备,其通过实时录像和回放功能帮助用户监控特定区域。根据清晰度和视角的不同,摄...
2016-03-14 00:00:00
双头螺丝批是常见的手动工具,其主要作用是用于拧紧或松开螺丝。与传统的单头螺丝批不同,双头螺丝批在两端配备了不同规格的螺丝刀头,用户可以根据需要快速更换,极大地提...
2013-01-18 00:00:00
增压泵是用于提高液体压力的设备,应用于多个领域。在家庭生活中,增压泵常用于提升自来水的水压,确保用户在高层住宅中也能享受到稳定的水流。增压泵在工业生产中也是重要...
2010-02-04 00:00:00