訊息的接收主要有3個函式:GetMessage、PeekMessage、WaitMessage。
GetMessage原型如下:BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax);
PeekMessage原型如下:BOOL PeekMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg);
該函式用於查看應用程式的訊息佇列,如果其中有訊息就將其放入lpMsg所指的結構中,不過,與GetMessage不同的是, PeekMessage函式不會等到有訊息放入佇列時才返回。同樣,如果hWnd為NULL,則PeekMessage獲取屬於調用該函式應用程式的任一視窗的訊息,如果hWnd=-1,那么函式只返回把hWnd參數為NULL的PostAppMessage函式送去的訊息。如果 wMsgFilterMin和wMsgFilterMax都是0,則PeekMessage就返回所有可得到的訊息。函式獲取之後將刪除訊息佇列中的除 WM_PAINT訊息之外的其他訊息,至於WM_PAINT則只有在其處理之後才被刪除。
WaitMessage原型如下:BOOL WaitMessage();當一個應用程式無事可做時,該函式就將控制權交給另外的應用程式,同時將該應用程式掛起,直到一個新的訊息被放入應用程式的佇列之中才返回。
訊息的處理
接下來我們談一下訊息的處理,首先我們來看一下VC中的訊息泵:
while(GetMessage(&msg, NULL, 0, 0))
{
if(!TranslateAccelerator(msg.hWnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
首先,GetMessage從進程的主執行緒的訊息佇列中獲取一個訊息並將它複製到MSG結構,如果佇列中沒有訊息,則GetMessage函式將等待一個訊息的到來以後才返回。如果你將一個視窗句柄作為第二個參數傳入GetMessage,那么只有指定視窗的的訊息可以從佇列中獲得。GetMessage也可以從訊息佇列中過濾訊息只接受訊息佇列中落在範圍內的訊息。這時候就要利用GetMessage/PeekMessage指定一個訊息過濾器。這個過濾器是一個訊息標識符的範圍或者是一個窗體句柄,或者兩者同時指定。當應用程式要查找一個後入訊息佇列的訊息是很有用。WM_KEYFIRST 和 WM_KEYLAST 常量用於接受所有的鍵盤訊息。 WM_MOUSEFIRST 和 WM_MOUSELAST 常量用於接受所有的滑鼠訊息。
然後TranslateAccelerator判斷該訊息是不是一個按鍵訊息並且是一個加速鍵訊息,如果是,則該函式將把幾個按鍵訊息轉換成一個加速鍵訊息傳遞給視窗的回調函式。處理了加速鍵之後,函式TranslateMessage將把兩個按鍵訊息WM_KEYDOWN和WM_KEYUP 轉換成一個WM_CHAR,不過需要注意的是,訊息WM_KEYDOWN,WM_KEYUP仍然將傳遞給視窗的回調函式。
處理完之後,DispatchMessage函式將把此訊息傳送給該訊息指定的視窗中已設定的回調函式。如果訊息是WM_QUIT,則 GetMessage返回0,從而退出循環體。應用程式可以使用PostQuitMessage來結束自己的訊息循環。通常在主視窗的 WM_DESTROY訊息中調用。
下面我們舉一個常見的小例子來說明這個訊息泵的運用:
if (::PeekMessage(&msg, m_hWnd, WM_KEYFIRST,WM_KEYLAST, PM_REMOVE))
{
if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)...
}
這裡我們接受所有的鍵盤訊息,所以就用WM_KEYFIRST 和 WM_KEYLAST作為參數。最後一個參數可以是PM_NOREMOVE 或者 PM_REMOVE,表示訊息信息是否應該從訊息佇列中刪除。
所以這段小代碼就是判斷是否按下了Esc鍵,如果是就進行處理。