首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

MFC 應用程式啟動流程深度解析:從 WinMain 到 AfxWinMain 的完整鏈路

     編輯:關於VC++

MFC 將 Win32 API 封裝為 C++ 類別庫,但其啟動流程常被開發者忽略。本文從 C 執行期庫 (CRT) 進入點 WinMain 開始,逐層剖析 MFC 如何透過 AfxWinMain、AfxWinInit、CWinApp::InitInstance、CWinThread::Run 啟動完整訊息迴路,並說明 Unicode/ANSI 入口點的自動切換機制。

一、CRT 入口點與 Unicode 切換

在 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。

二、AfxWinMain 核心流程 (WINMAIN.CPP)

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;
}

三、關鍵虛擬函式與擴充點

函式所屬類別用途常見覆寫內容
InitApplicationCWinApp應用程式層級一次性初始化 (DDE、文件範本註冊)註冊專用文件範本
InitInstanceCWinThread / CWinApp建立主視窗、處理命令列、載入設定建立 Document Template、主視窗、啟動 Splash
RunCWinThread標準訊息迴路 (GetMessage/TranslateMessage/DispatchMessage)閒置處理 OnIdle、多執行緒訊息泵
ExitInstanceCWinThread清理資源、儲存設定寫入登錄、關閉資料庫連線

四、單執行緒 vs 多執行緒應用程式

  • 單執行緒 (預設):CWinApp 繼承 CWinThread,主執行緒即 UI 執行緒。
  • 多執行緒:衍生 CWinThread (UI 或 Worker),AfxBeginThread 建立,各擁有獨立訊息迴路 (Run)。

五、除錯與常見問題

  1. 斷點無法命中 WinMain:專案屬性 → Linker → System → Entry Point 應為空白 (使用 CRT 預設)。
  2. AfxWinInit 失敗:檢查資源檔 (.rc) 是否正確編譯、是否遺漏 AFX_IDS_APP_TITLE 等標識字串。
  3. InitInstance 返回 FALSE:導致 Run 不被呼叫,程式立即退出,常見於主視窗建立失敗。

六、總結

MFC 啟動鏈路:CRT _tWinMain → AfxWinMain → AfxWinInit → CWinApp::InitApplication → CWinThread::InitInstance → CWinThread::Run (訊息迴路) → ExitInstance → AfxWinTerm。掌握此流程有助於理解 MFC 內部運作、自訂啟動邏輯、排查啟動失敗問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved