Win32 SDK基礎(十一)之消息隊列和GetMessage/PeekMessage、SendMessage/Postmesage的詳解

一、消息隊列

1.1 消息隊列

? ? ? ? 消息隊列是用來存放消息的一個隊列,消息在隊列中先入先出,所有的窗口程序都具有消息隊列,程序可以從隊列中獲取消息。

1.2 消息隊列的類型

? ? ? ? 系統消息隊列:由操作系統維護的消息隊列,存放系統產生的消息,如鼠標、鍵盤消息等等。

? ? ? ? 程序消息隊列:屬于每一個應用程序(線程)的消息隊列,用應用程序維護。

? ? ? ? 當產生鼠標、鍵盤等消息時,消息先存放到系統消息隊列,然后操作系統根據存放的消息找到對應的窗口的消息隊列,將消息投遞到窗口的消息隊列中。

1.3 隊列消息和非隊列消息

? ? ? ? 隊列消息:消息發出后,首先放入隊列,然后通過消息隊列獲取。常見的隊列消息:鍵盤、鼠標、隊列消息等等。

? ? ? ? 非隊列消息:消息發出后,直接找到窗口的消息處理隊列,調用消息處理函數進行處理,無需經過消息隊列。常見的非隊列消息:WM_PAINT、WM_SIZE等等。

二、消息循環和GetMessage/PeekMessage

2.1 消息循環

? ? ? ? 一般的消息循環如下:

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,"處理消息%dn",nMsg.message);  			WriteConsole(hOutput,buff,sizeof(buff),NULL,NULL);  		}  	}??  }

GetMessage/PeekMessage:從程序的消息隊列當中獲取消息。

TranslateMessage:將鍵盤上的按鍵等消息翻譯成字符消息。?

DispatchMessage:將翻譯后的消息再次放入到程序的消息隊列中。

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函數。

BOOL?PeekMessage(  LPMSG?IpMsg,  HWND?hWnd,  UINT?wMSGfilterMin,  UINT?wMsgFilterMax,  UINT?wRemoveMsg  );

lpMsg:接收消息信息的MSG結構指針。
hWnd:其消息被檢查的窗口句柄。
wMsgFilterMin:指定被檢查的消息范圍里的第一個消息。
wMsgFilterMax:指定被檢查的消息范圍里的最后一個消息。
wRemoveMsg:確定消息如何被處理。此參數可取下列值之一:

意義

PM_NOREMOVE

PeekMessage處理后,消息不從隊列里除掉。

PM_REMOVE

PeekMessage處理后,消息從隊列里除掉。

PM_NOYIELD

此標志使系統不釋放等待調用程序空閑的線程。可將PM_NOYIELD隨意組合到PM_NOREMOVE或PM_REMOVE。

GetMessage和PeekMessage的主要區別在于:GetMessage是阻塞函數,它會在消息循環中會一直阻塞直到消息隊列中出現了消息可以被獲取,而PeekMessage是非阻塞函數,不管有沒有獲取到消息隊列中的消息,它都會返回。PeekMessage更多用來檢測消息隊里中是否有消息,它的最后一個參數可以用來指定獲取到消息后要不要把消息從消息隊列中移除,通常情況下通過PeekMessage檢測到消息隊列有消息之后,再調用GetMessage區獲取。

2.3 GetMessage/PeekMessage獲取消息的過程

1、先在程序的消息隊列中查找消息,如果有隊列消息,就取出消息。

2、如果程序的消息隊列中沒有消息,向系統的消息隊列獲取屬于本程序的消息。如果系統的消息隊列中有屬于本程序的消息,系統的消息隊列會將消息分發到本程序的消息隊列中。

3、如果系統的消息隊列也沒有消息,檢查窗口需要繪制的區域是否需要重繪,如果發現有需要重繪的區域,產生WM_PAINT消息。

4、如果沒有重新繪制區域,檢查是否具有到時的定時器,如果有產生WM_隊列R定時器消息。

5、如果沒有到時的定時器,整理程序的資源、內存等等。

三、S隊列Message和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

? ? ? ? 發送消息到程序的消息隊列,不管消息有沒有被處理都會立即返回,用于隊列消息的發送

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享