MFC 文檔/視圖架構封裝了大量常用功能 (新建、開啟、儲存),讓開發者專注業務邏輯。但這層「透明性」也帶來困擾:不知何時呼叫何種虛擬函式、欲修改預設行為卻無從下手。本文透過 Debug 追蹤,梳理多文檔 (MDI) 架構下三大核心流程,單文檔 (SDI) 僅將 CMultiDocTemplate 換為 CSingleDocTemplate 即可類推。
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
入口: CWinApp::OnFileNew
→ CWinApp 預設實作呼叫: CDocManager::OnFileNew()
1. 判斷是否有文檔模板,無則返回
2. 多模板時彈出選擇對話框,取得模板指標
3. 呼叫 CMultiDocTemplate::OpenDocumentFile()
3.1 建立新文檔物件 (CDocument 派生)
3.2 建立對應子框架 (CMDIChildWnd),建立 文檔-框架-視圖 關聯
3.3 呼叫應用程式 OnNewDocument()
a. CDocument::OnNewDocument() → DeleteContents()
b. 使用者自訂初始化程式碼
3.4 InitialUpdateFrame() 顯示視圖
3.5 返回文檔指標
4. 返回
CDocument::OnNewDocument():初始化文檔資料結構CDocument::DeleteContents():清理舊資料 (新建/開啟前皆呼叫)CMultiDocTemplate::OpenDocumentFile():可覆寫自訂文檔建立邏輯ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
入口: CWinApp::OnFileOpen
→ CDocManager::OnFileOpen()
1. 彈出檔案對話框,取得完整路徑
2. 呼叫應用程式 OpenDocumentFile(lpszFileName)
2.1 使用者程式碼
2.2 CWinApp::OpenDocumentFile() → CDocManager::OpenDocumentFile()
a. 檢查檔案是否已開啟,是則激活視窗返回
b. CMultiDocTemplate::OpenDocumentFile()
b.1 建立文檔、子框架
b.2 呼叫應用程式 OnOpenDocument()
(1) CDocument::OnOpenDocument()
. 開啟檔案物件 (CFile)
. DeleteContents()
. 建立 CArchive 關聯檔案
. 呼叫文檔 Serialize() 反序列化
. 關閉 CArchive、檔案
(2) 顯示檔案視窗
b.3 返回
3. 返回
CDocument::OnOpenDocument():預設實作序列化,可覆寫自訂檔案格式 (XML/JSON/資料庫)CDocument::Serialize():核心資料持久化邏輯,ar.IsStoring() 區分讀/寫CDocManager::OpenDocumentFile():可攔截重複開啟、唯讀處理儲存 (ID_FILE_SAVE): ON_COMMAND(ID_FILE_SAVE, CDocument::OnFileSave)
入口: CDocument::OnFileSave()
→ CDocument::DoFileSave()
若檔名為空或唯讀 → DoSave(NULL)
否則 → DoSave(m_strPathName)
另存新檔 (ID_FILE_SAVE_AS): ON_COMMAND(ID_FILE_SAVE_AS, CDocument::OnFileSaveAs)
入口: CDocument::OnFileSaveAs()
→ DoSave(NULL)
CDocument::DoSave(lpszPathName, bReplace)
若 lpszPathName 為 NULL:
1. 設定預設檔名
2. 彈出儲存對話框取得檔名
3. 呼叫應用程式 OnSaveDocument()
3.1 使用者程式碼
3.2 CDocument::OnSaveDocument()
a. 建立/開啟檔案
b. 建立 CArchive
c. 呼叫 Serialize() 序列化
d. 關閉檔案、CArchive
e. 設定「未修改」旗標
4. 返回
CDocument::OnSaveDocument():可覆寫加入加密、壓縮、版本控制CDocument::DoSave():控制對話框行為、預設路徑、副檔名過濾CDocument::SetModifiedFlag():標記髒資料,提示儲存CWinApp
└─ CDocManager
└─ CMultiDocTemplate / CSingleDocTemplate
├─ CreateNewDocument() → CDocument
├─ CreateNewFrame() → CMDIChildWnd / CFrameWnd
├─ InitialUpdateFrame() → CView
└─ OpenDocumentFile() → 統籌上述流程
掌握這三大流程的呼叫鏈與虛擬函式擴充點,即可:
Serialize)OnSaveDocument)OpenDocumentFile)OnOpenDocument/OnSaveDocument)建議開發者親自追蹤一次,建立心智模型,事半功倍。