MFC具备检测设备的消息,但需要手动添加。针对USB设备,需要注册对应的GUID方可。本文对此进行简单记录。
本省略对MFC机制的描述,仅描述主要的模块代码。
一、步骤
Dbt.h头文件引用
在stdafx.h(或有关的头文件)添加Dbt.h
头文件的引用:
1 | #include <Dbt.h> |
注册USB设备GUID
在对话框初始化函数中注册:
1 | BOOL CFooDlg::OnInitDialog() |
说明1:不同的USB设备使用不同的GUID表示。在注册时需要指定要检测哪一类,本文针对HID,有兴趣者可使用其它来测试。
说明2:笔者使用的键盘有多个USB设备,其一为HID设备,在设备管理器中查询其类GUID为745a17a0-74d3-11d0-b6fe-00a0c90f57da
。
说明3:查询到的GUID与代码GUID结构体本质一样,形式不同。具体参考定义。
消息函数声明
在对话框头文件声明消息函数:
1 | afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData); |
消息声明
在对话框实现文件中添加ON_WM_DEVICECHANGE消息:
1 | BEGIN_MESSAGE_MAP(CFooDlg, CDialogEx) |
消息响应函数实现
下面实现OnDeviceChange函数:
1 | BOOL CFooDlg::OnDeviceChange(UINT nEventType, DWORD dwData) |
注1:只有注册的设备,nEventType才有DBT_DEVICEARRIVAL、DBT_DEVICEREMOVECOMPLETE(当然也有其它值,按下不提),如果不注册,nEventType的值为7。
注2:查了些资料,说nEventType值不同,dwData亦不同。但本文没有深入研究。
注3:如果要针对某一种设备,如所属为HID,但厂家不同,则可以通过查找VID关键字来过滤。文中代码使用偏移量外加字符串搜索来实现,仅作示例,有些绕,但能实现功能。
后在 Windows 7 系统上用 VS 2015 编译,发现 ON_WM_DEVICECHANGE 出错,经排查,定位到
1 | afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData); |
声明不兼容。修改为:
1 | afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD_PTR dwData); |
可解决编译问题,并且在 Win10 也能正常编译。
二、测试
使用
1 | 0xA5DCBF10, 0x6530, 0x11D2,{ 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } |
可以检测出所有的USB设备事件。包括U盘、键盘等。
使用
1 | 0x53f56307, 0xb6bf, 0x11d0,{ 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } |
只能检测出U盘事件。
使用
1 | 0x745A17A0, 0x74D3, 0x11D0,{ 0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA } |
检测不出HID事件(此处原因未知)。
但是,使用
1 | 0x4D1E55B2, 0xF16F, 0x11CF,{ 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } |
可以检测出HID事件。
三、小结
本文不过多涉及检测原理,代码测试通过。
需要指出的是,在 Windows 上使用 Qt 编程检测 USB 事件,也是使用本文所提到的技术,包括注册、响应事件。毕竟,无论 MFC 还是 Qt 程序,都是在 Windows 上运行的,可谓殊途同归。当然,如 Linux 或 MacOS 系统,机制已然不同,不在此列。