MFC文档视图结构框架分析

更新时间:2024-07-05 07:46:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

MFC文档视图结构框架分析 1:程序的“导火索”---theApp

CmyApp theApp;

在声明对象的同时,调用其构造函数。按C++的语法,首先要调用其基类Cwinapp的构造函数. 这个文件主要用于应用程序的一些初始化操作。

class CWinApp : public CWinThread {

DECLARE_DYNAMIC(CWinApp) public: // Constructor

CWinApp(LPCTSTR lpszAppName = NULL); ???? }

CWinApp::CWinApp(LPCTSTR lpszAppName) {

if (lpszAppName != NULL)

m_pszAppName = _tcsdup(lpszAppName); else

m_pszAppName = NULL; // initialize CWinThread state

AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE(); AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread; ASSERT(AfxGetThread() == NULL);

pThreadState->m_pCurrentWinThread = this; ASSERT(AfxGetThread() == this); m_hThread = ::GetCurrentThread(); m_nThreadID = ::GetCurrentThreadId();

// initialize CWinApp state

ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please pModuleState->m_pCurrentWinApp = this; ASSERT(AfxGetApp() == this);

// in non-running state until WinMain m_hInstance = NULL; m_hLangResourceDLL = NULL; m_pszHelpFilePath = NULL; m_pszProfileName = NULL; m_pszRegistryKey = NULL; m_pszExeName = NULL; m_pRecentFileList = NULL; m_pDocManager = NULL;

m_atomApp = m_atomSystemTopic = NULL; m_lpCmdLine = NULL; m_pCmdInfo = NULL;

// initialize wait cursor state m_nWaitCursorCount = 0; m_hcurWaitCursorRestore = NULL; // initialize current printer state m_hDevMode = NULL; m_hDevNames = NULL;

m_nNumPreviewPages = 0; // not specified (defaults to 1) // initialize DAO state

m_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called // other initialization m_bHelpMode = FALSE; m_eHelpType = afxWinHelp;

m_nSafetyPoolSize = 512; // default size }

2:theApp之后的隐藏代码,由他控制整个程序的流程。

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); }

其中有宏定义:#define _tWinMain wWinMain

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {

ASSERT(hPrevInstance == NULL); int nReturnCode = -1;

CWinThread* pThread = AfxGetThread();;// CWinApp是从CWinThread派生的, CWinApp* pApp = AfxGetApp(); //实质上就是pThread==pApp // AFX internal initialization

if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) //用于初始化

goto InitFailure;

// App global initializations (rare)

if (pApp != NULL && !pApp->InitApplication()) //用于初始化 goto InitFailure;

// Perform specific initializations

if (!pThread->InitInstance()) //注意多态性 virtual BOOL InitInstance();

//又因为pThread==pApp,所以调用pApp-> InitInstance()

{

if (pThread->m_pMainWnd != NULL) {

TRACE(traceAppMsg, 0, \n\

pThread->m_pMainWnd->DestroyWindow(); }

nReturnCode = pThread->ExitInstance(); goto InitFailure; }

nReturnCode = pThread->Run(); //控制消息循环 InitFailure: #ifdef _DEBUG

// Check for missing AfxLockTempMap calls

if (AfxGetModuleThreadState()->m_nTempMapLock != 0) {

TRACE(traceAppMsg, 0, \\\n\

AfxGetModuleThreadState()->m_nTempMapLock); }

AfxLockTempMaps(); AfxUnlockTempMaps(-1); #endif

AfxWinTerm(); return nReturnCode; }

由上面的程序可以看到几个很重要的函数

(1)AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) goto InitFailure; (2) pApp->InitApplication())

(3) pThread->InitInstance() (4) pThread->Run()

其中1,2 也是完成程序的一些初始化工作,4 主要是为了处理消息,3呢,很关键,我们运行时看到的窗口就是从这里产生。下面一一介绍

3:程序自动产生的InitInstance()函数

