MFC 應用程式架構封裝了文件建立、檔案開啟/儲存等核心功能,操作對使用者透明。但這也導致流程神祕,開發者難知何時呼叫何介面、如何修改預設行為。本文透過 Debug 單步追蹤核心原始碼,梳理多文件架構(MDI)關鍵流程,單文件 (SDI) 僅將 CMultiDocTemplate 換為 CSingleDocTemplate 即可類推。
入口: CWinApp::OnFileNew
→ CDocManager::OnFileNew()
1. 檢查文件模板是否存在
2. 多模板時彈出選擇對話框,取得模板指標
3. 呼叫 CMultiDocTemplate::OpenDocumentFile(NULL)
3.1 建立新文件物件
3.2 建立對應子框架,建立框架-文件-視圖關聯
3.3 呼叫應用程式 OnNewDocument()
a. CDocument::OnNewDocument() → DeleteContents()
b. 使用者自訂初始化代碼
3.4 InitialUpdateFrame() 顯示視圖
3.5 回傳文件指標
4. 返回
入口: CWinApp::OnFileOpen
→ CDocManager::OnFileOpen()
1. 彈出檔案對話框,取得完整路徑
2. 呼叫應用程式 OpenDocumentFile(lpszFileName)
2.1 使用者代碼
2.2 CWinApp::OpenDocumentFile → CDocManager::OpenDocumentFile
a. 檢查該檔案是否已有開啟的文件物件,有則激活視窗並返回
b. 呼叫 CMultiDocTemplate::OpenDocumentFile(lpszFileName)
b.1 建立新文件物件與子框架
b.2 呼叫應用程式 OnOpenDocument()
(1) CDocument::OnOpenDocument()
- 開啟檔案物件
- DeleteContents()
- 建立 CArchive 關聯檔案
- 呼叫文件 Serialize() 反序列化
- 關閉 CArchive 與檔案
(2) 顯示視窗
b.3 返回文件指標
2.2 返回
入口: CDocument::OnFileSave()
→ CDocument::DoFileSave()
- 若檔名為空或唯讀 → DoSave(NULL)
- 否則 → DoSave(m_strPathName)
入口: CDocument::OnFileSaveAs() → DoSave(NULL) // 強制彈出另存新檔對話框
DoSave(lpszPathName, bReplace)
1. lpszPathName 為 NULL 時:
a. 設定預設檔名
b. 彈出儲存對話框取得檔名
2. 呼叫應用程式 OnSaveDocument()
3.1 使用者代碼
3.2 CDocument::OnSaveDocument()
a. 建立/開啟檔案
b. 建立 CArchive
c. 呼叫文件 Serialize() 序列化
d. 關閉檔案與 CArchive
e. 設定「未修改」旗標
3. 返回
| 虛擬函式 | 用途 | 典型覆寫內容 |
|---|---|---|
| OnNewDocument | 新文件初始化 | 資料結構初始化、配置資源 |
| OnOpenDocument | 開啟檔案並反序列化 | 自訂檔案格式讀取、錯誤處理 |
| OnSaveDocument | 序列化並寫入檔案 | 自訂檔案格式寫入、壓縮/加密 |
| Serialize | 核心序列化邏輯 | 資料成員讀寫 CArchive |
| DeleteContents | 清除文件資料 | 釋放記憶體、重設狀態 |
掌握此流程即可精準控制文件生命週期,在正確時機注入自訂邏輯,或替換預設檔案處理行為。