Win32 SDK基礎(11)—— 訊息佇列和GetMessage/PeekMessage、SendMessage/Postmesage
阿新 • • 發佈:2019-02-19
一、訊息佇列
1.1 訊息佇列
訊息佇列是用來存放訊息的一個佇列,訊息在佇列中先入先出,所有的視窗程式都具有訊息佇列,程式可以從佇列中獲取訊息。1.2 訊息佇列的型別
系統訊息佇列:由作業系統維護的訊息佇列,存放系統產生的訊息,如滑鼠、鍵盤訊息等等。
程式訊息佇列:屬於每一個應用程式(執行緒)的訊息佇列,用應用程式維護。
當產生滑鼠、鍵盤等訊息時,訊息先存放到系統訊息佇列,然後作業系統根據存放的訊息找到對應的視窗的訊息佇列,將訊息投遞到視窗的訊息佇列中。
1.3 佇列訊息和非佇列訊息
佇列訊息:訊息發出後,首先放入佇列,然後通過訊息迴圈獲取。常見的佇列訊息:鍵盤、滑鼠、定時器訊息等等。 非佇列訊息:訊息發出後,直接找到視窗的訊息處理函式,呼叫訊息處理函式進行處理,無需經過訊息佇列。常見的非佇列訊息:WM_PAINT、WM_SIZE等等。二、訊息迴圈和GetMessage/PeekMessage
2.1 訊息迴圈
一般的訊息迴圈如下:GetMessage/PeekMessage:從程式的訊息隊列當中獲取訊息。 TranslateMessage:將鍵盤上的按鍵等訊息翻譯成字元訊息。 DispatchMessage:將翻譯後的訊息再次放入到程式的訊息佇列中。void Message(HWND hWnd) { MSG nMsg = { 0 }; while (GetMessage(&nMsg, hWnd, 0, 0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); if(nMsg.message == WM_PAINT) { char buff[30]={}; sprintf(buff,"處理訊息%d\n",nMsg.message); WriteConsole(hOutput,buff,sizeof(buff),NULL,NULL); } } }
2.2 GetMessage和PeekMessage
GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
)
lpMsg:指向MSG結構的指標,該結構從執行緒的訊息佇列裡接收訊息資訊。
hWnd:取得其訊息的視窗的控制代碼。當其值取NULL時,GetMessage為任何屬於呼叫執行緒的視窗檢索訊息,執行緒訊息通過PostThreadMessage寄送給呼叫執行緒。
wMsgFilterMin:指定被檢索的最小訊息值的整數。
wMsgFilterMax:指定被檢索的最大訊息值的整數。
返回值:如果函式取得WM_QUIT之外的其他訊息,返回非零值。如果函式取得WM_QUIT訊息,返回值是零。如果出現了錯誤,返回值是-1。例如,當hWnd是無效的視窗控制代碼或lpMsg是無效的指標時。若想獲得更多的錯誤資訊,請呼叫GetLastError函式。
lpMsg:接收訊息資訊的MSG結構指標。BOOL PeekMessage( LPMSG IpMsg, HWND hWnd, UINT wMSGfilterMin, UINT wMsgFilterMax, UINT wRemoveMsg );
hWnd:其訊息被檢查的視窗控制代碼。
wMsgFilterMin:指定被檢查的訊息範圍裡的第一個訊息。
wMsgFilterMax:指定被檢查的訊息範圍裡的最後一個訊息。
wRemoveMsg:確定訊息如何被處理。此引數可取下列值之一:
值 | 意義 |
---|---|
PM_NOREMOVE | PeekMessage處理後,訊息不從佇列裡除掉。 |
PM_REMOVE | PeekMessage處理後,訊息從佇列裡除掉。 |
PM_NOYIELD | 此標誌使系統不釋放等待呼叫程式空閒的執行緒。可將PM_NOYIELD隨意組合到PM_NOREMOVE或PM_REMOVE。 |
2.3 GetMessage/PeekMessage獲取訊息的過程
1、先在程式的訊息佇列中查詢訊息,如果有佇列訊息,就取出訊息。
2、如果程式的訊息佇列中沒有訊息,向系統的訊息佇列獲取屬於本程式的訊息。如果系統的訊息佇列中有屬於本程式的訊息,系統的訊息佇列會將訊息分發到本程式的訊息佇列中。
3、如果系統的訊息佇列也沒有訊息,檢查視窗需要繪製的區域是否需要重繪,如果發現有需要重繪的區域,產生WM_PAINT訊息。
4、如果沒有重新繪製區域,檢查是否具有到時的定時器,如果有產生WM_TIMER定時器訊息。
5、如果沒有到時的定時器,整理程式的資源、記憶體等等。
三、SendMessage和PostMessage
LRESULT SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM IParam
)
hWnd:其視窗程式將接收訊息的視窗的控制代碼。如果此引數為HWND_BROADCAST,則訊息將被髮送到系統中所有頂層視窗,包括無效或不可見的非自身擁有的視窗、被覆蓋的視窗和彈出式視窗,但訊息不被髮送到子視窗。
Msg:指定被髮送的訊息。
wParam:指定附加的訊息特定資訊。
IParam:指定附加的訊息特定資訊。 返回值:返回值指定訊息處理的結果,依賴於所傳送的訊息。
BOOL WINAPI PostMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
hWnd:其視窗程式接收訊息的視窗的控制代碼。可取有特定含義的兩個值:
HWND_BROADCAST:訊息被寄送到系統的所有頂層視窗,包括無效或不可見的非自身擁有的視窗、 被覆蓋的視窗和彈出式視窗。訊息不被寄送到子視窗
NULL:此函式的操作和呼叫引數dwThread設定為當前執行緒的識別符號PostThreadMessage函式一樣
Msg:指定被寄送的訊息。
wParam:指定附加的訊息特定的資訊。
LParam:指定附加的訊息特定的資訊。
返回值:如果函式呼叫成功,返回非零,否則函式呼叫返回值為零
1、SendMessage 傳送訊息到指定的視窗,並等候對方將訊息處理,為阻塞函式,獲取訊息的執行結果後返回。主要需要傳送非佇列訊息,傳送的訊息不經過訊息佇列。 2、PostMessage 傳送訊息到程式的訊息佇列,不管訊息有沒有被處理都會立即返回,用於佇列訊息的傳送。 Github位置:克隆本專案:
git clone [email protected]:HymanLiuTS/Win32SDK.git
獲取本文原始碼:
git checkout WL11