以下是自动生成的InitInstance()源程序: BOOL CmyApp::InitInstance() {

// 如果一个运行在 Windows XP 上的应用程序清单指定要 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, //则需要 InitCommonControls()。否则,将无法创建窗口。 InitCommonControls(); CWinApp::InitInstance(); // 初始化 OLE 库 if (!AfxOleInit()) {

AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; }

AfxEnableControlContainer(); // 标准初始化

// 如果未使用这些功能并希望减小 // 最终可执行文件的大小,则应移除下列 // 不需要的特定初始化例程 // 更改用于存储设置的注册表项 // TODO: 应适当修改该字符串, // 例如修改为公司或组织名

SetRegistryKey(_T(\应用程序向导生成的本地应用程序\

LoadStdProfileSettings(4); // 加载标准 INI 文件选项(包括 MRU) // 注册应用程序的文档模板。文档模板 // 将用作文档、框架窗口和视图之间的连接 CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(IDR_myTYPE, RUNTIME_CLASS(CmyDoc),

RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架 RUNTIME_CLASS(CmyView)); if (!pDocTemplate) return FALSE;

AddDocTemplate(pDocTemplate); // 创建主 MDI 框架窗口

CMainFrame* pMainFrame = new CMainFrame;

if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE;

m_pMainWnd = pMainFrame;

// 仅当具有后缀时才调用 DragAcceptFiles

// 在 MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生 // 分析标准外壳命令、DDE、打开文件操作的命令行 CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // 调度在命令行中指定的命令。如果

// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。

if (!ProcessShellCommand(cmdInfo)) //引发窗口注册 return FALSE;

// 主窗口已初始化,因此显示它并对其进行更新 pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); return TRUE;

}

其中,注册窗口用到了一下函数,比较长,如下:

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister) {

// mask off all classes that are already registered AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); fToRegister &= ~pModuleState->m_fRegisteredClasses; if (fToRegister == 0) return TRUE;

LONG fRegisteredClasses = 0; // common initialization WNDCLASS wndcls;

memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults wndcls.lpfnWndProc = DefWindowProc; //窗口处理函数 wndcls.hInstance = AfxGetInstanceHandle(); wndcls.hCursor = afxData.hcurArrow;

INITCOMMONCONTROLSEX init; init.dwSize = sizeof(init);

// work to register classes as specified by fToRegister, populate fRegisteredClasses as we go

if (fToRegister & AFX_WND_REG) {

// Child windows - no brush, no icon, safest default class styles wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wndcls.lpszClassName = _afxWnd; if (AfxRegisterClass(&wndcls)) fRegisteredClasses |= AFX_WND_REG;

}

if (fToRegister & AFX_WNDOLECONTROL_REG) {

// OLE Control windows - use parent DC for speed

wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wndcls.lpszClassName = _afxWndOleControl; if (AfxRegisterClass(&wndcls))

fRegisteredClasses |= AFX_WNDOLECONTROL_REG; }

if (fToRegister & AFX_WNDCONTROLBAR_REG) {

// Control bar windows

wndcls.style = 0; // control bars don't handle double click wndcls.lpszClassName = _afxWndControlBar;

wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); if (AfxRegisterClass(&wndcls))

fRegisteredClasses |= AFX_WNDCONTROLBAR_REG; }

if (fToRegister & AFX_WNDMDIFRAME_REG) {

// MDI Frame window (also used for splitter window) wndcls.style = CS_DBLCLKS; wndcls.hbrBackground = NULL;

if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME))

fRegisteredClasses |= AFX_WNDMDIFRAME_REG; }

if (fToRegister & AFX_WNDFRAMEORVIEW_REG) {

// SDI Frame or MDI Child windows or views - normal colors

wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))

fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG; }

if (fToRegister & AFX_WNDCOMMCTLS_REG) {

// this flag is compatible with the old InitCommonControls() API init.dwICC = ICC_WIN95_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MASK);

fToRegister &= ~AFX_WIN95CTLS_MASK; }

