day04

1)GetMessage 函數負責從消息隊列中得到消息,並將其內容填入msg結構體
BOOL GetMessage (
LPMSG lpMsg, //消息結構
HWND hWnd, //窗口句柄,若非NULL則只獲取特定窗口消息
UINT uMsgFilterMin, \
>若非0,則獲取兩個數字之間的消息
UINT uMsgFilterMax /
);
收到WM_QUIT消息返回FALSE,收到其他的消息返回TRUE
case WM_DESTROY:
PostQuitMessage (0);
return 0;
PostQuitMessage 函數在消息隊列放入一個WM_QUIT消息.
2)TranslateMessage 函數負責對部分消息(與可見字符相關,鍵盤消息)進行翻譯
BOOL TranslateMessage (
const MSG* lpMsg //消息結構
);
如果消息被翻譯了返回TRUE,否則返回FALSE
根據CapsLock鍵的狀態判斷大小寫
3)DispatchMessage 派發消息
LONG DispatchMessage (const MSG* lpmsg) 
{
根據lpmsg->hWnd獲取相應的窗口類;
從窗口類的lpfnWndProc成員確定窗口過程函數的地址;
return lpMsg->hWnd.窗口過程函數(lpMsg->hWnd, lpMsg->uMsg, lpMsg->wParam, lpMsg->lParam);
}
4)一旦GetMessage函數從消息隊列中取到WM_QUIT消息即返回FALSE,消息循環結束,線程終止。
----------------------------------------------------------------
一、消息處理
1.每個窗口必須具有窗口過程函數
LPRESULT CALLBACK WindowProc (
HWND hWnd, //窗口句柄
UINT uMsg, //消息標識
WPARAM wParam, //消息參數
LPARAM lParam //消息參數
);
窗口過程函數負責對消息做具體處理
2.窗口過程函數除了被DispatchMessage 函數調用以外,也可以被其他API函數調用,因此需要重入.
3.窗口過程函數並不需要處理所有的消息,對於應用程序不感興趣的消息直接交給缺省窗口過程函數處理即可
LRESULT CALLBACK DefWindowProc (
HWND hWnd, //窗口句柄
UINT uMsg, //消息標識
WPARAM wParam, //消息參數
LPARAM lParam //消息參數
);
窗口過程函數基本範式:
LPRESULT CALLBACK MyWindowProc (
HWND hWnd, //窗口句柄
UINT uMsg, //消息標識
WPARAM wParam, //消息參數
LPARAM lParam //消息參數
)
{
switch (uMsg) {
case WM_XXX:
處理WM_XXX消息
return 0;
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}


二、常見消息
1.WM_DESTROY - 窗口被銷燬時受到次罅隙,無參數。常用於在窗口銷燬之前釋放動態分配的資源,發送WM_QUIT消息結束消息循環.
點擊窗口關閉按鈕 -> WM_SYSCOMMAND(wParam == SC_CLOSE) -> DefWindowProc () ->
CloseWindow () -> WM_CLOSE -> DefWindowProc () -> DestroyWindow ()
-> WM_DESTROY
2.WM_SYSCONMAND - 系統命令消息,當點擊窗口的最大化,最小化,關閉等按鈕時受到此消息,可以根據wParam的不同取值判斷點擊的不同按鈕.
wParam - 具體命令,如SC_CLOSE等
lParam - 鼠標位置,LOWORD水平位置,HIWORD垂直位置。
3.WM_CREATE - 在CreateWindow/CreateWindowEx函數執行過程中,受到此消息,只有在處理該消息的窗口過程函數返回以後CreateWindow/CreateWindowEx函數才返回。常用語初始化窗口狀態、分配資源,創建子窗口.
wParam - 沒用.
lParam  - CREATESTRUCT結構體指針,保存了調用CreateWindow/CreateWindowEx函數所傳遞的參數
這個消息返回-1失敗返回0表示成功。
利用CREATESTRUCT結構體的lpCreateParams成員可以向窗口過程函數WM_CREATE消息處理代碼傳遞自定義的初始化數據.
若窗口過程函數在WM_CREATE消息的處理過程中發生錯誤,則可以return -1,以使CreateWindow/CreateWindowEx函數執行失敗,返回NULL
4.WM_SIZE - 當窗口的大小發生變化時,收到此消息。
常用於調整窗口的顯示或子控件的佈局。
wParam - 窗口大小變化的原因。
lParam - 變化後客戶區的大小。LOWORD寬度、HIWORD高度
5.WM_QUIT - 用於結束消息循環
wParam - PostQuitMessage 函數的參數,退出碼
6.其他消息
WM_PAINT - 繪圖消息
WM_KEYDOWN - 按鍵消息
WM_MOUSEMOVE - 鼠標移動消息
WM_TIMER - 定時器消息
......
三、獲取消息和查看消息
1.獲取消息GetMessage
一旦通過GetMessage從消息隊列中獲取了某個消息,則該消息即從消息隊列中消失。如果消息隊列中沒有符合條件消息,則該函數會阻塞。
2.查看消息:PeekMessage
以查看的方式從消息隊列中獲取消息,可以只看不拿。非阻塞函數。
如果符合條件的消息,該函數會返回TRUE,否則返回FALSE。
BOOL PeekMessage (
LPMSG lpMsg, //消息結構
HWND hWnd, //窗口句柄
UINT wMsgFilterMin,
UINT wMsgFilterMax
UINT wRemoveMsg //PM_NOREMOVE 不取走消息 //PM_REMOVE 取走
);


消息循環1:
MSG msg = {0};
for (;;)
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
{
if (msg.message == WM_QUIT) break;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
else
{
空閒處理;
}




消息循環2:
MSG msg = {0};
for (;;)
if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
{
if (! Getmessage (&msg, NULL, 0, 0) ) break;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
else
{
空閒處理;
}


四、發送消息和投遞消息
1.發送消息:SendMessage
不將消息放入消息隊列,而是直接以消息爲參數去調用相應的窗口過程函數
LRESUTL SendMessage (
HWND hWnd, //窗口句柄
UINT uMsg, //消息標識
WPARAM wParam, //消息參數
LPARAM lParam //消息參數
);
返回窗口過程函數的返回值
避免下面這樣使用該函數:
case WM_XXX
SendMessage (hWnd, WM_XXX, 0, 0);
2.投遞消息
將消息放入消息隊列即返回.
BOOL PostMessage (
HWND hWnd, //窗口句柄
UINT uMsg, //消息標識
WPARAM wParam, //消息參數
LPARAM lParam //消息參數
);
成功返回TRUE,失敗返回FALSE。


case WM_A :
對A的處理;
return 0;
case WM_B:
對B的處理;
return 0;




case WM_MAN:
DrawMan ();
reutrn 0;
case WM_FAMILY:
DrawWoman ();
SendMessage (hWnd, WM_MAN, 0, 0);
DrawChild ();
return 0;


對於需要立即處理的消息使用SendMessage發送,而對於不需要立即處理的消息最好使用PostMessage投遞。
五、消息分類
1.系統消息:0x0000 - 0x03FF
由系統定義的消息,可以在程序中直接使用。
2.用戶消息:0x0400(WM_USER) - 0x7FFF
由用戶定義的消息,自己發出自己處理。
#define WM_EAT WM_USER+1
#define WM_SLEEP WM_USER+2


3.應用程序消息: 0x8000(WM_APP) - 0xBFFF
用於應用程序間通信.
#define WM_WROK WM_APP+1
#define WM_REST WM_APP+2
4.系統註冊消息: 0xC000 - 0xFFFF
在系統中註冊並生成相應消息,然後在應用程序中使用該消息。
六、消息隊列
消息隊列是用於存放消息的隊列型容器.消息在隊列中先進先出(FIFO),所有的窗口程序都有消息隊列,每個線程最多有一個消息隊列。
系統消息隊列: 由系統維護的消息隊列,存放系統產生的消息。如鼠標、鍵盤等。
程序消息隊列: 屬於每一個線程的消息隊列,由線程自己維護。
消息隊列關係: 
A.當鼠標、鍵盤產生消息時,操作系統將此消息放入系統消息隊列;
B.操作系統根據系統消息隊列中每個消息的具體信息,找到相應窗口所屬於的進程。
C.將該消息投遞到程序消息隊列中。
七、隊列消息與非隊列消息
1.隊列消息:消息發送後首先進入消息隊列,然後通過消息循環,從消息隊列中獲取。
GetMessage() <- 程序消息隊列
PeekMessage () <- 程序消息隊列
PostMessage () <- 系統消息隊列
2.非隊列消息:消息發送後,不經過消息隊列,直接調用敞口過程函數
SendMessage() -> 窗口過程函數
3.諸如WM_PAINT、鍵盤、鼠標、定時器等對於順序性、及時性要求較低的消息,常被處理爲隊列消息。
諸如WM_CREATE、WM_SIZE等對於及時性要求較高的消息,常被處理爲非消息隊列消息.












































































發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章