窗口类的类别:有三种——systemClasses、Application Global Classes、Application Local Classes
这三种的不同在于作用域以及何时、如何注册和销毁方面。
SysTemClasses所谓的SystemClasses,是指那些已经由windows预先注册的类——windows标准控件的窗口类就是他们。由于是系统注册了这些类,因此用户无法销毁他们。
当一个进程的线程第一次开始呼叫GDI函数时,系统就会为这个进程注册这些systemClasses。
每个应用程序接收属于自己的那份systemClasses拷贝,所有的16位应用程序在同一个VDM(Virtual Dos machine)是共享systemClasses的。
systemClasses定义内容如下,这部分是可以被用户直接获得使用的:
- Delphi(Pascal) code
Class Description
Button The class for a button.
ComboBox The class for a combo box.
Edit The class for an edit control.
ListBox The class for a list box.
MDIClient The class for an MDI client window.
ScrollBar The class for a scroll bar.
Static The class for a static control.
这部分是给系统用的
- Delphi(Pascal) code
Class Description
ComboLBox The class for the list box contained in a combo box.
DDEMLEvent The class for Dynamic Data Exchange Management Library (DDEML) events.
Message The class for a message-only window.
#32768 The class for a menu.
#32769 The class for the desktop window.
#32770 The class for a dialog box.
#32771 The class for the task switch window.
#32772 The class for icon titles.
Application Global Classes由Exe或者Dll注册,可以被其它进程模块访问到。比如,其它进程一旦加载了这个dll(注册了这个窗口类),那么该进程就可以创建这个窗口类的实例了。
要创建可以被每个进程使用的窗口类,就需要把它放在Dll中,并使得可自动加载在每个进程中——可以把Dll的文件名放到注册表HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows
此路径下的AppInit_DLLs 键值 。
这样,在进程启动时,进入入口函数以前,系统就会为进程加载指定的dll。所以在dll中,窗口类的注册必须在初始化dll过程时进行,而且必须指定CS_GLOBALCLASS风格。
Application Local Classes与Global Classes相反,他只适合在本进程里面使用。其它进程无法获得该窗口类的任何信息,当然也找不到它。
一个窗口类只会注册一次,即使你调用了很多次RegisterClass。当注册该窗口类的模块终止了,系统会销毁这个Local Class
系统是如何定位一个窗口类呢? 系统会为每种类型的窗口类(即以上说明的三种窗口类)分别维护一个结构列表。当应用程序调用CreateWindow或CreateWindowEx来创建一个窗口时,系统会根据指定的窗口类,按照以下过程来定位这个类:
1、 根据指定的窗口类名和进程(或模块)的实例句柄(因为其它模块,也会以相同的窗口类名注册,所以会以模块的实例句柄作区分),查找Application Local Classes;
2、 若没有在1步骤中找到,则查找Application Global Classes;
3、 若没有在2步骤中找到,则查找System Classes;
所有由应用程序创建的窗口,包括因应用程序的行为使系统创建的窗口,都是采用这个过程定位的。
注册窗口类 窗口类定义了窗口的特性,比如style、Icon、Cursor、Menu和window procedure。注册窗口类,首先要做的是填充WNDCLASSEX 结构,然后把这个结构传给RegisterClassEx函数。
若要把窗口类注册为全局的(application Global Classes),则需要设定CS_GLOBALCLASS。
RegisterClassEx也区分是否为Unicode版本的函数。如RegisterClassExA,表示支持单字节字符集的Ansi版本 ,应用程序就要求系统传递消息(messages)的文本参数,要使用ANSI字符集;若是RegisterClassExW,则系统会被要求以unicode字符集传递。
可以用IsUnicodeWindow判断一个窗口所要求采用的字符集。
那些注册窗口类的Exe或Dll,本身为这些窗口类的拥有者(Owner of the class)。系统依据WNDCLASSEX结构的成员hInstance,判断此窗口类的拥有关系。如,对DLL来说,hInstance为DLL的handle。
拥有窗口类的(Owner of the class)DLL若被卸载了,但窗口类本身并不会被销毁。因此,如果system调用了此窗口类的窗口过程,则会出现地址错误,因为dll中的那个窗口过程已经不在内存中了。所以DLL注册的窗口类,必须在进程销毁前,销毁掉(unregisterCLass)窗口类。
窗口类的成员- C/C++ code
typedef struct {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;
这些成员定义了窗口的默认行为。应用程序注册一个类,先通过对WNDCLASSEX结构赋值,然后传给CreateWindowEx。GetClassInfoEx和GetClassInfo可以根据给定的窗口类,取得相关信息。SetClassLong可以改变局部窗口类(Application Local Class)或全局窗口类(Application Global Class)的成员内容。
虽然一个完整的窗口类由很多成员组成,但是系统仅要求应用程序提供class Name、window-procedure-address、instance handle。但是必须要初始化WNDCLASSEx结构其它未使用的成员为0或NULL。
下面挑出一些需要特别说明的成员:
Class Name 如一个唯一的ID,标识自己。可以通过设置WNDCLASSEX结构成员lpszCLASSNAME——指向存放0结尾字符串的地址,来设置CLASSNAME。由于窗口类是进程指定的,所以在同一个进程内,窗口类必须是唯一的。同时,由于CLASSName占用的是系统原子表(system’s ATOM TABLE)空间,所以尽可能要短。
GetClassName可以获取指定的窗口的窗口类名。
Class Cursor 用于定义光标在窗口的客户区域(Client area)的形状。当光标进入客户区域时,系统会自动将光标改为class Cursor所指定的。我们可以通过LoadCursor加载系统预定义的光标,再将返回的句柄赋给hCursor。
也可以从应用程序的资源文件里,用LoadCursor加载自定义的光标。
系统不要求一定要给这个成员赋值。当应用程序把这个成员值设为null时,那么系统会认为:应用程序自己会在每次光标移动时自己设置光标的形状。
我们也可以通过SetCursor设定一个窗口的光标形状。
Class ICON 用于设定应用程序的图标。应用程序有两种图标:一个大的和一个小的。当我们使用ALT+TAB时,会出现任务切换窗口(TASK-Switch WINDOW),上面显示的是应用程序的大图标,也出现在Explorer和开始菜单中以大图标视图查看。小图标,如出现在标题栏或explorer和开始菜单的小图标视图查看时。
要设置大图标,则给hIcon;小图标,则是hIconSM。图标的维度大小,要遵循系统约定。可以通过GetSystemMetrics取得维度大小。对于大图标,传SM_CXICON和SM_CYICON两个参数;对于小图标,传SM_CXSMIcon和SM_CYSMIcon。
若这两个成员都没有设定,那么系统会采用默认的应用程序图标作为大、小图标。若只给了大图标,系统会依据大图标,再创建一个小图标;若只给了小图标,系统会采用默认的程序图标作为大图标。
相关的操作消息: WM_SetIcon、WM_GetIcon
Class Background Brush 背景刷子(brush),用于后续窗口的绘画。系统会用这里指定的刷子,在窗口的客户区域(Client Area),以指定的纯色(solid color)或图案绘画。因此,系统会清除之前属于这个窗口区域的所有图像。系统会通过发送消息WM_ERASEBKGND通知窗口,以告知窗口的背景是否需要重画。
我们可以创建一个新的刷子,并把返回的句柄赋给它,也可以直接给它赋 系统标准的颜色值(参考GetSysColorBrush、SetSysColors)。
Class StylesCS_BYTEALIGNCLIENT Aligns the window's client area on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.
CS_BYTEALIGNWINDOW Aligns the window on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.
CS_CLASSDC Allocates one device context to be shared by all windows in the class. Because window classes are process specific, it is possible for multiple threads of an application to create a window of the same class. It is also possible for the threads to attempt to use the device context simultaneously. When this happens, the system allows only one thread to successfully finish its drawing operation.
CS_DBLCLKS Sends a double-click message to the window procedure when the user double-clicks the mouse while the cursor is within a window belonging to the class.
CS_DROPSHADOW Windows XP: Enables the drop shadow effect on a window. The effect is turned on and off through SPI_SETDROPSHADOW. Typically, this is enabled for small, short-lived windows such as menus to emphasize their Z order relationship to other windows.
CS_GLOBALCLASS Specifies that the window class is an application global class. For more information, see Application Global Classes.
CS_HREDRAW Redraws the entire window if a movement or size adjustment changes the width of the client area.
CS_NOCLOSE Disables Close on the window menu.
CS_OWNDC Allocates a unique device context for each window in the class.
CS_PARENTDC Sets the clipping rectangle of the child window to that of the parent window so that the child can draw on the parent. A window with the CS_PARENTDC style bit receives a regular device context from the system's cache of device contexts. It does not give the child the parent's device context or device context settings. Specifying CS_PARENTDC enhances an application's performance.
CS_SAVEBITS Saves, as a bitmap, the portion of the screen image obscured by a window of this class. When the window is removed, the system uses the saved bitmap to restore the screen image, including other windows that were obscured. Therefore, the system does not send WM_PAINT messages to windows that were obscured if the memory used by the bitmap has not been discarded and if other screen actions have not invalidated the stored image.
This style is useful for small windows (for example, menus or dialog boxes) that are displayed briefly and then removed before other screen activity takes place. This style increases the time required to display the window, because the system must first allocate memory to store the bitmap.
CS_VREDRAW Redraws the entire window if a movement or size adjustment changes the height of the client area.