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

來源:互聯網
上載者:User

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

一 系統訊息佇列和應用程式訊息佇列

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

序訊息佇列,用來存放該程式可能建立的各種視窗的訊息。應用程式中含有一段稱作“訊息迴圈”的代碼,用來從訊息佇列中

檢索這些訊息並把它們分發到相應的視窗函數中。


二 訊息迴圈

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應用程式的訊息處理機制

(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()則剛好相反,應用程式處理完此訊息後,它才返回。我想能夠比較好的體現這兩個函數的關係:

函數peekmessage和getmessage的區別?

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

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

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

中。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.