關於windowsx.h的介紹

關於windowsx.h的介紹

(2011-09-18 21:56:55)
標籤:

雜談


 很多初中級程序員用C/C++編寫WindwosAPI的程序時,經常面對面條式的switch...case語句塊
當你在Window過程(回調函數、下稱過程)中加入大量諸如WM_COMMAND orWM_CHAR的消息捕獲時。真是一場噩夢。
關於上千行代碼的Window過程的問題,隨着 C/C++ 7.0 編譯器和Windows SDK for Windows3.1發行時帶的一個頭文件而被解決。
這個頭文件是 <windowsx.h>以及所包含的大量的有用的宏。按照微軟的說法:這些頭文件所帶來的便利可重複用於下面這些地方(Groups)


.在C程序中使用STRICT宏進行嚴格的類型檢查。
.在windows程序中用宏簡化公共性操作。
.使用控件宏同windows控件進行通訊。
.windows環境下的消息解析器(messagecrackers)(是一個方便的、可移植的、類型安全的處理消息的方法)以及和他相關的參數和返回值


因爲消息解析器嚮導是用於消息解析器的,其他由這頭文件帶來的一些有用的宏,我就跳過不講了,如果你想看看關於
WINDOWSX.H的簡要介紹,可以看 MS Knowledge Base Article #83456.
(http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q83/4/56.asp)
好,讓我們說下消息解析器的優點,當然也包括爲什麼這裏提供的這個工具是如此有用。
當你使用W32SDK編程,用windows過程(通常叫做WndProc)處理窗口和對話框消息時,使用swich-case來捕獲你需要處理的消息是
非常普遍的做法。假設你想處理WM_COMMAND, WM_KEYUP, WM_CLOSE andWM_DESTROY消息,你是這樣作的:

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_COMMAND:
// ...
break;

case WM_KEYUP:
// ...
break;

case WM_CLOSE:
// ...
break;

case WM_DESTROY:
//...
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
這是自從Windows1.0誕生以來處理消息最常見的風格了。而且很肯定,它工作得很好。
但問題是,當你加入一個或多個複雜的特色到你的程序中時,如MDI,OLE 公共控件等等,
結果形成了一個上千行的Window過程,你開始用PageDn和PageUp來查找你想要修改的消息處理代碼了。

消息解析器的第一個好處就是:他把麪條式的case標籤轉換成類似MFC中易於維護和處理的函數。
第二個好處是:處理函數中合適的參數。你可以簡單使用switch(id)代替原先的switch(LOWORD(wparam)),
因爲消息解析器傳遞給你的是 "已解析 "的參數,他等價於LOWORD(wparam)。

HANDLE_MSG 這個消息處理宏在windowx.h中的定義如下:
#define HANDLE_MSG(hwnd, message, fn) \
case (message) : return HANDLE_##message((hwnd), (wParam),(lParam), (fn))
你想要把你的代碼做成 "消息解析 "版的,你需要提供一個解析宏HANDLE_MSG及其函數來處理你的消息.
在window過程裏HANDLE_MSG宏需要三個參數:窗口句柄(hwnd),消息(WM_XXXX),處理你消息的函數(function)。
爲更好地解釋這個:看下面,我們把上面那段代碼轉換成了下面的代碼:

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG (hwnd, WM_COMMAND, OnCommand);
HANDLE_MSG (hwnd, WM_KEYUP, OnKeyup);
HANDLE_MSG (hwnd, WM_CLOSE, OnClose);
HANDLE_MSG (hwnd, WM_DESTROY, OnDestroy);
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}

哇,太好了,緊湊且易於管理的window過程。現在你可以去定義你的消息處理函數了(OnKeyUp, OnClose, andOnDestroy)
還有一個真正的好處,你可以在visual studio IDE 環境中直接跳轉到消息處理函數。

圖片:...(看原文)

有個問題是:當你每加入一個消息處理,你必須在windowx.h中查找相關參數的定義。
因爲消息處理參數的格式是明確的而不能由你隨心所欲。但在頭文件中進行重複搜索是乏味且易出錯的。

消息解析嚮導工具用於解決這個:他允許你粘貼你需要的函數參數,
而你如果只是打草稿,他也會在在你消息處理中寫上一個模板化的window或對話框過程 (??這句有疑問)
消息前驅宏(message fowarding): WINDOWSX.H 的另一個特色 (消息前向?)
WINDOWSX.H另一個特色是消息前驅的可能性,
它是用於 "解壓 "消息處理參數到其他函數調用(如PostMessage, SendMessage,CallWindowProc等)所需要的合適的WPARAM和LPARAM值。
假設我們想用SendMessage發送一個WM_COMMAND消息到父窗口, "模擬"一個在名爲IDC_USERCTL控件上的雙擊(通過發送BN_DBLCLK的通知碼)
我們通常這麼做的:

SendMessage (hwndParent, WM_COMMAND,
MAKEWPARAM(IDC_USERCTL, BN_DBLCLK),
(LPARAM)GetDlgItem(hwnd, ID_USERCTL));
這是相當複雜的語法。SendMessage希望WPARAM參數的低字是控件ID而高字是通知碼,LPARAM參數是控件句柄,句柄我們通過GetDlgItem這

個API函數得到。
上述代碼可以被轉換爲WINDOWSX.H的消息前驅宏,FORWARD_WM_xxxxx。
對於每個消息,消息前向宏用同樣的方式 "打包 "消息解析嚮導創建的函數參數,
並且傳遞給你的處理函數 "已解壓 "的參數(LPARAM/WPARAMs)。
例如:對於一個myWnd窗口的WM_COMMAND消息,消息解析器嚮導將生成如下的函數原形:

void myWnd_OnCommand (HWND hwnd, int id, HWND hwndCtl, UINTcodeNotify)

那麼,這些解析的參數也同樣用於消息前驅宏,這樣上面那使人混亂的SendMessage調用可以簡化爲:

FORWARD_WM_COMMAND (hwndParent, IDC_USERCTL,
GetDlgItem(hwnd, ID_USERCTL), BN_DBLCLK, SendMessage

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