大家好,歡迎來到我的MFC編程入門系列。上次我們聊了MFC項目創建后的核心文件區別(項目名.cpp、.h、Dlg.cpp 和 Dlg.h),今天針對讀者的反饋,專門來拆解其中最重要的一個文件:項目名.cpp(這里以用戶提供的“YoloClassMFC.cpp”為例)。作為小白,你看到這個文件滿是代碼、宏和TODO注釋,肯定覺得一頭霧水——這都是啥?能刪掉嗎?它到底干嘛用的?別慌,這篇文章用最接地氣的語言幫你逐行解釋清楚。讀完后,你會明白為什么MFC必須有它,以及怎么安全地修改。
這篇文章基于Visual Studio自動生成的MFC“基于對話框”應用代碼(假設你是用VS2022或類似版本創建的)。咱們先整體看作用,然后細拆代碼,最后討論刪除問題。走起!
先了解背景:YoloClassMFC.cpp 是什么?
當你用Visual Studio創建MFC項目(項目名“YoloClassMFC”)時,它會自動生成這個.cpp文件。它是整個程序的“心臟”——定義了一個叫CYoloClassMFCApp
的類,繼承自MFC的CWinApp
(Windows Application的縮寫)。這個類負責啟動程序、初始化窗口、處理系統消息(如關閉窗口),并在程序結束時清理資源。
簡單比喻:想象你的MFC程序是一輛車,這個文件就是“引擎和鑰匙”。沒有它,車就啟動不了。MFC框架要求每個應用都有這樣一個入口類,否則程序無法運行。
關鍵點:這個文件是自動生成的,你可以修改但別亂刪。里面有很多 boilerplate(模板)代碼,小白先別改,理解了再動手。
逐行/逐部分解釋代碼
下面我把代碼貼出來,并加注釋解釋。每部分后加“小白解讀”,讓你輕松懂。代碼是標準的MFC模板,我會突出重點。
// YoloClassMFC.cpp: 定義應用程序的類行為。
//#include "pch.h" // 預編譯頭文件,包含常用頭文件,提高編譯速度
#include "framework.h" // MFC框架頭文件
#include "YoloClassMFC.h" // 本項目的應用類頭文件
#include "YoloClassMFCDlg.h" // 主對話框類的頭文件#ifdef _DEBUG // 如果是調試模式
#define new DEBUG_NEW // 自定義new操作符,幫助調試內存泄漏
#endif// CYoloClassMFCApp // 這是應用類名,繼承自CWinAppBEGIN_MESSAGE_MAP(CYoloClassMFCApp, CWinApp) // 開始消息映射(MFC機制,用于處理Windows消息)ON_COMMAND(ID_HELP, &CWinApp::OnHelp) // 映射“幫助”命令到默認處理函數
END_MESSAGE_MAP() // 結束消息映射// CYoloClassMFCApp 構造 // 類的構造函數CYoloClassMFCApp::CYoloClassMFCApp() // 構造函數定義
{// 支持重新啟動管理器 // 這行啟用Windows的重新啟動功能(如果程序崩潰,能自動重啟)m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;// TODO: 在此處添加構造代碼, // 這里是給你加自定義初始化的地方// 將所有重要的初始化放置在 InitInstance 中 // 提示:別在這里初始化,放InitInstance里
}// 唯一的 CYoloClassMFCApp 對象 // 創建全局對象theApp,這是程序的起點!CYoloClassMFCApp theApp; // 這個對象是MFC的“單例”,程序從這里啟動// CYoloClassMFCApp 初始化 // 最重要的函數:InitInstance()BOOL CYoloClassMFCApp::InitInstance() // 這個函數在程序啟動時自動調用
{// 如果一個運行在 Windows XP 上的應用程序清單指定要// 使用 ComCtl32.dll 版本 6 或更高版本來啟用可視化方式,//則需要 InitCommonControlsEx()。 否則,將無法創建窗口。INITCOMMONCONTROLSEX InitCtrls; // 初始化結構InitCtrls.dwSize = sizeof(InitCtrls); // 設置大小// 將它設置為包括所有要在應用程序中使用的// 公共控件類。InitCtrls.dwICC = ICC_WIN95_CLASSES; // 指定要初始化的控件類型(Windows標準控件)InitCommonControlsEx(&InitCtrls); // 調用初始化公共控件CWinApp::InitInstance(); // 調用父類的初始化AfxEnableControlContainer(); // 啟用MFC控件容器(支持ActiveX等)// 創建 shell 管理器,以防對話框包含// 任何 shell 樹視圖控件或 shell 列表視圖控件。CShellManager *pShellManager = new CShellManager; // 創建Shell管理器(處理文件瀏覽器等控件)// 激活“Windows Native”視覺管理器,以便在 MFC 控件中啟用主題CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); // 設置視覺樣式(讓界面看起來現代)// 標準初始化// 如果未使用這些功能并希望減小// 最終可執行文件的大小,則應移除下列// 不需要的特定初始化例程// 更改用于存儲設置的注冊表項// TODO: 應適當修改該字符串,// 例如修改為公司或組織名SetRegistryKey(_T("應用程序向導生成的本地應用程序")); // 設置注冊表鍵,用于保存程序設置(如窗口位置)CYoloClassMFCDlg dlg; // 創建主對話框對象(這是你的主窗口!)m_pMainWnd = &dlg; // 設置為主窗口INT_PTR nResponse = dlg.DoModal(); // 顯示對話框(模態窗口,阻塞直到關閉)if (nResponse == IDOK) // 如果用戶點擊“OK”{// TODO: 在此放置處理何時用// “確定”來關閉對話框的代碼}else if (nResponse == IDCANCEL) // 如果點擊“取消”{// TODO: 在此放置處理何時用// “取消”來關閉對話框的代碼}else if (nResponse == -1) // 如果創建失敗{TRACE(traceAppMsg, 0, "警告: 對話框創建失敗,應用程序將意外終止。\n"); // 輸出警告TRACE(traceAppMsg, 0, "警告: 如果您在對話框上使用 MFC 控件,則無法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");}// 刪除上面創建的 shell 管理器。if (pShellManager != nullptr) // 清理Shell管理器{delete pShellManager;}#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS) // 如果不是DLL模式ControlBarCleanUp(); // 清理控件欄
#endif// 由于對話框已關閉,所以將返回 FALSE 以便退出應用程序,// 而不是啟動應用程序的消息泵。return FALSE; // 返回FALSE,結束程序(因為是對話框應用,不需要消息泵)
}
小白解讀(分模塊)
- 頭文件包含(#include):這些是“導入庫”,告訴編譯器用哪些工具。
pch.h
是預編譯頭,加速編譯;YoloClassMFCDlg.h
鏈接主窗口。 - 消息映射(BEGIN_MESSAGE_MAP):MFC的“事件處理器”。這里只映射了幫助菜單,你可以加更多(如自定義菜單)。
- 構造函數(CYoloClassMFCApp()):初始化類。里面有TODO,意思是你可以加代碼,但最好放
InitInstance
里。 - 全局對象(theApp):這是魔法!Windows啟動程序時,會自動創建這個對象,然后調用它的
InitInstance()
。 - InitInstance():程序的“主函數”。它初始化控件、設置樣式、創建并顯示主對話框(
dlg.DoModal()
),處理關閉后的響應。最后返回FALSE,因為這是對話框應用(程序顯示窗口后就等用戶操作,關閉即退出)。 - 清理代碼:刪除管理器,防止內存泄漏。那些注釋是模板提示,告訴你可以優化(如移除不用的初始化來縮小EXE大小)。
這些代碼大多是MFC的“標準套路”,確保程序兼容Windows各種版本。
這個文件的作用是什么?為什么要有它?
-
作用:
- 程序入口:它是MFC應用的起點。沒有它,編譯會報錯,因為MFC需要一個
CWinApp
子類來管理一切。 - 初始化:設置控件、視覺主題、注冊表等,讓你的窗口能正常顯示。
- 窗口管理:創建并顯示主對話框(YoloClassMFCDlg),處理其關閉。
- 消息處理:通過消息映射響應系統事件(如幫助菜單)。
- 清理:確保程序退出時釋放資源,避免崩潰或內存問題。
- 程序入口:它是MFC應用的起點。沒有它,編譯會報錯,因為MFC需要一個
-
為什么要有這個:MFC是基于Windows API的框架,它模擬了Win32程序的結構(WinMain函數)。這個文件提供了那個“模擬”,讓你的C++代碼能無縫運行在Windows上。如果沒有它,程序就不知道怎么啟動、怎么顯示窗口、怎么響應用戶輸入。簡單說,MFC強制要求這個類來“橋接”你的代碼和操作系統。
比喻:就像手機App需要一個main函數啟動,MFC需要這個文件作為“App啟動器”。
能刪除嗎?千萬別!
- 不能刪除:刪了它,程序就沒了入口,編譯會失敗(報“未定義的theApp”或鏈接錯誤)。MFC框架依賴它。
- 能修改嗎:能!但小心:
- 加自定義初始化:在
InitInstance()
的TODO處。 - 如果你不想用模態對話框,可以改成非模態(但那是進階)。
- 移除不用的部分:如注釋說的,刪掉不用的初始化來優化,但別刪核心如
dlg.DoModal()
。
- 加自定義初始化:在
- 如果刪錯了:用VS的“撤消”或從備份恢復。測試時先備份項目。
小白如何讀懂和上手
- 運行看看:F5編譯運行,默認彈出空對話框。關閉后程序結束——這就是
DoModal()
的作用。 - 簡單實驗:在
InitInstance()
的if (nResponse == IDOK)里加MessageBox(NULL, _T("OK clicked!"), _T("Test"), MB_OK);
,運行點擊OK看彈窗。 - 調試技巧:在
InitInstance()
加斷點(F9),F5調試,單步執行(F10)看流程。 - 常見困惑:為什么這么多初始化?因為MFC要兼容老Windows。TODO是給你留的“鉤子”,別忽略。
- 進階:學MFC文檔,了解
CWinApp
的其他函數如ExitInstance()
。
MFC雖老,但理解這些模板能幫你快速開發Windows軟件。實踐多試錯,你很快就熟練了!有問題評論區問我。
參考:MSDN CWinApp文檔、VS MFC向導幫助。
點贊、收藏、關注,謝謝!下篇聊Dlg.cpp的秘密~