Windows消息(一):隊列消息和非隊列消息


轉自:http://www.cppblog.com/mzty/archive/2006/11/24/15619.html

一 系統消息隊列和應用程序消息隊列

Windows中有一個系統消息隊列,對於每一個正在執行的Windows應用程序,系統為其建立一個“消息隊列”,即應用程

序消息隊列,用來存放該程序可能創建的各種窗口的消息。應用程序中含有一段稱作“消息循環”的代碼,用來從消息隊列中

檢索些消息並把它們分發到相應的窗口函數中。

o_windowsmessage2.jpg

二 消息循環

Windows為當前執行的每個Windows程序維護一個「消息隊列」。在發生輸入事件之后,Windows將事件轉換為一個「消

息」並將消息放入程序的消息隊列中。程序通過執行一塊稱之為「消息循環」的程序代碼從消息隊列中取出消息:

while(GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;

DispatchMessage (&msg) ;
}

msg變量是型態為MSG的結構,型態MSG在WINUSER.H中定義如下:

typedef struct tagMSG
{
HWND hwnd ;
UINT message ;
WPARAM wParam ;
LPARAM lParam ;
DWORD time ;
POINT pt ;
}
MSG, * PMSG ;

POINT數據型態也是一個結構,它在WINDEF.H中定義如下:

typedef struct tagPOINT
{
LONG x ;
LONG y ;
}
POINT, * PPOINT;

TranslateMessage(&msg); 將msg結構傳給Windows,進行一些鍵盤轉換。

DispatchMessage(&msg);又將msg結構回傳給Windows。然后,Windows將該消息發送給適當的窗口消息處理程序,讓它

進行處理。這也就是說,Windows將呼叫窗口消息處理程序。在HELLOWIN中,這個窗口消息處理程序就是WndProc函數。

處理完消息之后,WndProc傳回到Windows。此時,Windows還停留在DispatchMessage呼叫中。在結束

DispatchMessage呼叫的處理之后,Windows回到HELLOWIN程序中,並且接着從下一個GetMessage呼叫開始消息循環。

附:關於窗口過程和消息循環的一些注解。轉自孫鑫老師《Windows程序內部運行機制》

1.關於WNDPROC函數指針原型:typedef LRESULT (CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM); 

   其中CALLBACK函數約定就是__stdcall約定.

2.TranslateMessage函數用於將虛擬鍵消息轉為字符消息。字符消息被投遞到調用線程的消息隊列中,當下一次調用GetMessage函數時取出。當我們敲擊鍵盤上的某個字符鍵時,系統將產生WM_KEYDOWN和WM_KEYUP消息。這兩個消息的附加參數(wParam和lParam)包含的是虛擬鍵代碼和掃描碼等消息,而我們在程序中往往需要得到某個字符的ASSII碼,TranslateMessage這個函數可以將WM_KEYDOWN和WM_KEYUP消息的組合轉換為一條WM_CHAR消息(該消息的wParam附加參數包含了字符的ASCII碼),並將轉換后的新消息投遞到調用線程的消息隊列中。注意,TranslateMessage函數並不會修改原有的消息,它只是產生新的消息並投遞到消息隊列中。

DispatchMessage函數分派一個消息到窗口過程,由窗口過程函數對消息進行處理。DispatchMessage實際上是將消息回傳給操作系統,由操作系統調用窗口過程函數對消息進行處理(響應)。

Windows應用程序的消息處理機制如下圖所示:

Windows程序的消息處理圖:Windows應用程序的消息處理機制

(1)操作系統收到應用程序的窗口消息,將消息投遞到該應用程序的消息隊列中。

(2)應用程序在消息循環中調用GetMessage函數從消息隊列中取出一條一條的消息。取出消息后,應用程序可以對消息進行一些預處理,例如,放棄對某些消息的響應,或者調用TranslateMessage產生新的消息。

(3)應用程序調用DispatchMessage,將消息回傳給操作系統。消息是由MSG結構體對象進行表示的,其中就包含了接收消息的窗口的句柄。因此,DispatchMessage函數總能進行正確的傳遞。

(4)系統利用WNDCLASS結構體的lpfnWndProc成員保存的窗口過程函數的指針調用窗口過程,對消息進行處理(即“系統給應用程序發送了消息”)。

以上就是Windows應用程序的消息處理過程。

三 隊列化消息與非隊列化消息

消息能夠被分為「隊列化的」和「非隊列化的」。隊列化的消息是由Windows放入程序消息隊列中的。在程序的消息循環中,

重新傳回並分配給窗口消息處理程序。非隊列化的消息在Windows呼叫窗口時直接送給窗口消息處理程序。也就是說,隊列化

的消息被「發送」給消息隊列,而非隊列化的消息則「發送」給窗口消息處理程序。任何情況下,窗口消息處理程序都將獲得

窗口所有的消息--包括隊列化的和非隊列化的。窗口消息處理程序是窗口的「消息中心」。

隊列化消息基本上是使用者輸入的結果,以擊鍵(如WM_KEYDOWN和WM_KEYUP消息)、擊鍵產生的字符

(WM_CHAR)、鼠標移動(WM_MOUSEMOVE)和鼠標按鈕(WM_LBUTTONDOWN)的形式給出。隊列化消息還包含時

鍾消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)

非隊列化消息則是其它消息。在許多情況下,非隊列化消息來自呼叫特定的Windows函數。例如,當WinMain呼叫

CreateWindow時,Windows將建立窗口並在處理中給窗口消息處理程序發送一個WM_CREATE消息。當WinMain呼叫

ShowWindow時,Windows將給窗口消息處理程序發送WM_SIZE和WM_SHOWWINDOW消息。當WinMain呼叫

UpdateWindow時,Windows將給窗口消息處理程序發送WM_PAINT消息。鍵盤或鼠標輸入時發出的隊列化消息信號,也能

在非隊列化消息中出現。例如,用鍵盤或鼠標選擇了一個菜單項時,鍵盤或鼠標消息就是隊列化的,而說明菜單項已選中的

WM_COMMAND消息則可能就是非隊列化的

四 SendMessage()與PostMessage()之間的區別是什么?

它們兩者是用於向應用程序發送消息的。PostMessage()將消息直接加入到應用程序的消息隊列中,不等程序返回就退出;而

SendMessage()則剛好相反,應用程序處理完此消息后,它才返回。我想下圖能夠比較好的體現這兩個函數的關系:
o_postmessage.gif

函數peekmessage和getmessage的區別?

兩個函數主要有以下兩個區別:

1.GetMessage將等到有合適的消息時才返回,而PeekMessage只是撇一下消息隊列。

2.GetMessage會將消息從隊列中刪除,而PeekMessage可以設置最后一個參數wRemoveMsg來決定是否將消息保留在隊列

中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM