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

深入淺出 MFC 核心機制:從 WinMain 到文檔/視圖架構

     編輯:C++ 入門

前言:MFC 是什麼?

MFC(Microsoft Foundation Classes)將 Windows API 封裝為 C++ 類別庫,極大簡化了視窗程式開發。本文通過 VS 向導生成的 SDI(單文檔介面)專案,層層剖析 MFC 程式的啟動、視窗建立、訊息循環與核心架構。

一、 程式入口:尋找隱藏的 WinMain

1. 真實入口:_tWinMain 巨集

在 appmodul.cpp 中發現 _tWinMain,非標準 WinMain。按 F12 追蹤至 tchar.h:

#define _tWinMain WinMain  // Unicode 建置下對應 wWinMain

在 _tWinMain 設斷點並 F5 運行,程式確實停在此處,證實為入口。

2. 全域應用程式物件 theApp 先於 WinMain 建構

  • 類別視圖中 CSDIMFCApp : public CWinAppEx : public CWinApp。
  • SDIMFC.cpp 定義全域物件:CSDIMFCApp theApp;
  • 斷點驗證執行順序:theApp 全域建構 → CSDIMFCApp::CSDIMFCApp() → _tWinMain。

結論:MFC 利用 C++ 全域物件建構機制,在進入 WinMain 前完成應用程式實例初始化。每個 MFC 程式有且僅有一個 CWinApp 派生物件(theApp)。

二、 MFC 如何封裝經典 Win32 流程

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

2. 視窗類註冊:AfxEndDeferRegisterClass → AfxRegisterClass

MFC 延遲註冊視窗類,直到真正需要建立視窗時(CWnd::CreateEx)才通過 AfxRegisterClass 向系統註冊,視窗程式指向 AfxWndProc。

3. 視窗建立:CWnd::CreateEx → CreateWindowEx

  • CFrameWnd::LoadFrame → Create → CreateEx。
  • 最終調用 API CreateWindowEx,lpClassName 為 MFC 註冊的類名(如 AfxFrameOrView42)。

4. 顯示與更新:ShowWindow / UpdateWindow

在 InitInstance 中:m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow();

5. 訊息循環:CWinThread::Run

BOOL CWinThread::Run() {
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        if (!PreTranslateMessage(&msg)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}

MFC 註入 PreTranslateMessage 鉤子,支援工具提示、快捷鍵等預處理。

6. 訊息映射機制:取代 WndProc 巨大 switch

  • 類向導為類別添加訊息處理函數(如 ON_WM_PAINT())。
  • 運行時透過 BEGIN_MESSAGE_MAP 靜態陣列查找對應處理函數,實現「訊息 → 函數」的動態分發。
  • 類似 .NET WinForms 的事件機制(訊息 ≈ 事件)。

三、 文檔/視圖架構

文檔視圖關係圖

  • Document (CDocument):資料模型,負責資料儲存、載入、序列化。非視窗類(繼承 CCmdTarget → CObject)。
  • View (CView):顯示邏輯,負責繪製、使用者互動。子視窗(CWnd 衍生)。
  • Frame (CFrameWnd):主視窗框架,包含選單、工具列、狀態列,父視窗包含 View。

設計哲學:資料與顯示分離(MVC 前身)。多視圖共享單一文檔、分割視窗、列印預覽皆基於此架構自然實現。

四、 總結:MFC 運行流程圖解

  1. 全域 theApp 建構
  2. _tWinMain → AfxWinMain
  3. AfxWinInit 初始化 MFC 狀態
  4. InitApplication(應用層初始化)
  5. InitInstance(建立文檔範本、主框架、視圖)
  6. Run 進入訊息循環
  7. 訊息映射分發至對應處理函數
  8. 程式結束 → AfxWinTerm 清理

MFC 將 Win32 SDK 的繁瑣流程全部封裝,開發者專注於 InitInstance、訊息處理、文檔序列化等業務邏輯。

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