1. 程式人生 > >Wparam與Lparam的區別

Wparam與Lparam的區別

在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傳過來的資料

我舉個例子吧,也不知確切不確切,大家多包涵阿 
首先要說windows是訊息驅動的系統,系統為每一個程式(應該說程序)建立一個訊息佇列。 
舉我們選擇選單的例子,當選擇了一個選單項的時候,Windows向選單所屬的視窗傳送WM_COMMAND訊息;而使用者按下了一個加速鍵的時候,windows向TranslateAccelerate函式指定的目標視窗傳送WM_COMMAND訊息。一般這兩者對應的視窗都是主視窗,所以在主視窗中的視窗過程中集中處理WM_COMMAND訊息,而不必考慮它究竟是選單引發的還是加速鍵引發的。 
WM_COMMAND訊息的兩個引數是這樣定義的: 
wParam的高位 =wNotifyCode ;通知碼 
wParam的低位 =wID ;命令ID 
lParam = hwdCtl ;傳送WM_COMMAND 訊息的子視窗控制代碼,即誰發的該訊息 
除了選單和加速鍵,WM_COMMAND 訊息也可以由其他子視窗引發,如主視窗中的按鈕或工具欄,還有你提到的系統托盤的滑鼠事件等等,lParam引數指定了引發訊息的子視窗控制代碼,對於選單和加速鍵引發的WM_COMMAND訊息,lParam的值為0。wParam引數的低16位是命令ID,也就是資源指令碼檔案中選單項的命令ID或加速鍵的命令ID,高16位是通知碼,選單訊息的通知碼是0,加速鍵訊息的通知碼為1。 
這只是選單和加速鍵的定義。其他的訊息可能與此不同,具體查資料吧。

WPARAM

  WPARAM,訊息響應機制  wParam和lParam 這兩個是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的低字中(LOWORD(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(...);   i f(id == quit)   break;    translateMessage(...);    }    當該程式沒有訊息通知時getMessage就不會返回,也就不會佔用系統的CPU時間。