深入解析C++的WNDCLASS结构体及其在Windows中的应用
WNDCLASS是一个由系统支持的结构,用来储存某一类窗口的信息,如ClassStyle,消息处理函数,Icon,Cursor,背景Brush等。也就是说,CreateWindow只是将某个WNDCLASS定义的窗体变成实例。要得到某一窗口的WNDCLASS数据,可以用GetClassLong();
RegisterClass()就是在系统注册某一类型的窗体。也就是将你提供的WNDCLASS数据注册为一个窗口类,在WNDCLASS.lpszClassName中定义该WNDCLASS的标识,无论CreateWindow或CreateWindowEx创建的窗口都必须对应一个WNDCLASS,但一个WNDCLASS可以有多个窗口对象。
有一些系统预定义的窗口类,如:ClassName=_T("BUTTON"or"COMBOBOX"or"EDIT"or"LISTBOX"or"MDICLIENT"or"SCOLLBAR"or"STATIC"),要用这些窗体,直接用CreateWindow创建相应对象就是了。要得到某一窗口的窗口类,可以用GetClassName();
WNDCLASS中的回调函数是窗体的消息处理函数:CALLBACKWinProc(MESSAGEmsg,LPARAMlparam,WPARAMwParam);
窗口类属性定义
结构WNDCLASS包含一个窗口类的全部信息,也是Windows编程中使用的基本数据结构之一,应用程序通过定义一个窗口类确定窗口的属性,定义如下:
typedefstruct_WNDCLASS{ UINTstyle; WNDPROClpfnWndProc; intcbClsExtra; intcbWndExtra; HINSTANCEhInstance; HICONhIcon; HCURSORhCursor; HBRUSHhbrBackground; LPCTSTRlpszMenuName; LPCTSTRlpszClassName; }WNDCLASS,*PWNDCLASS;
举例说明
例子:
longCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);//声明 //WinMain函数是所有Windows应用程序的入口,类似c语言中的main函数其功能是完成//一系列的定义和初始化,并产生消息循环。函数说明: intWINAPIWinMain(HINSTANCEhInstance,//handletocurrentinstance HINSTANCEhPrevInstance,//handletopreviousinstance LPSTRlpCmdLine,//commandline intnCmdShow//showstate ) { //初始化,初始化包括窗口类的定义、注册、创建窗口实例和显示窗口四部分 HWNDhwnd; MSGMsg; WNDCLASSwndclass; charlpszClassName[]="窗口";//窗口类名 charlpszTitle[]="测试窗口";//窗口标题名 //窗口类定义,窗口类定义了窗口的形式与功能,窗口类定义通过给窗口类数据结构WNDCLASS赋值完成 //该数据结构中包含窗口类的各种属性 wndclass.style=0;//窗口类型为缺省类型CS_ClassStyle wndclass.lpfnWndProc=WndProc;//定义窗口处理函数 wndclass.cbClsExtra=0;//窗口类无扩展 wndclass.cbWndExtra=0;//窗口实例无扩展 wndclass.hInstance=hInstance;//当前实例句柄 wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//窗口的最小化图标为缺省图标 wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);//窗口采用箭头光标 wndclass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH));//窗口背景为白色 wndclass.lpszMenuName=NULL;//窗口无菜单 wndclass.lpszClassName=lpszClassName;//窗口类名为“窗口” //以下是窗口类的注册-----------Windows系统本身提供部分预定义的窗口类,程序员也可以自定义窗口类,窗口类必须先注册后使用。 if(!RegisterClass(&wndclass))//如果注册失败发出警告 {MessageBeep(0);returnFALSE;} //创建窗口创建一个窗口的实例由函数CreateWindow()实现 hwnd=CreateWindow(lpszClassName,//窗口类名,创建窗口时一定要基于我们已经注册过的窗口类名,即"窗口"。 lpszTitle,//窗口标题名 WS_OVERLAPPEDWINDOW,//窗口的风格WS_WindowsStyle CW_USEDEFAULT,//窗口左上角坐标值为缺省值CW_CreateWndow CW_USEDEFAULT, CW_USEDEFAULT,//窗口的高和宽为缺省值 CW_USEDEFAULT, NULL,//此窗口无父窗口 NULL,//此窗口无子菜单 hInstance,//创建此窗口的应用程序的当前句柄 NULL//不使用该值 ); //显示窗口 ShowWindow(hwnd,nCmdShow); //绘制用户区 UpdateWindow(hwnd); //消息循环 while(GetMessage(&Msg,NULL,0,0))//GetMessage()函数是从调用线程的消息队列中取出一条消息;对于每一个应用程序窗口线程,操作系统都会为其建立一个消息队列,当我们的窗口有消息时(即所有与这个窗口线程相关的消息),操纵系统会把这个消息放到该线程的消息队列当中,我们的窗口程序就通过这个GetMessage()函数从自己的消息队列中取出一条一条具体的消息并进行响应操作。 { TranslateMessage(&Msg);//对"消息对"的转化,如对键盘的WM_KEYDOWN和WM_KEYUP消息对转化为WM_CHAR消息,并且将转换后的新消息投递到我们的消息队列中去,这个转化操作不会影响原来的消息,只会产生一个新的消息。 DispatchMessage(&Msg);//DispatchMessage()函数是将我们取出的消息传到窗口的回调函数去处理;可以理解为该函数将取出的消息路由给操作系统,然后操作系统去调用我们的窗口回调函数对这个消息进行处理。 } returnMsg.wParam;//消息循环结束即程序结束时将信息返回系统 } //窗口函数,窗口函数定义了应用程序对接收到的不同消息的响应,其中包含了应用程序对各种可能接受到的消息的处理过程,时消息处理分支控制语句的集合 longCALLBACKWndProc(HWNDhwnd, UINTmessage, WPARAMwParam, LPARAMlParam) { switch(message) { caseWM_DESTROY: PostQuitMessage(0); default://缺省时采用系统消息缺省处理函数 returnDefWindowProc(hwnd,message,wParam,lParam); } return(0); }
注:窗口回调函数的函数指针定义typedefLRESULTCALLBACK (*WNDPROC)(HWND,UINT,WPARAM,LPARAM);
WNDPROCOldWndProc; LRESULTCALLBACKNewWndProc(HWNDhwnd,UINTuMsg,WPARAMwParam,LPARAMlParam){ switch(Msg) { ...... } returnCallWindowProc(OldWndProc,g_Wnd,Msg,wParam,lParam); } OldWndProc=(WNDPROC)GetWindowLong(g_Wnd,GWL_WNDPROC); SetWindowLong(hwnd,GWL_WNDPROC,(LPARAM)(WNDPROC)NewWndProc);
通过调用SetWindowLong函数可以修改该窗体类的回调函数。
CallBack函数中的wParam和lParam有什么区别:
WPARAM wParam, 定义成WORD型
LPARAM lParam 定义成LONG型
在Win3.x中,WPARAM是16位的,而LPARAM是32位的,两者有明显的区别。
在Win32API中,WPARAM和LPARAM都是32位,所以没有什么本质的区别。
但是习惯上,我们愿意使用LPARAM传递地址,而WPARAM传递其他参数。
functionMouseHookProc(nCode:Integer;wPar:WPARAM;lPar:LPARAM):lResult;stdcall;
如果我要判断鼠标左键是否按下,用wParam==WM_LBUTTONDOWN判断.
lParam是(tagMOUSEHOOKSTRUCT的指针)PMouseHookStruct类型,主要是获得发送窗口句柄,鼠标坐标,以及其他一些信息。
lParam用的时候需要强制转换,转换成PMouseHookStruct类型.
PMouseHookStruct=^TMouseHookStruct; tagMOUSEHOOKSTRUCT=packedrecord pt:TPoint; hwnd:HWND; wHitTestCode:UINT; dwExtraInfo:DWORD; end; TMouseHookStruct=tagMOUSEHOOKSTRUCT;例如:
functionGetMsgProc(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;
数据结构原型
typedefstruct_WNDCLASS{ UINTstyle; WNDPROClpfnWndProc; intcbClsExtra; intcbWndExtra; HANDLEhInstance; HICONhIcon; HCURSORhCursor; HBRUSHhbrBackground; LPCTSTRlpszMenuName; LPCTSTRlpszClassName; }WNDCLASS;
结构说明
WNDCLASS结构包含了RegisterClass函数注册的类属性
分量简介
style:指定类风格。这些风格可通过按位或操作组合起来。风格如下:
- CS_BYTEALIGNCLIENT:在字节边界上(在x方向上)定位窗口的用户区域的位置
- CS_BYTEALIGNWINDOW:在字节边界上(在x方向上)定位窗口的位置
- CS_CLASSDC:该窗口类的所有窗口实例都共享一个窗口类DC
- CS_DBLCLKS:允许向窗口发送双击鼠标键的消息
- CS_GLOBALCLASS:当调用CreateWindow或CreateWindowEx函数来创建窗口时允许它的hInstance参数和注册窗口类时传递给RegisterClass的hInstance参数不同。如果不指定该风格,则这两个hInstance必须相同。
- CS_HREDRAW:当水平长度改变或移动窗口时,重画整个窗口
- CS_NOCLOSE:禁止系统菜单的关闭选项
- CS_OWNDC:给予每个窗口实例它本身的DC。注意,尽管这样是很方便,但它必须慎重使用,因为每个DC大约要占800个字节的内存。
- CS_PARENTDC:将子窗口的裁剪区域设置到父窗口的DC中去,这样子窗口便可以在父窗口上绘制自身。注意,这是子窗口还是从系统缓存中获取DC,而不是使用父窗口的DC。使用该风格可以提高系统性能。
- CS_SAVEBITS:以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送WM_PAINT消息。该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失。设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存。
- CS_VREDRAW:当垂直长度改变或移动窗口时,重画整个窗口
- lpfnWndProc:指向窗口过程
cbClsExtra:指定紧随在WNDCLASS数据结构后分配的字节数。系统将其初始化为零。
cbWndExtra:指定紧随在窗口实例之后分配的字节数,系统将其初始化为零。如果应用程序正在用WNDCLASS结构注册一个在RC资源描述文件中用CLASS指令创建的对话框时,它必须设置这个字段为DLGWINDOWEXTRA。
hInstance:标识了该窗口类的窗口过程所在的模块实例的句柄,不能为NULL。
hIcon:标识了该窗口类的图标。hIcon字段必须是一个图标的句柄;若hIcon字段为NULL,则无论何时用户把应用程序缩至最小时,应用程序必须画一个图标。
hCursor:标识该窗口类的光标,hCursor必须是一个光标资源的句柄。若hCursor字段为NULL,则无论何时鼠标移到应用程序窗口时,应用程序必须显式设置光标形状。
hbrBackground:标识了该窗口类的背景画笔。hbrBackground字段必须是用于绘制背景的物理刷子的句柄,或者是一个颜色的值。如果给出一个颜色的值,它必须是下面列出的标准系统颜色之一(系统将对所选颜色加1)。如果给出了颜色值,它必须是转换成下列的HBRUSH类型之一的颜色:
- 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
- 当hbrBackground字段为NULL时,每当需要绘制其用户区域时,应用程序必须自己来绘制其背景。应用程序可以通过处理WM_ERASEBKGND消息或检查由BeginPaint函数填写的PAINTSTRUCT结构的fErase字段来确定背景什么时候需要着色。
lpszMenuName:指向NULL结束的字符串,该字符串描述菜单的资源名,如同在资源文件里显示的名字一样。若使用一个整数标识菜单,可以使用MAKEINTRESOURCE宏。如果lpszMenuName为NULL,
那么该窗口类的窗口将没有默认菜单。
lpszClassName:指向NULL结束的字符串,或者是一个原型(atom)。若该参数是一个原型,它必须是一个有先前调用RegisterClass或者RegisterClassEx函数产生的类原型。类原型必须作为lpszClassName的低字,高字必须为0.若lpszClassName是一个字符串,它描述了窗口类名。这个类名可以是由RegisterClass或者RegisterClassEx注册的名字,或者是任何预定义的控件类名。
结构信息Header在winuser.h声明,包含windows.h