MFC 將 Win32 API 封裝為 C++ 類別庫,但其啟動流程常被開發者忽略。本文從 C 執行期庫 (CRT) 進入點 WinMain 開始,逐層剖析 MFC 如何透過 AfxWinMain、AfxWinInit、CWinApp::InitInstance、CWinThread::Run 啟動完整訊息迴路,並說明 Unicode/ANSI 入口點的自動切換機制。
在 TCHAR.H 中定義:
#ifdef _UNICODE
#define _tWinMain wWinMain
#else
#define _tWinMain WinMain
#endif
CRT 依專案字元集設定呼叫 wWinMain (Unicode) 或 WinMain (ANSI)。MFC 在 APPMODUL.CPP 定義:
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow) {
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
因此無論 Unicode 或 ANSI,MFC 統一進入 AfxWinMain。
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow) {
ASSERT(hPrevInstance == NULL); // Win32 忽略 hPrevInstance
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// 1. MFC 內部初始化:載入資源、建立 GDI 物件表等
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// 2. 應用程式層級初始化 (較少用)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// 3. 執行緒/視窗初始化:建立主視窗、載入框架
if (!pThread->InitInstance()) {
if (pThread->m_pMainWnd != NULL) {
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
// 4. 進入訊息迴路
nReturnCode = pThread->Run();
InitFailure:
#ifdef _DEBUG
// 檢查臨時對應表鎖定計數
if (AfxGetModuleThreadState()->m_nTempMapLock != 0) { ... }
AfxLockTempMaps(); AfxUnlockTempMaps(-1);
#endif
AfxWinTerm(); // MFC 終結清理
return nReturnCode;
}
| 函式 | 所屬類別 | 用途 | 常見覆寫內容 |
|---|---|---|---|
| InitApplication | CWinApp | 應用程式層級一次性初始化 (DDE、文件範本註冊) | 註冊專用文件範本 |
| InitInstance | CWinThread / CWinApp | 建立主視窗、處理命令列、載入設定 | 建立 Document Template、主視窗、啟動 Splash |
| Run | CWinThread | 標準訊息迴路 (GetMessage/TranslateMessage/DispatchMessage) | 閒置處理 OnIdle、多執行緒訊息泵 |
| ExitInstance | CWinThread | 清理資源、儲存設定 | 寫入登錄、關閉資料庫連線 |
CWinApp 繼承 CWinThread,主執行緒即 UI 執行緒。CWinThread (UI 或 Worker),AfxBeginThread 建立,各擁有獨立訊息迴路 (Run)。AFX_IDS_APP_TITLE 等標識字串。Run 不被呼叫,程式立即退出,常見於主視窗建立失敗。MFC 啟動鏈路:CRT _tWinMain → AfxWinMain → AfxWinInit → CWinApp::InitApplication → CWinThread::InitInstance → CWinThread::Run (訊息迴路) → ExitInstance → AfxWinTerm。掌握此流程有助於理解 MFC 內部運作、自訂啟動邏輯、排查啟動失敗問題。