MFC(Microsoft Foundation Classes)將 Windows API 封裝為 C++ 類別庫,極大簡化了視窗程式開發。本文通過 VS 向導生成的 SDI(單文檔介面)專案,層層剖析 MFC 程式的啟動、視窗建立、訊息循環與核心架構。
WinMain_tWinMain 巨集在 appmodul.cpp 中發現 _tWinMain,非標準 WinMain。按 F12 追蹤至 tchar.h:
#define _tWinMain WinMain // Unicode 建置下對應 wWinMain
在 _tWinMain 設斷點並 F5 運行,程式確實停在此處,證實為入口。
theApp 先於 WinMain 建構CSDIMFCApp : public CWinAppEx : public CWinApp。SDIMFC.cpp 定義全域物件:CSDIMFCApp theApp;theApp 全域建構 → CSDIMFCApp::CSDIMFCApp() → _tWinMain。結論:MFC 利用 C++ 全域物件建構機制,在進入 WinMain 前完成應用程式實例初始化。每個 MFC 程式有且僅有一個 CWinApp 派生物件(theApp)。
AfxWinMain 核心流程int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow) {
// 1. 取得執行緒與應用程式指標
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// 2. AFX 內部初始化
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) return -1;
// 3. 初始化應用程式(虛函數,派生類覆寫)
if (!pApp->InitApplication()) return -1;
// 4. 初始化實例(建立主視窗等,虛函數)
if (!pThread->InitInstance()) return -1;
// 5. 進入訊息循環
int nReturnCode = pThread->Run();
// 6. 清理
AfxWinTerm();
return nReturnCode;
}
AfxEndDeferRegisterClass → AfxRegisterClassMFC 延遲註冊視窗類,直到真正需要建立視窗時(CWnd::CreateEx)才通過 AfxRegisterClass 向系統註冊,視窗程式指向 AfxWndProc。
CWnd::CreateEx → CreateWindowExCFrameWnd::LoadFrame → Create → CreateEx。CreateWindowEx,lpClassName 為 MFC 註冊的類名(如 AfxFrameOrView42)。ShowWindow / UpdateWindow在 InitInstance 中:m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow();
CWinThread::RunBOOL CWinThread::Run() {
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (!PreTranslateMessage(&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
MFC 註入 PreTranslateMessage 鉤子,支援工具提示、快捷鍵等預處理。
WndProc 巨大 switchON_WM_PAINT())。BEGIN_MESSAGE_MAP 靜態陣列查找對應處理函數,實現「訊息 → 函數」的動態分發。
CCmdTarget → CObject)。CWnd 衍生)。設計哲學:資料與顯示分離(MVC 前身)。多視圖共享單一文檔、分割視窗、列印預覽皆基於此架構自然實現。
theApp 建構_tWinMain → AfxWinMainAfxWinInit 初始化 MFC 狀態InitApplication(應用層初始化)InitInstance(建立文檔範本、主框架、視圖)Run 進入訊息循環AfxWinTerm 清理MFC 將 Win32 SDK 的繁瑣流程全部封裝,開發者專注於 InitInstance、訊息處理、文檔序列化等業務邏輯。