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

MFC 核心機制深度解析(五之一):對象創建關系、虛擬函數接口與 SDI 啟動流程全景圖

     編輯:關於VC++

MFC 文檔/視圖架構的靈魂在於「對象創建與協作」。本文系統梳理 應用程序、文檔模板、文檔、框架窗口、視圖 五大核心對象的創建關系、交互接口、關鍵數據成員,並以前 4 章機制(動態創建、消息映射、命令路由)為基礎,完整還原 SDI 應用程序從 WinMain → InitInstance → Run 消息循環 → 對象創建 → 窗口顯示的啟動全流程,為深度掌握 MFC 框架打下堅實基礎。

一、 核心對象創建與交互關系圖譜

1. 創建責任鏈

創建者被創建對象關鍵函數
應用程序對象 (CWinApp)文檔模板 (CDocTemplate)AddDocTemplate
文檔模板文檔 (CDocument)CreateNewDocument / OpenDocumentFile
文檔模板框架窗口 (CFrameWnd/CMDIChildWnd)CreateNewFrame → LoadFrame
框架窗口視圖 (CView)OnCreateClient → CreateView

2. 運行時交互導航表(獲取關聯對象)

當前對象目標對象成員函數
CDocument視圖列表GetFirstViewPosition / GetNextView
CDocument文檔模板GetDocTemplate
CView文檔GetDocument
CView框架窗口GetParentFrame
CFrameWnd/CMDIChildWnd活動視圖GetActiveView
CMDIFrameWnd活動子框架MDIGetActive

3. 通知協作模式

  • 視圖數據變更 → GetDocument()->UpdateAllViews(pSender, lHint, pHint) → 所有關聯視圖 OnUpdate。
  • 框架窗口設置活動視圖 → SetActiveView(pView, bNotify) → 視圖 OnActivateView。

二、 MFC 編程兩大擴展接口

1. 虛擬函數接口表(部分核心類)

類關鍵虛擬函數覆蓋目的
CWinThreadInitInstance, ExitInstance, Run, OnIdle, PreTranslateMessage線程初始化/退出/消息循環/空閒處理/消息預處理
CWinAppInitInstance, ExitInstance, OnFileNew/Open, SaveModifiedDocument, DoMessageBox**必覆蓋** 應用程序初始化;文件命令/保存提示/訊息框定制
CFrameWndOnCreateClient, ActivateFrame, LoadFrame, GetMessageBar視圖創建策略、窗口激活方式、框架加載、狀態欄訪問
CMDIFrameWndCreateClient, GetWindowMenuPopupMDI Client 窗口創建、Window 菜單彈出項獲取
CViewOnDraw, OnInitialUpdate, OnUpdate, OnPrepareDC, OnPrint, OnActivateView/Frame**核心繪製**、初始化、增量更新、打印、激活響應
CDocumentOnNewDocument, OnOpenDocument, OnSaveDocument, DeleteContents, Serialize文檔生命周期、序列化、內容清理
CDocTemplateCreateNewDocument, CreateNewFrame, InitialUpdateFrame, OpenDocumentFile, MatchDocType文檔/框架/視圖創建工廠、打開邏輯、類型匹配度

註:覆蓋虛擬函數通常需調用基類實現以保持框架默認行為。

2. 標準命令消息映射表(部分)

MFC 為常用菜單命令提供默認實現,路由至特定類:

  • ID_FILE_NEW/OPEN → CWinApp::OnFileNew/Open
  • ID_FILE_SAVE/SAVE_AS → CDocument::OnFileSave/SaveAs
  • ID_FILE_PRINT/PRINT_PREVIEW → CView::OnFilePrint/PrintPreview
  • ID_APP_EXIT → CWinApp::OnAppExit
  • ID_VIEW_TOOLBAR/STATUS_BAR → CFrameWnd 處理顯示/隱藏
  • ID_WINDOW_NEW/CASCADE/TILE → CMDIFrameWnd 管理 MDI 子窗口

程序員可通過類向導映射至派生類覆蓋,建議遵循默認路由類。

三、 應用程序啟動入口:WinMain 與 CWinThread::Run

1. WinMain 簡化流程

int AFXAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPTSTR lpCmdLine, int nCmdShow) {
    // 1. 全局應用程序對象已構造
    // 2. AFX 模塊狀態初始化
    // 3. 調用 pThread->InitInstance() -- 必須覆蓋,返回 FALSE 則退出
    // 4. 調用 pThread->Run() -- 進入消息循環
    // 5. 調用 pThread->ExitInstance() -- 清理
    // 6. 返回退出碼
}

2. CWinThread::Run 消息循環核心

BOOL CWinThread::Run() {
    while (PumpMessage()); // 循環獲取/分發消息
    return TRUE;
}