if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG) {

init.dwICC = ICC_UPDOWN_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_UPDOWN_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_TREEVIEW_REG) {

init.dwICC = ICC_TREEVIEW_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TREEVIEW_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_TAB_REG) {

init.dwICC = ICC_TAB_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_

TAB_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_PROGRESS_REG) {

init.dwICC = ICC_PROGRESS_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PROGRESS_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_LISTVIEW_REG) {

init.dwICC = ICC_LISTVIEW_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LISTVIEW_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_HOTKEY_REG) {

init.dwICC = ICC_HOTKEY_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_HOTKEY_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_BAR_REG) {

init.dwICC = ICC_BAR_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_BAR_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_ANIMATE_REG) {

init.dwICC = ICC_ANIMATE_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_

ANIMATE_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_INTERNET_REG) {

init.dwICC = ICC_INTERNET_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_INTERNET_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_COOL_REG) {

init.dwICC = ICC_COOL_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_COOL_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_USEREX_REG) {

init.dwICC = ICC_USEREX_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_USEREX_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_DATE_REG) {

init.dwICC = ICC_DATE_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_DATE_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_LINK_REG) {

init.dwICC = ICC_LINK_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_

LINK_REG);

}

// save new state of registered controls

pModuleState->m_fRegisteredClasses |= fRegisteredClasses;

// special case for all common controls registered, turn on AFX_WNDCOMMCTLS_REG

if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == AFX_WIN95CTLS_MASK)

{

pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG; fRegisteredClasses |= AFX_WNDCOMMCTLS_REG; }

// must have registered at least as mamy classes as requested return (fToRegister & fRegisteredClasses) == fToRegister; }

他是在PreCreateWindow中调用的注册,

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) {

if (cs.lpszClass == NULL) {

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background }

if (cs.style & FWS_ADDTOTITLE) cs.style |= FWS_PREFIXTITLE;

cs.dwExStyle |= WS_EX_CLIENTEDGE; return TRUE; }

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) {

if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE;

// TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return TRUE; }

BOOL CView::PreCreateWindow(CREATESTRUCT & cs) {

ASSERT(cs.style & WS_CHILD); if (cs.lpszClass == NULL) {

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background }

if (cs.style & WS_BORDER) {

cs.dwExStyle |= WS_EX_CLIENTEDGE; cs.style &= ~WS_BORDER; }

return TRUE; }

BOOL CTestView::PreCreateWindow(CREATESTRUCT& cs) {

// TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs

return CView::PreCreateWindow(cs); }

有几点要说明

(1)m_pMainWnd,头文件里并没有这个变量呀? 噢,这个在基类里定义的public 类型的变量,所以,他是通过继承得到的。

(2) 你注意过吗,当我们一点运行,会默认出来一个视图窗口,这是谁调用的呢?哦,就是下面这几行,它调用了opendocument() 函数。

CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (!ProcessShellCommand(cmdInfo)) return FALSE; (3)这个函数有个关键的地方 CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(IDR_myTYPE, RUNTIME_CLASS(CmyDoc),

RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架 RUNTIME_CLASS(CmyView)); if (!pDocTemplate) return FALSE;

AddDocTemplate(pDocTemplate); 通过它,把视图,窗口和文档结合起来。

4:主窗口CMainFrame的创建

(1)通过CMainFrame* pMainFrame = new CMainFrame;

我们得到的是不断调用的基类 CMainFrame::CMainFrame() {

// TODO: 在此添加成员初始化代码 }

CMDIFrameWnd::CMDIFrameWnd() {

m_hWndMDIClient = NULL; }

CFrameWnd::CFrameWnd() {

ASSERT(m_hWnd == NULL);

m_nWindow = -1; m_bAutoMenuEnable = TRUE; m_lpfnCloseProc = NULL; m_hMenuDefault = NULL; m_hAccelTable = NULL; m_nIDHelp = 0; m_nIDTracking = 0; m_nIDLastMessage = 0; m_pViewActive = NULL;

m_cModalStack = 0; m_phWndDisable = NULL; m_pNotifyHook = NULL; m_hMenuAlt = NULL;

m_nIdleFlags = 0; m_rectBorder.SetRectEmpty();

m_bHelpMode = HELP_INACTIVE; m_dwPromptContext = 0;

m_pNextFrameWnd = NULL;

m_bInRecalcLayout = FALSE; m_pFloatingFrameClass = NULL; m_nShowDelay = -1; AddFrameWnd();

// unknown window ID // auto enable on by default // initialize modality support// no idle work at start // not in Shift+F1 help mode // not in list yet // no delay pending

}

(2)pMainFrame->LoadFrame(IDR_MAINFRAME)所引发的一系列

BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) {

if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext)) return FALSE;

