缘由:在修改一份旧代码,是基于wxWidgets开发的,使用VS2017编译。修改过程中,发现wxWidgets需要响应WM_DEVICECHANGE消息,用来监测USB设备的拔插,但是,进一步发现,如果只是依靠wxWidgets本身提供的功能是不能知道USB设备插入(DBT_DEVICEARRIVAL)事件的。这其实涉及到几方面问题了。
1,wxWidgets怎么拦截/监听/响应Windows的消息?
只要在wxFrame的继承类重写下面MSWWindowProc函数即可,比如
//如果有必要就 #include <Windows.h>
WXLRESULT ProjectWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
wxLogDebug(wxT("MSWWindowProc nMsg=%x,%x %x"), nMsg, wParam, lParam);
if (WM_PAINT == message) {
//...这里就可以额外响应WM_PAINT消息了。
}
return wxFrame::MSWWindowProc(message, wParam, lParam);
}
2,拦截/监听 WM_DEVICECHANGE消息
记住要包含头文件
#include <Dbt.h>
#include <usb.h>
#include <usbuser.h>
#include <usbiodef.h>
实践表明,单单就照着下面这么写,可以监听到WM_DEVICECHANGE,能知道DBT_DEVNODES_CHANGED,但是不能获取到DBT_DEVICEARRIVAL和DBT_DEVICEREMOVECOMPLETE 事件。
WXLRESULT ProjectWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
//wxLogDebug(wxT("MSWWindowProc %08x %08x %08x"), nMsg, wParam, lParam);
if ( WM_DEVICECHANGE == message)
{
//注意,此时,只能获取到DBT_DEVNODES_CHANGED事件
if ( DBT_DEVICEARRIVAL == wParam) {
wxLogDebug(wxT("system detected a new device"));
}
else if( DBT_DEVICEREMOVECOMPLETE == wParam ) {
wxLogDebug(wxT("device is gone"));
}
else if( DBT_DEVNODES_CHANGED == wParam ) {
wxLogDebug(wxT("device nodes changed"));
}
}
return wxFrame::MSWWindowProc(message, wParam, lParam);
}
3,怎么知道USB设备拔插事件?
基于WM_DEVICECHANGE 要区分DBT_DEVICEARRIVAL和DBT_DEVICEREMOVECOMPLETE事件,怎么实现?
关键之处就是,要额外注册USB设备事件,完整版如下
//Howard 2020-04-01
WXLRESULT ProjectWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
//wxLogDebug(wxT("MSWWindowProc nMsg=%x,%x %x"), nMsg, wParam, lParam);
if (WM_PAINT == message) {
//仅仅方便测试,关键就是要注册!!
static bool isNeedRegister = true;
if (isNeedRegister) {
isNeedRegister = false;
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
HWND hWnd = (HWND)this->GetHWND();
RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
}
}
else if ( WM_DEVICECHANGE == message)
{
wxLogDebug(wxT("WM_DEVICECHANGE %x %x"), wParam, lParam);
if ( DBT_DEVICEARRIVAL == wParam) {
wxLogDebug(wxT("system detected a new device"));//USB设备插入
}
else if( DBT_DEVICEREMOVECOMPLETE == wParam ) {
wxLogDebug(wxT("device is gone"));//USB设备拔出
}
else if( DBT_DEVNODES_CHANGED == wParam ) {
wxLogDebug(wxT("device nodes changed"));
}
}
return wxFrame::MSWWindowProc(message, wParam, lParam);
}
4,特别说明,设备类型与GUID
特别强调,对于监听HID设备,使用的GUID是不同的。不同类型设备,对应的GUID是有明确规定的。
Common Device Class GUIDs | ||
---|---|---|
Class | GUID | Device Description |
CDROM | 4D36E965-E325-11CE-BFC1-08002BE10318 | CD/DVD/Blu-ray drives |
DiskDrive | 4D36E967-E325-11CE-BFC1-08002BE10318 | Hard drives |
Display | 4D36E968-E325-11CE-BFC1-08002BE10318 | Video adapters |
FDC | 4D36E969-E325-11CE-BFC1-08002BE10318 | Floppy controllers |
FloppyDisk | 4D36E980-E325-11CE-BFC1-08002BE10318 | Floppy drives |
HDC | 4D36E96A-E325-11CE-BFC1-08002BE10318 | Hard drive controllers |
HIDClass | 745A17A0-74D3-11D0-B6FE-00A0C90F57DA | Some USB devices |
1394 | 6BDD1FC1-810F-11D0-BEC7-08002BE2092F | IEEE 1394 host controller |
Image | 6BDD1FC6-810F-11D0-BEC7-08002BE2092F | Cameras and scanners |
Keyboard | 4D36E96B-E325-11CE-BFC1-08002BE10318 | Keyboards |
Modem | 4D36E96D-E325-11CE-BFC1-08002BE10318 | Modems |
Mouse | 4D36E96F-E325-11CE-BFC1-08002BE10318 | Mice and pointing devices |
Media | 4D36E96C-E325-11CE-BFC1-08002BE10318 | Audio and video devices |
Net | 4D36E972-E325-11CE-BFC1-08002BE10318 | Network adapters |
Ports | 4D36E978-E325-11CE-BFC1-08002BE10318 | Serial and parallel ports |
SCSIAdapter | 4D36E97B-E325-11CE-BFC1-08002BE10318 | SCSI and RAID controllers |
System | 4D36E97D-E325-11CE-BFC1-08002BE10318 | System buses, bridges, etc. |
USB | 36FC9E60-C465-11CF-8056-444553540000 | USB host controllers and hubs |
参考资料:
https://docs.microsoft.com/en-us/windows/win32/devio/detecting-media-insertion-or-removal