Win32程序與Qt程序對U盤的探測實踐

在Windows操作系統下,所有的事件都是以消息爲驅動的,因此,當我們插U盤和拔U盤時,也是觸發了Windows的消息,我們對此消息進行監聽並接收該消息,就可以探測對U盤的插拔。


01


Win32程序

對於消息的監聽,熟悉Windows中Win32程序原理的你,一定非常熟悉,其六大步驟如下:

1. 聲明消息類(WNDCLASS)

2. 註冊消息類(RegisterClass)

3. 創建窗口(CreateWindow)

4. 獲取消息隊列(GetMessage)

5. 消息傳送(TranslateMessage)

6. 消息派發(DispatchMessage)

在聲明消息類WNDCLASS時,設置消息回調wc.lpfnWndProc爲我們自己的函數,即可以接收到系統的消息到該函數中。

以上過程,在main函數中的源碼如下:

int _tmain(int argc, _TCHAR* argv[])
{
	isNumber("5.8.");

	WNDCLASS wc;
	ZeroMemory(&wc, sizeof(wc));
	wc.lpszClassName = TEXT("myusbmsg");
	wc.lpfnWndProc = WndProc;

	RegisterClass(&wc);
	HWND h = CreateWindow(TEXT("myusbmsg"), TEXT(""), 0, 0, 0, 0, 0,
		0, 0, GetModuleHandle(0), 0);
	MSG msg;
	while (GetMessage(&msg, 0, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}

要接收U盤的插拔消息,就可以在我們設置的回調函數中判斷,假如我們的回調函數聲明如下:

LRESULT CALLBACK WndProc(HWND h, UINT msg, WPARAM wp, LPARAM lp);

首先得判斷收到的消息msg是不是U盤的插拔,因爲Windows的消息非常多,因此得屏蔽掉無關的消息,只處理我們想接受的消息。U盤的插拔所觸發的消息消息爲 WM_DEVICECHANGE 消息,不管是插入U盤,韓式拔掉U盤,都會觸發 WM_DEVICECHANGE 消息。

Windows的消息回調函數還會攜帶WPARAM wp, LPARAM lp連個參數,可以幫助我們判斷U盤是插入還是拔出,以及U盤插入後是

哪個盤符,其詳細解釋如下:

  • wp的值爲 DBT_DEVICEARRIVAL 時,表示U盤插入了。其值爲 DBT_DEVICEREMOVECOMPLETE 時,表示U盤拔出了。

  • 將lp進行轉換 DEV_BROADCAST_VOLUME* p = (DEV_BROADCAST_VOLUME*)lp;得到DEV_BROADCAST_VOLUME的指針p,當 p->dbcv_devicetype == DBT_DEVTYP_VOLUME 時,表示卷標發生變化,即可以知道U盤發生了插入或拔出。

  • 通過 p->dbcv_unitmask 可以根據其位操作中1的標識位判斷具體是哪個盤發生了插入或拔出,其判斷函數如下:

char FirstDriveFromMask(ULONG unitmask)

{

char i;

for (i = 0; i < 26; ++i)

{

if (unitmask & 0x1)

break;

unitmask = unitmask >> 1;

}

return (i + 'A');

}

通過代碼一目瞭然可知,當p->dbcv_unitmask爲0x1時爲A盤,爲0x10時爲B盤,爲0x100時爲C盤,爲0x1000時爲D盤...以此類推。


以下奉上接收消息的函數,以及U盤插拔判斷的邏輯,如下僅供參考:

LRESULT CALLBACK WndProc(HWND h, UINT msg, WPARAM wp, LPARAM lp)

{

/*

* system uses the WM_DEVICECHANGE message to notify device is changed(USB is inserted or removed).

*/

if (msg == WM_DEVICECHANGE) {

printf("注意---Msg-Change===wp=%d---lp=%d\n", wp, lp);


/*

* #define DBT_DEVNODES_CHANGED 0x0007

* Message = WM_DEVICECHANGE

* wParam  = DBT_DEVNODES_CHANGED

* lParam  = 0

*

*      send when configmg finished a process tree batch. Some devnodes

*      may have been added or removed. This is used by ring3 people which

*      need to be refreshed whenever any devnode changed occur (like

*      device manager). People specific to certain devices should use

*      DBT_DEVICE* instead.

*

* The upon windows-msg-param is received when device list is changed, but this time

* system don't know which device is add or remove, after second signal received, the

* below wparam can judge U-Disk or other device.

*/


/*

* The below wparam DBT_DEVICEARRIVAL(system detected a new device) & DBT_DEVICEREMOVECOMPLETE(device is gone)

* can just detect U-Disk inserted or removed(VOLUME List Changed), other device didn't show in volume list

* will not receive DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE(Like Mouse and KeyBorad with not line).

*/

if ((DWORD)wp == DBT_DEVICEARRIVAL) {

DEV_BROADCAST_VOLUME* p = (DEV_BROADCAST_VOLUME*)lp;

if (p->dbcv_devicetype == DBT_DEVTYP_VOLUME) {

char disk = FirstDriveFromMask(p->dbcv_unitmask);

printf("注意---%c盤插進來了\n", disk);

}

}

else if ((DWORD)wp == DBT_DEVICEREMOVECOMPLETE) {

DEV_BROADCAST_VOLUME* p = (DEV_BROADCAST_VOLUME*)lp;

if (p->dbcv_devicetype == DBT_DEVTYP_VOLUME) {

char disk = FirstDriveFromMask(p->dbcv_unitmask);

printf("注意---%c盤被拔掉了\n", disk);

}

}

return TRUE;

}

else return DefWindowProc(h, msg, wp, lp);

}

以上即爲win32接收U盤插拔的監聽探測代碼。

02


Qt程序

下面介紹Qt如何監聽探測U盤的插拔消息,由於Windows系統是以消息爲驅動的,因此,想用Qt接受監聽U盤的插拔消息,說到底其實就是Qt如何接收監聽Windows的消息。

在Qt4中,接收監聽Windows消息的Qt函數聲明如下:

bool winEvent(MSG *message, long *result);

 在Qt5之後,函數聲明變爲了如下:

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

對以上兩個函數中的message參數進行如下處理:

MSG* msg = reinterpret_cast<MSG*>(message);

即可得到Windows消息的結構體MSG,其定義如下:

typedef struct tagMSG {

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time;

POINT pt;

} MSG

因此就可以得到UINT message、WPARAM wParam 以及 LPARAM lParam; 接下來的處理就如同win32中的回調函數WndProc一樣了。


以上不僅僅是Qt對U盤插拔消息的監聽,通過以上Qt的winEvent或nativeEvent函數的重寫,以及相應參數的轉換處理,Qt可以接收監聽所有的Windows的消息,說到這裏,對Win32瞭解的你,一定非常熟悉了。


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