【wxWidgets】【響應Windows消息】【監聽WM_DEVICECHANGE消息、解決監聽不到DBT_DEVICEARRIVAL的問題、監測USB設備拔插】

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

https://stackoverflow.com/questions/30399992/wm-devicechange-received-but-not-dbt-devicearrival-in-my-qt-app

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章