// save menu to use when no active MDI child window is present ASSERT(m_hWnd != NULL);

m_hMenuDefault = ::GetMenu(m_hWnd); if (m_hMenuDefault == NULL)

TRACE(traceAppMsg, 0, \\\n\

return TRUE; }

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) {

// only do this once

ASSERT_VALID_IDR(nIDResource);

ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)

CString strFullString;

if (strFullString.LoadString(nIDResource))

AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); // attempt to create the window

LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); CString strTitle = m_strTitle;

if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext)) {

return FALSE; // will self destruct on failure normally }

// save the default menu handle ASSERT(m_hWnd != NULL);

m_hMenuDefault = ::GetMenu(m_hWnd); // load accelerator resource

LoadAccelTable(MAKEINTRESOURCE(nIDResource)); if (pContext == NULL) // send initial update

SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); return TRUE; }

BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle,

CCreateContext* pContext) {

HMENU hMenu = NULL;

if (lpszMenuName != NULL) {

// load in a menu that will get destroyed when window gets destroyed

HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU); if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL) {

TRACE(traceAppMsg, 0, \nd.\\n\

PostNcDestroy(); // perhaps delete the C++ object return FALSE; } }

m_strTitle = lpszWindowName; // save title for later

if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,

pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) {

TRACE(traceAppMsg, 0, \ if (hMenu != NULL) DestroyMenu(hMenu); return FALSE; }

return TRUE; }

因为CFrameWnd没有重新写CreateEX,所以是调用的基类的CreateEx的函数: BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight,

HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) {

// allow modification of several common create parameters CREATESTRUCT cs;

cs.dwExStyle = dwExStyle; cs.lpszClass = lpszClassName; cs.lpszName = lpszWindowName; cs.style = dwStyle; cs.x = x; cs.y = y; cs.cx = nWidth; cs.cy = nHeight;

cs.hwndParent = hWndParent; cs.hMenu = nIDorHMenu;

cs.hInstance = AfxGetInstanceHandle(); cs.lpCreateParams = lpParam;

if (!PreCreateWindow(cs)) {

PostNcDestroy(); return FALSE; }

AfxHookWindowCreate(this);

HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,

cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

#ifdef _DEBUG if (hWnd == NULL) {

TRACE(traceAppMsg, 0, \r returns 0x%8.8X\\n\

GetLastError()); } #endif

if (!AfxUnhookWindowCreate())

PostNcDestroy(); // cleanup if CreateWindowEx fails too soon

if (hWnd == NULL) return FALSE;

ASSERT(hWnd == m_hWnd); // should have been set in send msg hook return TRUE; }

