深入解析C++的WNDCLASS結(jié)構(gòu)體及其在Windows中的應(yīng)用
WNDCLASS是一個(gè)由系統(tǒng)支持的結(jié)構(gòu),用來(lái)儲(chǔ)存某一類(lèi)窗口的信息,如ClassStyle,消息處理函數(shù),Icon,Cursor,背景Brush等。也就是說(shuō),CreateWindow只是將某個(gè)WNDCLASS定義的窗體變成實(shí)例。要得到某一窗口的WNDCLASS數(shù)據(jù),可以用GetClassLong();
RegisterClass()就是在系統(tǒng)注冊(cè)某一類(lèi)型的窗體。也就是將你提供的WNDCLASS數(shù)據(jù)注冊(cè)為一個(gè)窗口類(lèi),在WNDCLASS.lpszClassName中定義該WNDCLASS的標(biāo)識(shí),無(wú)論CreateWindow或CreateWindowEx創(chuàng)建的窗口都必須對(duì)應(yīng)一個(gè)WNDCLASS,但一個(gè)WNDCLASS可以有多個(gè)窗口對(duì)象。
有一些系統(tǒng)預(yù)定義的窗口類(lèi),如:ClassName=_T("BUTTON" or "COMBOBOX" or "EDIT" or "LISTBOX" or "MDICLIENT" or "SCOLLBAR" or "STATIC"),要用這些窗體,直接用CreateWindow創(chuàng)建相應(yīng)對(duì)象就是了。要得到某一窗口的窗口類(lèi),可以用GetClassName();
WNDCLASS中的回調(diào)函數(shù)是窗體的消息處理函數(shù):CALLBACK WinProc(MESSAGE msg,LPARAM lparam,WPARAM wParam);
窗口類(lèi)屬性定義
結(jié)構(gòu)WNDCLASS包含一個(gè)窗口類(lèi)的全部信息,也是Windows編程中使用的基本數(shù)據(jù)結(jié)構(gòu)之一,應(yīng)用程序通過(guò)定義一個(gè)窗口類(lèi)確定窗口的屬性,定義如下:
typedef struct _WNDCLASS { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS, *PWNDCLASS;
舉例說(shuō)明
例子:
long CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);//聲明 //WinMain函數(shù)是所有Windows應(yīng)用程序的入口,類(lèi)似c語(yǔ)言中的main函數(shù)其功能是完成//一系列的定義和初始化,并產(chǎn)生消息循環(huán)。函數(shù)說(shuō)明: int WINAPI WinMain(HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { //初始化,初始化包括窗口類(lèi)的定義、注冊(cè)、創(chuàng)建窗口實(shí)例和顯示窗口四部分 HWND hwnd; MSG Msg; WNDCLASS wndclass; char lpszClassName[]="窗口"; //窗口類(lèi)名 char lpszTitle[]="測(cè)試窗口"; //窗口標(biāo)題名 //窗口類(lèi)定義,窗口類(lèi)定義了窗口的形式與功能,窗口類(lèi)定義通過(guò)給窗口類(lèi)數(shù)據(jù)結(jié)構(gòu)WNDCLASS賦值完成 //該數(shù)據(jù)結(jié)構(gòu)中包含窗口類(lèi)的各種屬性 wndclass.style =0; // 窗口類(lèi)型為缺省類(lèi)型CS_ Class Style wndclass.lpfnWndProc=WndProc; //定義窗口處理函數(shù) wndclass.cbClsExtra=0; //窗口類(lèi)無(wú)擴(kuò)展 wndclass.cbWndExtra=0; //窗口實(shí)例無(wú)擴(kuò)展 wndclass.hInstance=hInstance; //當(dāng)前實(shí)例句柄 wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); //窗口的最小化圖標(biāo)為缺省圖標(biāo) wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); // 窗口采用箭頭光標(biāo) wndclass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH)); //窗口背景為白色 wndclass.lpszMenuName=NULL; //窗口無(wú)菜單 wndclass.lpszClassName=lpszClassName; //窗口類(lèi)名為“窗口” //以下是窗口類(lèi)的注冊(cè)-----------Windows系統(tǒng)本身提供部分預(yù)定義的窗口類(lèi),程序員也可以自定義窗口類(lèi),窗口類(lèi)必須先注冊(cè)后使用。 if(!RegisterClass(&wndclass)) //如果注冊(cè)失敗 發(fā)出警告 {MessageBeep(0); return FALSE;} //創(chuàng)建窗口創(chuàng)建一個(gè)窗口的實(shí)例由函數(shù)CreateWindow()實(shí)現(xiàn) hwnd=CreateWindow( lpszClassName, //窗口類(lèi)名,創(chuàng)建窗口時(shí)一定要基于我們已經(jīng)注冊(cè)過(guò)的窗口類(lèi)名,即"窗口"。 lpszTitle, //窗口標(biāo)題名 WS_OVERLAPPEDWINDOW, //窗口的風(fēng)格 WS_ Windows Style CW_USEDEFAULT, //窗口左上角坐標(biāo)值為缺省值 CW_ Create Wndow CW_USEDEFAULT, CW_USEDEFAULT, //窗口的高和寬為缺省值 CW_USEDEFAULT, NULL, //此窗口無(wú)父窗口 NULL, //此窗口無(wú)子菜單 hInstance, //創(chuàng)建此窗口的應(yīng)用程序的當(dāng)前句柄 NULL //不使用該值 ); //顯示窗口 ShowWindow(hwnd,nCmdShow); //繪制用戶區(qū) UpdateWindow(hwnd); //消息循環(huán) while(GetMessage(&Msg,NULL,0,0)) //GetMessage()函數(shù)是從調(diào)用線程的消息隊(duì)列中取出一條消息;對(duì)于每一個(gè)應(yīng)用程序窗口線程,操作系統(tǒng)都會(huì)為其建立一個(gè)消息隊(duì)列,當(dāng)我們的窗口有消息時(shí)(即所有與這個(gè)窗口線程相關(guān)的消息),操縱系統(tǒng)會(huì)把這個(gè)消息放到該線程的消息隊(duì)列當(dāng)中,我們的窗口程序就通過(guò)這個(gè)GetMessage()函數(shù)從自己的消息隊(duì)列中取出一條一條具體的消息并進(jìn)行響應(yīng)操作。 { TranslateMessage(&Msg);//對(duì)"消息對(duì)"的轉(zhuǎn)化,如對(duì)鍵盤(pán)的WM_KEYDOWN和WM_KEYUP消息對(duì)轉(zhuǎn)化為WM_CHAR消息,并且將轉(zhuǎn)換后的新消息投遞到我們的消息隊(duì)列中去,這個(gè)轉(zhuǎn)化操作不會(huì)影響原來(lái)的消息,只會(huì)產(chǎn)生一個(gè)新的消息。 DispatchMessage(&Msg);//DispatchMessage()函數(shù)是將我們?nèi)〕龅南鞯酱翱诘幕卣{(diào)函數(shù)去處理;可以理解為該函數(shù)將取出的消息路由給操作系統(tǒng),然后操作系統(tǒng)去調(diào)用我們的窗口回調(diào)函數(shù)對(duì)這個(gè)消息進(jìn)行處理。 } return Msg.wParam; //消息循環(huán)結(jié)束 即程序結(jié)束時(shí) 將信息返回系統(tǒng) } //窗口函數(shù),窗口函數(shù)定義了應(yīng)用程序?qū)邮盏降牟煌⒌捻憫?yīng),其中包含了應(yīng)用程序?qū)Ω鞣N可能接受到的消息的處理過(guò)程,時(shí)消息處理分支控制語(yǔ)句的集合 long CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_DESTROY: PostQuitMessage(0); default: //缺省時(shí)采用系統(tǒng)消息缺省處理函數(shù) return DefWindowProc(hwnd,message,wParam,lParam); } return (0); }
注:窗口回調(diào)函數(shù)的函數(shù)指針定義typedef LRESULT CALLBACK (* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
WNDPROC OldWndProc; LRESULT CALLBACK NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ switch (Msg) { ...... } return CallWindowProc(OldWndProc,g_Wnd,Msg,wParam,lParam); } OldWndProc = (WNDPROC)GetWindowLong(g_Wnd,GWL_WNDPROC); SetWindowLong(hwnd, GWL_WNDPROC,(LPARAM)(WNDPROC)NewWndProc);
通過(guò)調(diào)用SetWindowLong函數(shù)可以修改該窗體類(lèi)的回調(diào)函數(shù)。
CallBack 函數(shù)中的wParam和lParam有什么區(qū)別:
WPARAM wParam, 定義成WORD型
LPARAM lParam 定義成LONG型
在Win 3.x中,WPARAM是16位的,而LPARAM是32位的,兩者有明顯的區(qū)別。
在Win32 API中,WPARAM和LPARAM都是32位,所以沒(méi)有什么本質(zhì)的區(qū)別。
但是習(xí)慣上,我們?cè)敢馐褂肔PARAM傳遞地址,而WPARAM傳遞其他參數(shù)。
function MouseHookProc(nCode: Integer; wPar: WPARAM; lPar: LPARAM): lResult; stdcall;
如果我要判斷鼠標(biāo)左鍵是否按下,用wParam==WM_LBUTTONDOWN判斷.
lParam 是 (tagMOUSEHOOKSTRUCT的指針)PMouseHookStruct類(lèi)型,主要是獲得發(fā)送窗口句柄,鼠標(biāo)坐標(biāo) ,以及其他一些信息 。
lParam 用的時(shí)候需要強(qiáng)制轉(zhuǎn)換,轉(zhuǎn)換成PMouseHookStruct類(lèi)型.
PMouseHookStruct = ^TMouseHookStruct; tagMOUSEHOOKSTRUCT = packed record pt: TPoint; hwnd: HWND; wHitTestCode: UINT; dwExtraInfo: DWORD; end; TMouseHookStruct = tagMOUSEHOOKSTRUCT;
function GetMsgProc(nCode: Integer; wPara: WPARAM; lPara: LPARAM) : lResult; stdcall; var hGetMsgHook:HHOOK; Msg: TMsg; begin if (nCode >= 0) then begin FillChar(pMsgData^, Sizeof(TMessageRecord), #0); Msg := TMsg(Pointer(lPara)^); end; Result := CallNextHookEx(hGetMsgHook, nCode, wPara, lPara); end;
數(shù)據(jù)結(jié)構(gòu)原型
typedef struct _WNDCLASS{ UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; }WNDCLASS;
結(jié)構(gòu)說(shuō)明
WNDCLASS 結(jié)構(gòu)包含了RegisterClass函數(shù)注冊(cè)的類(lèi)屬性
分量簡(jiǎn)介
style: 指定類(lèi)風(fēng)格。這些風(fēng)格可通過(guò)按位或操作組合起來(lái)。風(fēng)格如下:
- CS_BYTEALIGNCLIENT: 在字節(jié)邊界上(在x方向上)定位窗口的用戶區(qū)域的位置
- CS_BYTEALIGNWINDOW: 在字節(jié)邊界上(在x方向上)定位窗口的位置
- CS_CLASSDC: 該窗口類(lèi)的所有窗口實(shí)例都共享一個(gè)窗口類(lèi)DC
- CS_DBLCLKS: 允許向窗口發(fā)送雙擊鼠標(biāo)鍵的消息
- CS_GLOBALCLASS: 當(dāng)調(diào)用CreateWindow 或 CreateWindowEx 函數(shù)來(lái)創(chuàng)建窗口時(shí)允許它的hInstance參數(shù)和注冊(cè)窗口類(lèi)時(shí)傳遞給RegisterClass 的 hInstance參數(shù)不同。如果不指定該風(fēng)格,則這兩個(gè) hInstance 必須相同。
- CS_HREDRAW: 當(dāng)水平長(zhǎng)度改變或移動(dòng)窗口時(shí),重畫(huà)整個(gè)窗口
- CS_NOCLOSE: 禁止系統(tǒng)菜單的關(guān)閉選項(xiàng)
- CS_OWNDC: 給予每個(gè)窗口實(shí)例它本身的DC。注意,盡管這樣是很方便,但它必須慎重使用,因?yàn)槊總€(gè)DC大約要占800個(gè)字節(jié)的內(nèi)存。
- CS_PARENTDC: 將子窗口的裁剪區(qū)域設(shè)置到父窗口的DC中去,這樣子窗口便可以在父窗口上繪制自身。注意,這是子窗口還是從系統(tǒng)緩存中獲取DC,而不是使用父窗口的DC。使用該風(fēng)格可以提高系統(tǒng)性能。
- CS_SAVEBITS: 以位圖形式保存被該窗口遮擋的屏幕部分,這樣當(dāng)給窗口移動(dòng)以后,系統(tǒng)便可以用該保存的位圖恢復(fù)屏幕移動(dòng)的相應(yīng)部分,從而系統(tǒng)不用向被該窗口遮擋的窗口發(fā)送 WM_PAINT 消息。該特性對(duì)于菜單類(lèi)型的窗口比較合適,因?yàn)樗ǔJ呛?jiǎn)短的顯示一下之后便消失。設(shè)置該特性將增加顯示該窗口的時(shí)間,因?yàn)樗ǔR确峙浔4嫖粓D的內(nèi)存。
- CS_VREDRAW: 當(dāng)垂直長(zhǎng)度改變或移動(dòng)窗口時(shí),重畫(huà)整個(gè)窗口
- lpfnWndProc: 指向窗口過(guò)程
cbClsExtra: 指定緊隨在 WNDCLASS 數(shù)據(jù)結(jié)構(gòu)后分配的字節(jié)數(shù)。系統(tǒng)將其初始化為零。
cbWndExtra: 指定緊隨在窗口實(shí)例之后分配的字節(jié)數(shù),系統(tǒng)將其初始化為零。如果應(yīng)用程序正在用WNDCLASS結(jié)構(gòu)注冊(cè)一個(gè)在RC資源描述文件中用CLASS指令創(chuàng)建的對(duì)話框時(shí),它必須設(shè)置這個(gè)字段為 DLGWINDOWEXTRA。
hInstance: 標(biāo)識(shí)了該窗口類(lèi)的窗口過(guò)程所在的模塊實(shí)例的句柄,不能為NULL。
hIcon: 標(biāo)識(shí)了該窗口類(lèi)的圖標(biāo)。hIcon字段必須是一個(gè)圖標(biāo)的句柄;若hIcon字段為NULL,則無(wú)論何時(shí)用戶把應(yīng)用程序縮至最小時(shí),應(yīng)用程序必須畫(huà)一個(gè)圖標(biāo)。
hCursor: 標(biāo)識(shí)該窗口類(lèi)的光標(biāo),hCursor必須是一個(gè)光標(biāo)資源的句柄。若hCursor字段為NULL,則無(wú)論何時(shí)鼠標(biāo)移到應(yīng)用程序窗口時(shí),應(yīng)用程序必須顯式設(shè)置光標(biāo)形狀。
hbrBackground: 標(biāo)識(shí)了該窗口類(lèi)的背景畫(huà)筆。hbrBackground字段必須是用于繪制背景的物理刷子的句柄,或者是一個(gè)顏色的值。如果給出一個(gè)顏色的值,它必須是下面列出的標(biāo)準(zhǔn)系統(tǒng)顏色之一(系統(tǒng)將對(duì)所選顏色加1)。如果給出了顏色值,它必須是轉(zhuǎn)換成下列的HBRUSH類(lèi)型之一的顏色:
- COLOR_ACTIVEBORDER
- COLOR_ACTIVECAPTION
- COLOR_APPWORKSPACE
- COLOR_BACKGROUND
- COLOR_BTNFACE
- COLOR_BTHSHADOW
- COLOR_BTNTEXT
- COLOR_CAPTIONTEXT
- COLOR_GRAYTEXT
- COLOR_HIGHLIGHT
- COLOR_HIGHLIGHTTEXT
- COLOR_INACTIVEBORDER
- COLOR_INACTIVECAPTION
- COLOR_MENU
- COLOR_MENUTEXT
- COLOR_SCROLLBAR
- COLOR_WINDOW
- COLOR_WINDOWFRAME
- COLOR_WINDOWTEXT
- 當(dāng)hbrBackground字段為NULL時(shí),每當(dāng)需要繪制其用戶區(qū)域時(shí),應(yīng)用程序必須自己來(lái)繪制其背景。應(yīng)用程序可以通過(guò)處理WM_ERASEBKGND 消息或檢查由 BeginPaint 函數(shù)填寫(xiě)的 PAINTSTRUCT 結(jié)構(gòu)的fErase 字段來(lái)確定背景什么時(shí)候需要著色。
lpszMenuName:指向NULL結(jié)束的字符串,該字符串描述菜單的資源名,如同在資源文件里顯示的名字一樣。若使用一個(gè)整數(shù)標(biāo)識(shí)菜單,可以使用MAKEINTRESOURCE宏。如果lpszMenuName為NULL,
那么該窗口類(lèi)的窗口將沒(méi)有默認(rèn)菜單。
lpszClassName:指向NULL結(jié)束的字符串,或者是一個(gè)原型(atom)。若該參數(shù)是一個(gè)原型,它必須是一個(gè)有先前調(diào)用RegisterClass或者 RegisterClassEx函數(shù)產(chǎn)生的類(lèi)原型。類(lèi)原型必須作為lpszClassName的低字,高字必須為0.若lpszClassName是一個(gè)字符串,它描述了窗口類(lèi)名。這個(gè)類(lèi)名可以是由RegisterClass或者RegisterClassEx注冊(cè)的名字,或者是任何預(yù)定義的控件類(lèi)名。
結(jié)構(gòu)信息Header 在winuser.h聲明,包含windows.h
相關(guān)文章
基于C++實(shí)現(xiàn)日期計(jì)算器的詳細(xì)教程
在現(xiàn)代社會(huì)中,計(jì)算器已經(jīng)進(jìn)入了每一個(gè)家庭,人們?cè)谏詈蛯W(xué)習(xí)中經(jīng)常需要使用到計(jì)算器,下面這篇文章主要給大家介紹了關(guān)于基于C++實(shí)現(xiàn)日期計(jì)算器的相關(guān)資料,需要的朋友可以參考下2022-06-06c++字符串char[]數(shù)組分割split問(wèn)題
這篇文章主要介紹了c++字符串char[]數(shù)組分割split問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09