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

深入剖析 MFC 應用程式架構:SDI 程式框架詳解(二)

     編輯:VC++

MFC 應用程式結構核心解析

在上一篇《明明白白看 MFC 之程式框架(一)》中,我們已分析過經典 SDK 應用程式的結構。本文將正式進入 MFC 應用程式架構的核心——以最經典的 SDI(單文檔介面)Hello World 為例,剖析 MFC 如何封裝 Windows 程式的啟動與運行流程。

從向導生成的程式碼說起

使用 AppWizard 生成 SDI 專案後,會產生多個檔案。為了理清主流程,我們暫且忽略檔案劃分,直接提取關鍵原始碼進行分析(原始 MFC 產生的程式碼閱讀性較差,此處已重新整理排版)。

CHelloWorldApp theApp;

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPTSTR lpCmdLine, int nCmdShow)
{
    CWinThread* pThread = AfxGetThread();
    CWinApp* pApp = AfxGetApp();
    // AFX 內部初始化
    if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
        goto InitFailure;
    // 應用程式全域初始化(少用)
    if (pApp != NULL && !pApp->InitApplication())
        goto InitFailure;
    // 執行具體初始化
    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;
    }
    nReturnCode = pThread->Run();
InitFailure:
    // ...
    AfxWinTerm();
    return nReturnCode;
}

BOOL CWinApp::InitApplication()
{
    if (CDocManager::pStaticDocManager != NULL)
    {
        if (m_pDocManager == NULL)
            m_pDocManager = CDocManager::pStaticDocManager;
        CDocManager::pStaticDocManager = NULL;
    }
    if (m_pDocManager != NULL)
        m_pDocManager->AddDocTemplate(NULL);
    else
        CDocManager::bStaticInit = FALSE;
    return TRUE;
}

BOOL CHelloWorldApp::InitInstance()
{
    AfxEnableControlContainer();
    // ...
    // 修改註冊表鍵值以儲存設定
    SetRegistryKey(_T("Local AppWizard-Generated Applications"));
    LoadStdProfileSettings(); // 載入標準 INI 選項(含 MRU)
    // 註冊文檔模板:連接文檔、框架視窗與視圖
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CHelloWorldDoc),
        RUNTIME_CLASS(CMainFrame), // 主 SDI 框架視窗
        RUNTIME_CLASS(CHelloWorldView));
    AddDocTemplate(pDocTemplate);
    // 解析命令列參數
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);
    // 分派命令列指令
    if (!ProcessShellCommand(cmdInfo))
        return FALSE;
    // 唯一視窗已初始化,顯示並更新
    m_pMainWnd->ShowWindow(SW_SHOW);
    m_pMainWnd->UpdateWindow();
    return TRUE;
}

BOOL CWinApp::InitInstance()
{
    return TRUE;
}

程式執行流程圖解

乍看之下,這段程式碼似乎無從下手,甚至找不到傳統意義上的 main() 入口點。實則 AfxWinMain() 正是 MFC 程式的入口點。其執行路徑如下:

  1. 入口點 AfxWinMain()
  2. AfxGetThread() 取得執行緒指標
  3. AfxGetApp() 取得應用程式物件指標
  4. AfxWinInit() 進行 MFC 內部初始化
  5. pApp->InitApplication() 應用程式層級初始化
  6. pThread->InitInstance() 執行個體初始化(關鍵步驟)
  7. pThread->Run() 進入訊息迴圈(對應 SDK 的 GetMessage/DispatchMessage 迴圈)

核心機制解讀

程式啟動時,首先定義全域變數 theApp 代表整個應用程式的存在。AfxWinMain() 透過 AfxGetApp() 取得 CWinApp 衍生類別指標,進而呼叫初始化與啟動相關成員函式,最後進入 Run() 訊息迴圈。

你可能會疑惑:「Hello World」字串何時輸出? 這並非疏忽,而是 MFC 採用全新的訊息處理機制(相對於 SDK),其繪圖與輸出邏輯封裝在文檔/視圖架構中。這部分涉及 MFC 文件組織與類別間的呼叫關係,將在下一篇詳細剖析。

學習 MFC 是漫長過程,建立宏觀架構認識至關重要。下一篇將深入分析 MFC 產生的主要檔案與類別關係,敬請期待。

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