承接上篇,本文深入剖析 MFC 文檔/視圖架構中最複雜的環節:**框架窗口加載、視圖創建、初始化更新、激活顯示** 的完整調用鏈。通過源碼級流程圖解,揭示 LoadFrame、OnCreate、OnCreateClient、CreateView、InitialUpdateFrame、OnInitialUpdate、ActivateFrame 等關鍵虛擬函數的協作機制,並對比 SDI 與 MDI 的異同,助你精準掌控窗口生命周期。
BOOL CFrameWnd::LoadFrame(UINT nIDResource,
DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
CWnd* pParentWnd = NULL,
CCreateContext* pContext = NULL)
AfxRegisterWndClass)。Create → 內部 ::CreateWindowEx 創建 HWND,將 pContext 作為 lpCreateParams 傳入。WM_NCCREATE/WM_CREATE,進入 OnCreate。int CFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
CCreateContext* pContext = (CCreateContext*)lpCreateStruct->lpCreateParams;
return OnCreateHelper(lpCreateStruct, pContext);
}
OnCreateHelper 核心邏輯:
CWnd::OnCreate(基類處理)。OnCreateClient(lpCreateStruct, pContext) —— SDI 默認實現調用 CreateView 創建視圖。WM_SETMESSAGESTRING 設置狀態欄「Ready」。RecalcLayout 佈局工具欄/狀態欄。CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID = AFX_IDW_PANE_FIRST)
pContext->m_pNewViewClass 動態創建視圖對象(CRuntimeClass::CreateObject)。Create 創建子窗口(ID = AFX_IDW_PANE_FIRST,父窗口 = 框架窗口)。WM_CREATE 由 CView::OnCreate 處理(通常無特殊邏輯)。void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)
調用時機:文檔模板 OpenDocumentFile 結束前,傳入新建文檔指針與 TRUE。
AFX_IDW_PANE_FIRST 的視圖,調用 SetActiveView(pView, FALSE) 設置(不通知激活)。bMakeVisible==TRUE,向**所有**子窗口(視圖、工具欄、狀態欄)發送 WM_INITIALUPDATE。
CView::OnInitialUpdate → 默認調用 OnUpdate(NULL, 0, NULL) → 使客戶區無效,觸發首次 WM_PAINT 繪製。pView->OnActivateFrame(WA_INACTIVE, this) 保存焦點狀態(CFormView 用於恢復輸入焦點)。ActivateFrame → 觸發 WM_ACTIVATE → OnActivateTopLevel/OnActivate → 若有活動視圖調用 OnActivateView(TRUE)。pDoc 非空,更新 m_nWindow 計數(MDI 多視圖同一文檔編號用),設置標題(如 "Doc:1"、"Doc:2",SDI 單視圖 m_nWindow=-1 不顯示編號)。SetActiveView:失活舊視圖 (OnActivateView(FALSE)) → 更新 m_pViewActive → 通知新視圖 (OnActivateView(TRUE))。ActivateFrame:ShowWindow + BringWindowToTop + SetForegroundWindow 組合,可覆蓋自定義激活邏輯(如最小化啟動)。CView::OnInitialUpdate():虛擬函數,默認調用 OnUpdate(NULL, 0, NULL)。重寫點:在此初始化滾動範圍、設置縮放比例、綁定數據源等。CView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint):文檔調用 UpdateAllViews 觸發。默認使整個客戶區無效。參數用於增量更新(lHint 為提示碼,pHint 為提示對象)。AfxWndProc → _AfxHandleActivate:若為頂層非子窗口且頂級父窗口異,發送 WM_ACTIVATETOPLEVEL。CWnd::OnActivateTopLevel:失活時取消 Tooltip。CFrameWnd::OnActivateTopLevel:若為線程主窗口,失活活動視圖 (OnActivateView(FALSE))。CWnd::OnActivate / CFrameWnd::OnActivate:基類默認處理;框架窗口激活時重新激活活動視圖 (OnActivateView(TRUE)) 並通知幀狀態變化 (OnActivateFrame)。SDI 核心鏈:
InitInstance → 文檔模板 → OpenDocumentFile → 文檔創建 (OnNewDocument/OnOpenDocument) → 框架創建 (LoadFrame) → 視圖創建 (CreateView) → 初始化 (InitialUpdateFrame) → 激活顯示。
MDI 關鍵差異(下節詳解):
CMDIFrameWnd,創建於 InitInstance 早期(非延遲到打開文檔)。CMDIChildWnd(子窗口),由 MDI Client 窗口 (WM_MDICREATE) 管理。CMultiDocTemplate) 管理多文檔列表,無唯一文檔指針。WM_MDIREFRESHMENU)。