Windows 程式設計的基石是「窗口類」。本文從傳統 SDK 的 WNDCLASS/RegisterClass 入手,層層遞進揭示 MFC 如何封裝、自動化並擴展這一核心機制,為後續深入源碼分析鋪路。
窗口類非 C++ 類,而是一個 數據結構 (WNDCLASS/WNDCLASSEX),定義一類窗口共享的屬性:
lpfnWndProc):核心,決定窗口行為。style):如 CS_HREDRAW | CS_VREDRAW (尺寸變化重繪)、CS_DBLCLKS (雙擊支持)。hIcon)、游標 (hCursor)、背景刷 (hbrBackground)、菜單 (lpszMenuName)。hInstance):模組標識。lpszClassName):唯一字符串標識,CreateWindow 依此查找。cbClsExtra (類級)、cbWndExtra (窗口級)。填寫結構後調用 RegisterClass 向系統登記,隨後即可多次呼叫 CreateWindow 創建實例,「一次註冊,多次創建」,極大提升代碼復用與一致性。
// 經典 WinMain 窗口類註冊流程
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
WNDCLASS wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = TEXT("HelloWin");
RegisterClass(&wc); // 註冊
HWND hwnd = CreateWindow(TEXT("HelloWin"), ..., NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 消息循環...
}
程式員手動控制每一步,靈活但繁瑣,且易出錯 (如忘記註冊、類名拼寫錯誤)。
MFC 應用精靈生成的代碼中「看不見」窗口類註冊,實則由框架在底層自動完成。核心在於 五大預定義窗口類 與 延遲註冊機制。
#define AFX_WND_REG 0x0001 // 通用窗口 (CWnd)
#define AFX_WNDCONTROLBAR_REG 0x0002 // 控制欄 (CControlBar)
#define AFX_WNDMDIFRAME_REG 0x0004 // MDI 主框架 (CMDIFrameWnd)
#define AFX_WNDFRAMEORVIEW_REG 0x0008 // 框架/視圖 (CFrameWnd, CView)
#define AFX_WNDOLECONTROL_REG 0x0020 // OLE 控制項 (COleControl)
| 標誌 | 內部符號 | 字符串常量 | 展開後類名 |
|---|---|---|---|
| AFX_WND_REG | _afxWnd | AFX_WNDCLASS("WND") | MFCWindow |
| AFX_WNDCONTROLBAR_REG | _afxWndControlBar | AFX_WNDCLASS("ControlBar") | MFCControlBar |
| AFX_WNDMDIFRAME_REG | _afxWndMDIFrame | AFX_WNDCLASS("MDIFrame") | MFCMDIFrame |
| AFX_WNDFRAMEORVIEW_REG | _afxWndFrameOrView | AFX_WNDCLASS("FrameOrView") | MFCFrameOrView |
| AFX_WNDOLECONTROL_REG | _afxWndOleControl | AFX_WNDCLASS("OleControl") | MFCOleControl |
AFX_WNDCLASS 宏會根據 Unicode/ANSI 構建帶模組標識的唯一類名,防止多模組衝突。
具體註冊行為封裝在全局函數 AfxDeferRegisterClass 中,採用「按需註冊、緩存結果」策略,詳見下篇源碼級分析。
所有可見物件繼承自 CWnd,創建窗口最終調用 CreateEx。CWnd 及其派生類通過重寫 PreCreateWindow 指定所需窗口類:
CWnd → AFX_WND_REG (通用子窗口、對話框控件)CFrameWnd → AFX_WNDFRAMEORVIEW_REG (SDI 框架)CMDIFrameWnd → AFX_WNDMDIFRAME_REG (MDI 框架,帶專屬圖標)CView → AFX_WNDFRAMEORVIEW_REG (視圖)CControlBar → AFX_WNDCONTROLBAR_REG (工具/狀態欄)這種「繼承即配置」設計,讓開發者無感知地獲得正確的窗口類屬性。
CS_DBLCLKS、CS_OWNDC 等特殊風格時,必須在 PreCreateWindow 註冊專屬類。SetClassLong 限制)。從 SDK 的手工 RegisterClass 到 MFC 的自動化延遲註冊,窗口類機制經歷了「手動→封裝→延遲→多態配置」的演進。掌握五大預定義類、類名生成規則、PreCreateWindow 多態分發,是通往 MFC 核心架構師之路的必修課。下篇將深入源碼剖析 AfxDeferRegisterClass 實現細節與自定義類註冊實戰。