TN001: 窗口类注册
translated by zhkza99c
这个笔记描述了MFC如何在Microsoft Windows注册一个特定的WNDCLASSes的规则。并且讨论了如何在MFC和WINDOWS里面定制WNDCLASS 的属性。
问题
CWnd对象的属性和Windows里面的HWND是类似的,都存在两个地方:窗口对象和WNDCLASS中。WNDCLASS是与C++类不同的一个类。WNDCLASS的名字是通过普通窗口构造函数的lpszClassName参数传入的,例如CWnd::Create 函数和 CFrameWnd::Create函数
WNDCLASS必须通过一下四种之一的方式来注册:
- 隐式的通过mfc提供的WNDCLASSes
- 隐式的通过子类化窗口的控件(或者其他一些控件)
- 显式的通过MFC的AfxRegisterWndClass 或者 AfxRegisterClass函数
- 显式的通过调用Windows的RegisterClass函数。
WNDCLASSes 和 MFC
WNDCLASS结构是由各种各样的区域值来描述一个窗口类的,下面是这些域和他们在MFC程序里的使用方法
Style |
窗口的风格: 看下面 |
LpfnWndProc |
窗口函数, 必须是AfxWndProc |
CbClsExtra |
不被使用(应该置0) |
CbWndExtra |
不被使用 (应该是0) |
HInstance |
自动由AfxGetInstanceHandle填充 |
HIcon |
框架窗口的图标,具体下详 |
HCursor |
当鼠标进入窗口内时的样式,下详 |
HbrBackground |
背景颜色,下详 |
LpszMenuName |
不被使用 (应该置 NULL) |
LpszClassName |
类的名字,下详 |
所提供的 WNDCLASSes
在之前的MFC版本中(MFC4.0之前),提供了一些预定义的窗口类,由于多版本引发的技术问题,这些窗口类不再默认提供(多版本的MFC加载在同一个地址空间)如涉及到的一个实际情况就是MFC应用程序和OLE控件都使用到MFC的DLL。
以下的参考是用来帮助解决之前版本的WNDCLASS的移植问题。应用程序要通过AfxRegisterWndClass(通过适当的参数)来代替这些窗口类。
下面展示了这些类和他们的属性:
- "AfxWnd"被所有由CWnd::Create创建的子窗口使用
类的样式:CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW
无图标
箭头鼠标
没有背景颜色
- "AfxFrameOrView" 用来定制窗口的框架和视图(包括被孤立的CFrameWnds 和 CMDIChildWnds)
- 类的样式:CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
- 图标为AFX_IDI_STD_FRAME
- 箭头鼠标
- 背景颜色为COLOR_WINDOW
- "AfxMDIFrame" 使用CMDIFrameWnd::Create. 来创建MDI框架的窗口(即父窗口)
-
- 类的样式 : CS_DBLCLKS [ 改变大小时减小闪烁]
- 图标为AFX_IDI_STD_MDIFRAME
- 箭头鼠标
- 无背景颜色
- "AfxControlBar" 被用来定义标准的控件栏
- 类的样式 : 0 [ 改变大小时减少闪烁并且没有双击]
- 无图标
- 箭头鼠标
- 灰背景色 (COLOR_BTNFACE)
如果应用程序提供了一个由特殊的资源ID表示的资源(例如,AFX_IDI_STD_FRAME)ID,MFC将会使用这些资源,其他情况下会使用默认资源。例如图标,标准的应用程序图标将被使用,或者鼠标,标准的箭头鼠标将被使用。
就单文档类型提供了两个图标来支持MDI应用程序(一个图标用来给主程序,另一个图标用来标示文档/MDIChild窗口)。例如文档类型又多个图标,你必须在WNDCLASSes注册图标或者使用CFrameWnd::LoadFrame 函数。
CFrameWnd::LoadFrame 会通过标准的"AfxFrameOrView"自动注册一个WNDCLASS,但是图标的ID你必须通过LoadFrame第一个参数来标示。
当MDIFrameWnd 的客户区域被"MDICLIENT"窗口完全覆盖时,MDIFrameWnd里背景颜色和鼠标类型的值不被使用。微软不鼓励子类化"MDICLIENT"窗口,所以尽可能的使用标准的颜色和鼠标类型。
子类化控件
如果你子类化或者超类化窗口控件(例如,CButton),你的类的WNDCLASS的属性会自动由你所继承的窗口所提供。
AfxRegisterWndClass函数
MFC提供了一个帮助规则来注册一个窗口类,只要给出一系列的属性(窗口类风格,鼠标,背景刷和图标)就会生成一个窗口的名字并且注册这个窗口。
例如,
const char* AfxRegisterWndClass(UINT nClassStyle,HCURSOR hCursor,
HBRUSH hbrBackground,HICON hIcon);
这个函数返回一个临时的字符串来生成注册的窗口类的名字,请看Class Library Reference 来获得更多的细节。
这个返回的字符串是一个指向静态字符串缓冲区的临时指针,它在下一个AfxRegisterWndClass调用之前都会有效。如果你想要保存这个字符串,将它存储在一个CString变量中。
例如,
CString strWndClass = AfxRegisterWndClass(CS_DBLCLK, ...);
...
CWnd* pWnd = new CWnd;
pWnd->Create(strWndClass, ...);
...
如果窗口类注册失败的时候AfxRegisterWndClass会抛出一个CResourceException 异常(不论是给出了错误的参数还是Windows的内存不足)
RegisterClass函数和AfxRegisterClass函数
如果你想要做一些AfxRegisterWndClass所没有提供的更多的事情,你可以调用Windows API RegisterClass 或者 MFC的函数 AfxRegisterClass. CWnd, CFrameWnd 和 CMDIChildWnd Create函数都使用lpszClassName作为第一个参数来确定窗口类的名字。任何窗口类的名字都可以被使用,不论它是怎么被注册的。
在DLL和Win32中使用AfxRegisterClass (或者AfxRegisterWndClass)是非常重要的。Win32并不自动反注册由Dll注册的类,因此必须在DLL被中止的时候显式的做这些工作。
通过使用AfxRegisterClass来代替RegisterClass可以自动为你做到这些,AfxRegisterClass包括了一个列表,这个列表是由你的DLL注册的独一无二的并且可以在DLL中止的时候进行自动反注册。
当在DLL中使用RegisterClass的时候,你必须确定在DLL终止的时候所有的类都要进行反注册(在你的DllMain函数中)。没有做这些可能会造成在你的DLL被其他客户应用程序所使用时,RegisterClass抛出失败的异常,
posted on 2008-03-12 16:15
田园的拾荒者 阅读(1462)
评论(1) 编辑 收藏 引用 所属分类:
翻译