BOOL CWinThread::PumpMessage() {
    MSG msg;
    if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        if (msg.message == WM_QUIT) return FALSE;
        PreTranslateMessage(&msg); // 虛擬函數,預處理(加速鍵、工具提示)
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    } else {
        // 無消息時進入空閒處理
        long lIdle = 0;
        while (OnIdle(lIdle++)) ; // 虛擬函數,更新 UI 狀態等
    }
    return TRUE;
}

關鍵點:PreTranslateMessage 由 WalkPreTranslateTree 向上遞歸調用目標窗口及其祖先的預處理;OnIdle 返回 TRUE 表示繼續空閒處理,FALSE 結束本輪空閒。

四、 SDI 應用程序對象創建完整流程

1. InitInstance 標準三部曲

BOOL CMyApp::InitInstance() {
    // ① 創建並註冊單文檔模板
    CSingleDocTemplate* pTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME, RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CMyView));
    AddDocTemplate(pTemplate);

    // ② 解析命令行並執行 Shell 命令(新建/打開/打印)
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo); // 填充 m_nShellCommand (FileNew/FileOpen...), m_strFileName
    if (!ProcessShellCommand(cmdInfo)) return FALSE; // 核心創建入口

    // ③ 返回 TRUE,WinMain 將調用 Run 進入消息循環
    return TRUE;
}

2. 命令行分析與分發

  • CCommandLineInfo 封裝解析結果:m_nShellCommand (FileNew/FileOpen/FilePrint...)、m_strFileName。
  • 默認構造函數設置 m_nShellCommand = FileNew,無參數啟動即新建文檔。
  • ProcessShellCommand 根據命令類型調用:
    • FileNew → OnFileNew → 文檔模板 OpenDocumentFile(NULL)
    • FileOpen → OnFileOpen → 彈出對話框獲取文件名 → 應用程序 OpenDocumentFile → 文檔模板 OpenDocumentFile

3. 文檔模板 OpenDocumentFile 核心流程 (CSingleDocTemplate)

流程圖解 (圖 5-8):

  1. 若已有文檔打開 → 提示保存 → 關閉舊文檔 (OnCloseDocument)。
  2. 創建新文檔對象 (CreateNewDocument → CRuntimeClass::CreateObject → CDocument 構造)。
  3. 創建框架窗口 (CreateNewFrame → CFrameWnd::LoadFrame → HWND 創建)。
  4. 框架窗口 OnCreate → OnCreateClient → CreateView 創建視圖對象及 HWND。
  5. 初始化文檔:NULL 文件名調用 OnNewDocument(初始化數據結構);有文件名調用 OnOpenDocument → CArchive 序列化讀取。
  6. 調用 InitialUpdateFrame(pDoc, TRUE) → 視圖 OnInitialUpdate、窗口激活顯示、標題更新。

4. 關鍵虛擬函數調用鏈總結

命令行分析 → CWinApp::OnFileNew
    → CDocTemplate::OpenDocumentFile(NULL)
        → CreateNewDocument() → CDocument::OnNewDocument()
        → CreateNewFrame() → CFrameWnd::LoadFrame()
            → CFrameWnd::Create() → ::CreateWindowEx()
            → WM_CREATE → CFrameWnd::OnCreate()
                → OnCreateHelper() → OnCreateClient()
                    → CreateView() → CView::Create() → HWND 視圖窗口
        → InitialUpdateFrame() → CView::OnInitialUpdate() → OnUpdate()
            → CFrameWnd::ActivateFrame() → 窗口顯示

五、 核心類關鍵數據成員速查

CWinApp 關鍵成員

  • m_pDocManager (CDocManager*):文檔模板管理器,實際持有模板列表。
  • m_pRecentFileList (CRecentFileList*):最近文件列表(MRU)。
  • m_nCmdShow, m_lpCmdLine:啟動參數。

CDocument 關鍵成員

  • m_strTitle, m_strPathName:標題/路徑。
  • m_pDocTemplate:反向指針。
  • m_viewList (CPtrList):關聯視圖列表。
  • m_bModified:髒標記,決定關閉時是否提示保存。

CDocTemplate / CSingleDocTemplate / CMultiDocTemplate

  • m_nIDResource:共享資源 ID(菜單/工具欄/圖標/字符串)。
  • m_pDocClass, m_pFrameClass, m_pViewClass:三大類的 CRuntimeClass*。
  • m_strDocStrings:7 段字符串(窗口標題、默認文檔名、文件類型描述、過濾器、擴展名、註冊表 ID/Name)。
  • SDI 獨有:m_pOnlyDoc 指向唯一文檔。MDI 獨有:m_docList 文檔列表、m_hMenuShared/m_hAccelTable 共享菜單/加速鍵。

掌握上述創建鏈、接口表、數據成員,即掌握了 MFC 框架的「骨架與經絡」,後續所有業務邏輯填充皆建立於此基石之上。

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