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

MFC 入門核心教程(一):CWinApp、CFrameWnd、消息循環與動態創建窗口

     編輯:VC++

MFC 架構核心兩大類


CWinApp (應用程序對象)          CFrameWnd (框架窗口)
├── 單例,進程級                  ├── 繼承 CWnd → 擁有 HWND
├── 管理消息泵                    ├── 封裝 CreateWindow/ShowWindow
├── InitInstance() → 創建主窗口    ├── 封裝消息映射宏
├── Run() → 消息循環              └── MDI: CMDIFrameWnd / CMDIChildWnd
└── ExitInstance() → 清理

最小 MFC 程序完整代碼


#include  // MFC 核心頭文件

// 1. 自定義框架窗口類
class CMyFrame : public CFrameWnd {
public:
    CMyFrame() {
        // 創建窗口:類名 NULL 使用默認 "Afx:...",標題 "MFC Window"
        Create(NULL, _T("MFC Window"));
        // 構造函數中彈出對話框演示
        MessageBox(_T("My MFC Window"), _T("CFrame Constructor"), MB_OK);
    }
};

// 2. 自定義應用程序類
class CMyApp : public CWinApp {
public:
    virtual BOOL InitInstance() {
        MessageBox(NULL, _T("My MFC Window"), _T("InitInstance"), MB_OK | MB_ICONASTERISK);
        
        // 動態創建主窗口對象 (堆上)
        CMyFrame* pFrame = new CMyFrame();
        
        // 關鍵:賦值給 m_pMainWnd
        // 1) 讓框架知道主窗口,Run() 會自動 ShowWindow/SW_SHOW
        // 2) 防止 InitInstance 結束時棧上對象銷毀導致窗口消失
        m_pMainWnd = pFrame;
        
        // 最大化顯示
        pFrame->ShowWindow(SW_SHOWMAXIMIZED);
        pFrame->UpdateWindow();
        
        return TRUE; // 繼續運行消息循環
    }
    
    virtual int ExitInstance() {
        MessageBox(NULL, _T("My Window"), _T("ExitInstance"), MB_OK | MB_ICONHAND);
        return CWinApp::ExitInstance();
    }
};

// 3. 全局唯一應用程序對象 (程序入口)
CMyApp theApp; // main() / WinMain() 隱藏在 MFC 庫中,自動構造 theApp → InitInstance() → Run()

編譯配置關鍵步驟 (VC++ 6.0 / VS 歷史專案)

  1. 新建 **Win32 Application** 專案,選 **Empty Project**。
  2. 添加 C++ 源文件 (`.cpp`)。
  3. **專案屬性 → General → Use of MFC** → **Use MFC in a Shared DLL** (或 Static Library)。
    未設置會鏈接錯誤:`unresolved external symbol _endthreadex / _beginthreadex` (CRT 與 MFC 線程模型不匹配)。
  4. 編譯運行。

核心流程深度解析

1. `CMyApp theApp` 全局構造

  • C++ 全局對象在 `main`/`WinMain` 前構造。
  • MFC 的 `WinMain` (在 `appmodul.cpp` 中) 會調用 `theApp.InitInstance()`。

2. `InitInstance()` — 應用程序初始化入口

  • **必須**創建主窗口並賦值 `m_pMainWnd`。
  • 返回 `TRUE` → 進入 `Run()` 消息循環;`FALSE` → 直接退出。
  • 典型任務:文檔模板註冊、主框架創建、命令行處理、配置載入。

3. `m_pMainWnd` 的來源與作用


// 定義在 CWinThread (CWinApp 基類)
public: CWnd* m_pMainWnd;
  • **來源**:`CWinApp` 繼承 `CWinThread` → 繼承 `m_pMainWnd`。
  • **作用**:
    1. `Run()` 中檢查 `m_pMainWnd`,自動調用 `ShowWindow(m_nCmdShow)` / `UpdateWindow()`。
    2. 消息循環中 `GetMessage` 篩選屬於主窗口的消息。
    3. 應用程序退出時框架自動銷毀 `m_pMainWnd` 指向的窗口對象。
  • **為何堆分配 (`new`)?** `InitInstance` 是棧幀,局部指針 `pFrame` 函數結束即銷毀,若不賦值給 `m_pMainWnd` (成員變量,隨 `theApp` 生命週期),窗口對象會過早釋放導致窗口消失。

4. `CFrameWnd::Create` 封裝 `CreateWindowEx`


BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
    DWORD dwStyle = WS_OVERLAPPEDWINDOW,
    const RECT& rect = rectDefault,
    CWnd* pParentWnd = NULL,
    LPCTSTR lpszMenuName = NULL,
    DWORD dwExStyle = 0,
    CCreateContext* pContext = NULL);
  • 參數有默認值,僅傳類名/標題即可創建標準重疊窗口。
  • 類名 `NULL` → MFC 自動註冊/使用預設窗口類 (`AfxWndClass`)。

5. 消息循環 `Run()` 簡化邏輯


int CWinApp::Run() {
    if (!InitInstance()) return FALSE;
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return ExitInstance();
}
  • `GetMessage` 阻塞等待消息,`DispatchMessage` 將消息分發到窗口過程 (`WndProc`)。
  • MFC 的 `WndProc` (`AfxWndProc`) 內部查找 `CWnd` 對象,調用消息映射表 (`BEGIN_MESSAGE_MAP`)。

常見新手誤區

誤區正確理解
以為 `CMyFrame` 構造函數結束窗口就創建好了`Create()` 才真正創建系統窗口 (HWND),構造函數僅初始化 C++ 對象
以為 `m_pMainWnd` 是靜態/全局變量它是 `CWinThread` 實例成員,`theApp` 是全局唯一實例
在 `InitInstance` 返回前 `delete pFrame`**絕對禁止**,`m_pMainWnd` 持有所有權,框架負責銷毀
以為 `MessageBox` 在構造函數中阻塞會影響窗口創建構造函數中 `Create()` 已完成,`MessageBox` 只阻塞當前線程,窗口已存在
不配置 "Use MFC" 直接編譯鏈接失敗,缺少 MFC 入口庫與 CRT 線程支持

擴展:文檔/視圖架構預覽

真實 MFC 應用通常繼承 `CWinApp` → `AddDocTemplate` 註冊 `CSingleDocTemplate` / `CMultiDocTemplate`,包含:

  • `CDocument` — 數據模型
  • `CView` — 視圖渲染
  • `CFrameWnd` / `CMDIFrameWnd` — 框架窗口
  • `CDocTemplate` — 協調三者創建

下一講將詳細講解文檔/視圖架構、消息映射、資源管理與對話框編程。

結語

MFC 的靈魂在於 **`CWinApp` 管理應用生命週期與消息泵**,**`CFrameWnd` 封裝窗口創建與消息分發**,**`m_pMainWnd` 連接兩者**。掌握最小程序的每一行代碼含義,是理解 MFC 文檔/視圖、消息映射、動態創建、序列化等高級機制的基石。

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