MFC 消息響應與消息處理過程

WPARAMLPARAM,消息響應機制
wParamlParam 這兩個是Win16系統遺留下來的產物,在Win16API中WndProc有兩個參數: 
一個是WORD類型的16位整型變量;另一個是LONG類型的32位整型變量。因此根據匈牙利命名法,16位的變量就被命名爲wParam, 32位的變量就被命名爲lParam。 

到了Win32API中,原來的16位變量也被擴展爲32位,因此此時wParam和lParam的大小完全相同。 
在Win32API的早期,爲了保證和Win16API的代碼可移植性MS定義了WPARAM和LPARAM兩個宏。 
當時保留了w前綴的原因一方面是由於WPARAM宏也已W開頭,還有也因爲要提醒程序員注意到可移植性,當然到了現在Win16早已退出歷史舞臺,這個前綴也就約定俗成的沿用下來了。
例如:主程序MyDlg.cpp 
1.自定義消息:#define WM_TRAY WM_USER 100 
2.函數原形:afx_msg LRESULT OnTrayNotify(WPARAM wParam,LPARAM lParam); 
3.消息映射:ON_MESSAGE(WM_TRAY,OnTrayNotify) 
4.原函數: 
LRESULT CMyDlg::OnTrayNotify(WPARAM wParam,LPARAM lParam) 
{ 
return m_tray.OnTrayNotify(wParam,lParam); 
} 

托盤類的實現程序Tray.cpp 
成員函數: 
int OnTrayNotify(WPARAM wID,LPARAM lEvent) 
{ 
if(wID == TRAYNOTIFYDATA.uID) 
return 0; 
if(lEvent == WM_LBUTTONDOWN){ 
處理代碼 
} 
else if(lEvent == WM_RBUTTONDOWN){ 
處理代碼 
} 
return 0; 
} 
WPARAM 和 LPARAM 本質上沒有什麼區別:都是32位數,
但是區別也還是有的:除了上面幾位若仁兄說的關於16位的的歷史問題外,MICROSOFT在使用時兩種參數分別代表不同的含義和內容,WPARAM常常代表一些控件的ID或者高位底位組合起來分別表示鼠標的位置,如果消息的發送者需要將某種結構的指針或者是某種類型的句柄時,習慣上用LPARAM來傳遞,可以參考各種控件的通知消息:可以查看:EN_CHANGE (EDIT控件的一個通知消息),CBEM_INSERTITEM(可擴展組合框的可接受消息)等等來加以領會。
理論上在使用自定義消息時,WPARAM LPARAM的含義可以程序員任意指定的,但是最好遵從MFC中的習慣。在調用SendMessage()函數時,第二個參數是WPARAM,第三個參數是這個消息的LPARAM,但是你在程序中某個類中寫下ON_MESSAGE()宏來處理這個消息時,處理函數SomeHandler(WPARAM,LPRAM(默認是0))中解釋這兩個參數時必須按照SendMessage調用中的意義來進行。

消息響應機制
1、消息的組成:一個消息由一個消息名稱(UINT),和兩個參數(WPARAM,LPARAM)。當用戶進行了輸入或是窗口的狀態發生改變時系統都會發送消息到某一個窗口。例如當菜單轉中之後會有WM_COMMAND消息發送,WPARAM的高字中(HIWORD(wParam))是命令的ID號,對菜單來講就是菜單ID。當然用戶也可以定義自己的消息名稱,也可以利用自定義消息來發送通知和傳送數據。 

2、誰將收到消息:一個消息必須由一個窗口接收。在窗口的過程(WNDPROC)中可以對消息進行分析,對自己感興趣的消息進行處理。例如你希望對菜單選擇進行處理那麼你可以定義對WM_COMMAND進行處理的代碼,如果希望在窗口中進行圖形輸出就必須對WM_PAINT進行處理。 

3、未處理的消息到那裏去了:M$爲窗口編寫了默認的窗口過程,這個窗口過程將負責處理那些你不處理消息。正因爲有了這個默認窗口過程我們纔可以利用Windows的窗口進行開發而不必過多關注窗口各種消息的處理。例如窗口在被拖動時會有很多消息發送,而我們都可以不予理睬讓系統自己去處理。 

4、窗口句柄:說到消息就不能不說窗口句柄,系統通過窗口句柄來在整個系統中唯一標識一個窗口,發送一個消息時必須指定一個窗口句柄表明該消息由那個窗口接收。而每個窗口都會有自己的窗口過程,所以用戶的輸入就會被正確的處理。例如有兩個窗口共用一個窗口過程代碼,你在窗口一上按下鼠標時消息就會通過窗口一的句柄被髮送到窗口一而不是窗口二。 

5、示例:下面有一段僞代碼演示如何在窗口過程中處理消息 

LONG yourWndProc(HWND hWnd,UINT uMessageType,WPARAM wP,LPARAM)
{
 switch(uMessageType)
 {//使用SWITCH語句將各種消息分開
  case(WM_PAINT):
   doYourWindow(...);//在窗口需要重新繪製時進行輸出
  break;
  case(WM_LBUTTONDOWN):
   doYourWork(...);//在鼠標左鍵被按下時進行處理
  break;
  default:
   callDefaultWndProc(...);//對於其它情況就讓系統自己處理
  break;
 }
}

接下來談談什麼是消息機制:系統將會維護一個或多個消息隊列,所有產生的消息都回被放入或是插入隊列中。系統會在隊列中取出每一條消息,根據消息的接收句柄而將該消息發送給擁有該窗口的程序的消息循環。每一個運行的程序都有自己的消息循環,在循環中得到屬於自己的消息並根據接收窗口的句柄調用相應的窗口過程。而在沒有消息時消息循環就將控制權交給系統所以Windows可以同時進行多個任務。下面的僞代碼演示了消息循環的用法: 

while(1)
{
 id=getMessage(...);
 if(id == quit)
  break;
 translateMessage(...);
}
當該程序沒有消息通知時getMessage就不會返回,也就不會佔用系統的CPU時間。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章