窗口消息
#define WM_LBUTTONDOWN 0x0201
有一些消息具有與它們相關的數據,比如 WM_LBUTTONDOWWN 消息包含了鼠標當前位置的X座標與Y座標。
消息循環
MSG msg;
GetMessage(&msg, NULL, 0, 0);
這個函數從隊列頭部刪除第一條消息,如果隊列是空的,直到另一個功能塊的消息進行排隊。事實上,GetMessage阻塞並不會使你的程序沒有反應。如果沒有消息,程序不做任何事情。如果你需要執行後臺處理,你可以創建額外的線程繼續運行,而GetMessage函數等待另一條消息。(查看寫窗口過程)
TranslateMessage(&msg);
DispatchMessage(&msg);
TranslateMessage函數與鍵盤輸入關聯,它把鍵盤的鍵擊(鍵按下,按鍵放開)轉換成字符,你不需要真正的知道這個函數是如何工作的,只需要知道在調用DispatchMessage函數之前調用它。如果你需要更深入的瞭解,MSDN文檔的鏈接會給你更多的信息。
- 操作系統在消息隊列放置一個WM_LBUTTONDOWN消息。
- 你的程序調用GetMessage函數。
- GetMessage中隊列中提取WM_LBUTTONDOWN並填充MSG結構。
- 你的程序調用TranslateMessage和DispatchMessage函數。
- 在DispatchMessage,操作系統調用你的窗口過程。
- 你的窗口函數可以響應消息或忽略它。
當窗口函數返回,它將返回到DispatchMessage,下一條消息再回到消息循環。只要你的程序在運行,消息將繼續到達隊列。因此,你需要一個循環,不斷的從隊列中提取消息並調度它們。你可能想到的循環執行以下操作:
//警告:實際上不要這樣寫循環
while (1)
{
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
正如以上所寫,這個循環永遠不會結束。這是GetMessage函數放在循環內的返回值。正常情況下,GetMessage函數返回一個非零值。當你想要退出程序和中斷消息循環,簡單的調用PostQuitMessage函數。
PostQuitMessage(0);
PostQuitMessage函數將一個WM_QUIT消息放入隊列,WM_QUIT是一條特殊的消息,它引起GetMessage函數返回零值,消息循環結束的信號。這是修改後的消息循環:
// 正確的消息循環
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
只要GetMessage函數返回非零值,在while循環中表達式的值就是真值,在調用PostQuitMessage函數後,表達式值爲假值程序跳出循環。(這種行爲有一個有趣的結果,你的窗口過程從未收到WM_QUIT消息,所以並不需要在窗口過程中爲這個消息使用case語句。)
下一個明顯的問題是:你應該在什麼時候調用PostQuitMessage函數?我們回到本主題中的窗口關閉的問題。但我們首先要寫我們的窗口過程。
發佈消息和發送消息
上一節談到進入隊列的消息,在某些情況下,操作系統將繞過消息隊列,直接調用窗口過程。
進行這種區分的術語有可能造成混淆:
發佈(Post)一條消息意味着消息在消息隊列中,並通過消息循環調度(GetMessage和DispatchMessage)。
發送(Send)一條消息意味着跳過消息隊列,操作系統直接調用窗口過程。
現在,區別不是很重要。窗口過程處理所有消息,但某些消息繞過消息隊列,直接進入你的窗口過程。然而,如果你的應用程序窗口之間進行通訊它可以有所作爲。你可以在關於消息和消息隊列(About Messages and Message Queues)的主題中找到更深入的討論。
下一節:書寫窗口過程