可以看到,::CreateWindowEx是一个全局的函数,在其中触发WM_CREATE消息,进而调用我们自己定义的CMainFrame::OnCreate()

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {

if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;

if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0(\未能创建工具栏\\n\ return -1; // 未能创建 }

if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) {

TRACE0(\未能创建状态栏\\n\ return -1; // 未能创建 }

//TODO: 如果不需要工具栏可停靠,则删除这三行 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar);

return 0; }

5:运行后为什么能产生CMainFarme,文档 ,视图以及视图外包围的farme呢?

你注意过吗,当我们一点运行,会默认出来一个视图窗口,这是谁调用的呢?哦,就是下面这几行,它调用void CWinApp::OnFileNew()函数.

CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo);

if (!ProcessShellCommand(cmdInfo)) return FALSE;

你可以自己跟踪以下。这里有个小技巧,你可以在BOOL CmyDoc::OnNewDocument()处设立断点,然后“跳出”,最后你会达到起始点!ProcessShellCommand(cmdInfo)

void CWinApp::OnFileNew() {

if (m_pDocManager != NULL)

m_pDocManager->OnFileNew(); //接着调用下面的函数 }

void CDocManager::OnFileNew() {

if (m_templateList.IsEmpty()) {

TRACE(traceAppMsg, 0, \ CWinApp.\\n\

AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); return; }

CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead(); if (m_templateList.GetCount() > 1) {

// more than one document template to choose from // bring up dialog prompting user CNewTypeDlg dlg(&m_templateList); INT_PTR nID = dlg.DoModal(); if (nID == IDOK)

pTemplate = dlg.m_pSelectedTemplate; else

return; // none - cancel operation }

ASSERT(pTemplate != NULL);

ASSERT_KINDOF(CDocTemplate, pTemplate);

pTemplate->OpenDocumentFile(NULL); //接着调用下面的函数

// if returns NULL, the user has already been alerted }

CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible) {

CDocument* pDocument = CreateNewDocument(); //产生模板控制之一:文档 if (pDocument == NULL) {

TRACE(traceAppMsg, 0, \L.\\n\

AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); return NULL; }

ASSERT_VALID(pDocument);

BOOL bAutoDelete = pDocument->m_bAutoDelete;

pDocument->m_bAutoDelete = FALSE; // don't destroy if something goes wrong

CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL); //产生新的:框架

pDocument->m_bAutoDelete = bAutoDelete; if (pFrame == NULL) {

AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); delete pDocument; // explicit delete on error return NULL; }

ASSERT_VALID(pFrame);

if (lpszPathName == NULL)

{

// create a new document - with default document name SetDefaultTitle(pDocument);

// avoid creating temporary compound file when starting up invisible

if (!bMakeVisible)

pDocument->m_bEmbedded = TRUE;

if (!pDocument->OnNewDocument()) {

// user has be alerted to what failed in OnNewDocument

TRACE(traceAppMsg, 0, \\\n\

pFrame->DestroyWindow(); return NULL; }

// it worked, now bump untitled count m_nUntitledCount++; } else {

// open an existing document CWaitCursor wait;

if (!pDocument->OnOpenDocument(lpszPathName)) {

// user has be alerted to what failed in OnOpenDocument

TRACE(traceAppMsg, 0, \\\n\

pFrame->DestroyWindow();

return NULL; }

pDocument->SetPathName(lpszPathName); }

InitialUpdateFrame(pFrame, pDocument, bMakeVisible); return pDocument; }

我需要对上述函数进行进一步说明

(1)CreateNewDocument()产生文档

CDocument* CDocTemplate::CreateNewDocument() {

// default implementation constructs one from CRuntimeClass if (m_pDocClass == NULL) {

TRACE(traceAppMsg, 0, \eNewDocument.\\n\

ASSERT(FALSE); return NULL; }

CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject(); if (pDocument == NULL) {

TRACE(traceAppMsg, 0, \ failed.\\n\

m_pDocClass->m_lpszClassName); return NULL;

}

ASSERT_KINDOF(CDocument, pDocument); AddDocument(pDocument); return pDocument; }

(2)CreateNewFrame(pDocument, NULL),产生框架和视图

CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)

{

if (pDoc != NULL) ASSERT_VALID(pDoc);

// create a frame wired to the specified document

ASSERT(m_nIDResource != 0); // must have a resource ID to load from CCreateContext context;

context.m_pCurrentFrame = pOther;

}

ASSERT_KINDOF(CDocument, pDocument); AddDocument(pDocument); return pDocument; }

(2)CreateNewFrame(pDocument, NULL),产生框架和视图

CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)

{

if (pDoc != NULL) ASSERT_VALID(pDoc);

// create a frame wired to the specified document

ASSERT(m_nIDResource != 0); // must have a resource ID to load from CCreateContext context;

context.m_pCurrentFrame = pOther;

本文来源:https://www.bwwdw.com/article/63q.html

Top