消息中的wParam和lParam

原文鏈接:https://blog.csdn.net/ahuang1900/article/details/38441121

具體是這麼說:

“在Win 3.x中,WPARAM是16位的,而LPARAM是32位的,兩者有明顯的區別。因爲地址通常是32位的,所以LPARAM 被用來傳遞地址,這個習慣在Win32 API中仍然能夠看到。

在Win32 API中,WPARAM和LPARAM都是32位,所以沒有什麼本質的區 別。


Windows的消息必須參考幫助文件才能知道具體的含義。如果是你定義的消息,願意怎麼使這兩個參數都行。但是習慣上,我們願意使用LPARAM傳 遞地址,而WPARAM傳遞其他參數。”


在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); 
}


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時間。


在Win32 SDK中消息本身是作爲一個結構體記錄傳遞給應用程序的,這個記錄中包含了消息的類型以及其他信息。這個記錄類型叫做MSG,它在window中是這樣聲明的:


typedef struct tagMSG { // msg


HWND hwnd; //窗口句柄


UINT message; //消息常量標識符


WPARAM wParam; //32位消息的特定附加信息,具體表示什麼取決於message


LPARAM lParam; //32位消息的特定附加信息,具體表示什麼取決於message


DWORD time; //消息創建時的時間


POINT pt; //消息創建時的鼠標位置


} MSG;


hwnd 接收消息的32位窗口句柄。窗口可以是任何類型的屏幕對象,因爲Win32能夠維護大多數可視對象的句柄(窗口、對話框、按鈕、編輯框等)。


message 用於區別其他消息的常量值,這些常量可以是Windows單元中預定義的常量,也可以是自定義的常量。


wParam 通常是一個與消息有關的常量值,也可能是窗口或控件的句柄。 lParam 通常是一個指向內存中數據的指針。由於wParam,lParam和指針都是32位的,需要時可以強制類型轉換。具體表示什麼,與message相關,他們是事先定義好的。


如果自定義消息:#define WM_MYMESSAGE WM_USER+100,需確定wParam,lParam的意義 (假設wParam=0時發送數據,wParam=1時接收數據,lParam爲CMyClass* 指針,指向一個CMyClass對象,準備要發送的數據或接收數據 發送WM_MYMESSAGE時 SendMessage(hwnd,WM_MYMESSAGE,0,pMyClassObject) 接收消息的窗口,接收WM_MYMESSAGE中(CMyClass*)lParam參數即pMyClassObject傳過來的數據


MFC數據類型WPARAM 窗口函數或callback函數的一個參數


 


實際上所有的消息響應都有WPARAM和LPARAM的存在,只是有些消息響應WPARAM和LPARAM沒有意義,所以在MFC封裝後有些固定的消息響應函數看不到WPARAM和LPARAM,但依然可以通過GetCurrentMessage()取得當前的消息來查看WPARAM和LPARAM。


WPARAM //typedef UINT WPARAM;control identifier
       LPARAM //typedef LONG LPARAM;notification messages


Windows中的消息由,消息號,字參數(lParam),長字參數(wParam)組成。是包含有關消息的附加信息,隨不同的消息有所不同。例如在鼠標消息中參數lParam 包含鼠標光標座標,wParam包含一個指示各種虛鍵狀態的值(如按下鼠標左鍵還是右鍵。。。).


從消息參數中獲取字符串和位置信息存放到子串口類的成員函數中。字符串m_string爲什麼對應wParam,點m_point對應lParam
LRESULT CChildView::OnReceive(WPARAM wParam,LPARAM lParam)
{
   m_string = *((CSring *)wParam);
   m_point = *((CPoint *)lParam);
  Invalidate();
  return 0;


程序代碼*在對話框中取出數據,並向其他窗口發送消息和數據,將數據指針作爲一個參數發送*/
void CTestDlg2::OnCommBtn()
{
     char szOut[30];
      GetDlgItemText(IDC_OUT,szOut,30);
      m_pParent->SendMessage(WM_DLG_NOTIFY,(WPARAM)szOut);
}


/*在消息接收窗口中*/
/*映射消息處理函數*/
ON_MESSAGE(WM_DLG_NOTIFY,OnDlgNotifyMsg)


/*在視圖中繪製出字符串 m_szOut*/
void CMy53_s1View::OnDraw(CDC* pDC)
{
      CMy53_s1Doc* pDoc = GetDocument();
      ASSERT_VALID(pDoc);
     // TODO: add draw code for native data here
      pDC->TextOut(0,0,"Display String");
      pDC->TextOut(0,20,m_szOut);
}
/*處理通知消息,保存信息並更新顯示*/
LONG CMy53_s1View::OnDlgNotifyMsg(WPARAM wP,LPARAM lP)
{
      m_szOut=(char*)wP;
      Invalidate();
     return 0;
}


一個字符串的地址通過WPARAM來標識,再通過Windows消息發送出去;之後在消息處理函數中WPARAM接受到的參數就是該地址,然後就可以對該地址進行操作了~~~


這是Windows消息機制中經常用到的兩個data type

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