TN001:窗口类注册
此说明介绍了注册 Microsoft Windows 所需的特殊 WNDCLASS 的 MFC 例程。 讨论了 MFC 和 Windows 使用的特定 WNDCLASS
属性。
问题
CWnd 对象的属性(如 Windows 中的 HWND
句柄)存储在两个位置:窗口对象和 WNDCLASS
。 WNDCLASS
的名称传递给常规窗口创建函数,例如 lpszClassName 参数中的 CWnd::Create 和 CFrameWnd::Create。
此 WNDCLASS
必须通过以下四种方法之一进行注册:
隐式使用 MFC 提供的
WNDCLASS
。隐式创建 Windows 控件(或其他一些控件)的子类。
显式调用 MFC AfxRegisterWndClass 或 AfxRegisterClass。
显式调用 Windows 例程 RegisterClass。
WNDCLASS 字段
WNDCLASS
结构由描述窗口类的各种字段组成。 下表显示了这些字段,并指定如何在 MFC 应用程序中使用它们:
字段 | 说明 |
---|---|
lpfnWndProc | 窗口进程必须是 AfxWndProc |
cbClsExtra | 未使用(应为零) |
cbWndExtra | 未使用(应为零) |
hInstance | 使用 AfxGetInstanceHandle 自动填充 |
hIcon | 框架窗口的图标,请参阅下文 |
hCursor | 鼠标位于窗口上方时的光标,请参阅下文 |
hbrBackground | 背景色,请参阅下文 |
lpszMenuName | 未使用(应为 NULL) |
lpszClassName | 类名,请参阅下文 |
提供的 WNDCLASS
早期版本的 MFC(MFC 4.0 之前)提供了多个预定义的窗口类。 默认情况下,不再提供这些窗口类。 应用程序应使用带有相应参数的 AfxRegisterWndClass
。
如果应用程序提供具有指定资源 ID 的资源(例如,AFX_IDI_STD_FRAME),MFC 将使用该资源。 否则,它将使用默认资源。 对于图标,将使用标准应用程序图标,对于游标,将使用标准箭头光标。
两个图标支持具有单文档类型的 MDI 应用程序:一个图标用于主应用程序,另一个图标用于图标文档/MDIChild 窗口。 对于具有不同图标的多文档类型,必须注册其他 WNDCLASS
或使用 CFrameWnd::LoadFrame 函数。
CFrameWnd::LoadFrame
将使用指定为第一个参数和以下标准属性的图标 ID 注册 WNDCLASS
:
类样式:
CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
图标 AFX_IDI_STD_FRAME
箭头光标
COLOR_WINDOW 背景色
由于 MDICLIENT 窗口完全覆盖了 CMDIFrameWnd
的工作区,因此不使用 CMDIFrameWnd 的背景色和光标的值。 Microsoft 不建议创建 MDICLIENT 窗口的子类,因此尽可能使用标准颜色和光标类型。
创建控件的子类和超类
例如,如果创建 Windows 控件(例如,CButton)的子类或超类,则类会自动获取该控件的 Windows 实现中提供的 WNDCLASS
属性。
AfxRegisterWndClass 函数
MFC 提供用于注册窗口类的帮助程序函数。 假设有一组属性(窗口类样式、光标、背景画笔和图标),则将生成合成名称,并注册生成的窗口类。 例如,
const char* AfxRegisterWndClass(UINT nClassStyle,
HCURSOR hCursor,
HBRUSH hbrBackground,
HICON hIcon);
此函数返回生成的已注册窗口类名的临时字符串。 有关此函数的详细信息,请参阅 AfxRegisterWndClass。
返回的字符串是指向静态字符串缓冲区的临时指针。 它在下次调用 AfxRegisterWndClass
之前有效。 如果要保留此字符串,请将其存储在 CString 变量中,如以下示例所示:
CString strWndClass = AfxRegisterWndClass(CS_DBLCLK, ...);
...
CWnd* pWnd = new CWnd;
pWnd->Create(strWndClass, ...);
...
如果窗口类无法注册(由于参数错误或 Windows 内存不足),则 AfxRegisterWndClass
会引发 CResourceException。
RegisterClass 和 AfxRegisterClass 函数
如果要执行比 AfxRegisterWndClass
提供的操作更复杂的操作,则可以调用 Windows API RegisterClass
或 MFC 函数 AfxRegisterClass
。 CWnd
、CFrameWnd 和 CMDIChildWndCreate
函数将窗口类的 lpszClassName 字符串名称用作第一个参数。 可以使用任何已注册的窗口类名,而不管用于注册它的方法。
请务必在 Win32 上的 DLL 中使用 AfxRegisterClass
(或 AfxRegisterWndClass
)。 Win32 不会自动取消注册 DLL 注册的类,因此必须在 DLL 终止时显式取消注册类。 通过使用 AfxRegisterClass
(而不是 RegisterClass
),系统会自动为你处理。 AfxRegisterClass
维护 DLL 注册的唯一类的列表,并在 DLL 终止时自动取消注册它们。 在 DLL 中使用 RegisterClass
时,必须确保在 DLL 终止时取消注册所有类(在 DllMain 函数中)。 当另一个客户端应用程序尝试使用 DLL 时,执行此操作失败可能导致 RegisterClass
意外失败。