緣由:在修改一份舊代碼,是基於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