本文转载自:http://blog.csdn.net/teleinfor/article/details/1856725
对OnFileNew()/OnFileOpen()的MFC代码跟踪简析,简析可能也谈不上了,为了快速的理解MFC的实现思路以及文档视图架构的应用,在学习的过程当中我也没有进行学习理解的注解。不过细细阅读整个的实现流程,相信你我都能理解掌握MFC的整体思路。以后有机会再进行注解吧。
A) OnFileNew()执行过程分析
1. void CWinApp::OnFileNew()
{
if
(m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}
注释:MFC对ID_FILE_NEW菜单的响应函数,系统默认操作.
2. void CDocManager::OnFileNew()
{
if
(m_templateList.IsEmpty())
{
TRACE0("Error:
no document templates registered with
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
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
}
注:如果跳过此函数而手动操作直接进入pTemplate->OpenDocumentFile(),那么文档模版列表选择对话框也就不会出现了.
3. CDocument*
CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL
bMakeVisible)
{
CDocument*
pDocument =
CreateNewDocument();
if
(pDocument == NULL)
{
TRACE0("CDocTemplate::CreateNewDocument
returned NULL./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
TRACE0("CDocument::OnNewDocument
returned FALSE./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
TRACE0("CDocument::OnOpenDocument
returned FALSE./n");
pFrame->DestroyWindow();
return
NULL;
}
pDocument->SetPathName(lpszPathName);
}
InitialUpdateFrame(pFrame,
pDocument, bMakeVisible);
return
pDocument;
}
4. CDocument* CDocTemplate::CreateNewDocument()
{
//
default implementation constructs one from
CRuntimeClass
if
(m_pDocClass == NULL)
{
TRACE0("Error:
you must override
CDocTemplate::CreateNewDocument./n");
ASSERT(FALSE);
return
NULL;
}
CDocument*
pDocument =
(CDocument*)m_pDocClass->CreateObject();
if
(pDocument == NULL)
{
TRACE1("Warning:
Dynamic create of document type %hs
failed./n",
m_pDocClass->m_lpszClassName);
return
NULL;
}
ASSERT_KINDOF(CDocument,
pDocument);
AddDocument(pDocument);
return
pDocument;
}
5. 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;
context.m_pCurrentDoc
= pDoc;
context.m_pNewViewClass
= m_pViewClass;
context.m_pNewDocTemplate
= this;
if
(m_pFrameClass == NULL)
{
TRACE0("Error:
you must override
CDocTemplate::CreateNewFrame./n");
ASSERT(FALSE);
return
NULL;
}
CFrameWnd*
pFrame =
(CFrameWnd*)m_pFrameClass->CreateObject();
if
(pFrame == NULL)
{
TRACE1("Warning:
Dynamic create of frame %hs failed./n",
m_pFrameClass->m_lpszClassName);
return
NULL;
}
ASSERT_KINDOF(CFrameWnd,
pFrame);
if
(context.m_pNewViewClass == NULL)
TRACE0("Warning:
creating frame with no default view./n");
//
create new from resource
if
(!pFrame->LoadFrame(m_nIDResource,
WS_OVERLAPPEDWINDOW
|
FWS_ADDTOTITLE, //
default frame styles
NULL,
&context))
{
TRACE0("Warning:
CDocTemplate couldn't create a frame./n");
//
frame will be deleted in PostNcDestroy
cleanup
return
NULL;
}
//
it worked !
return
pFrame;
}
6. BOOL
CDocument::OnNewDocument()
{
if
(IsModified())
TRACE0("Warning:
OnNewDocument replaces an unsaved
document./n");
DeleteContents();
m_strPathName.Empty(); //
no path name yet
SetModifiedFlag(FALSE); //
make clean
return
TRUE;
}
7. BOOL
CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
if
(IsModified())
TRACE0("Warning:
OnOpenDocument replaces an unsaved
document./n");
CFileException
fe;
CFile*
pFile = GetFile(lpszPathName,
CFile::modeRead|CFile::shareDenyWrite,
&fe);
if
(pFile == NULL)
{
ReportSaveLoadException(lpszPathName,
&fe,
FALSE,
AFX_IDP_FAILED_TO_OPEN_DOC);
return
FALSE;
}
DeleteContents();
SetModifiedFlag(); //
dirty during de-serialize
CArchive loadArchive(pFile,
CArchive::load |
CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument
= this;
loadArchive.m_bForceFlat
= FALSE;
TRY
{
CWaitCursor
wait;
if
(pFile->GetLength() != 0)
Serialize(loadArchive); //
load me
loadArchive.Close();
ReleaseFile(pFile,
FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile,
TRUE);
DeleteContents(); //
remove failed contents
TRY
{
ReportSaveLoadException(lpszPathName,
e,
FALSE,
AFX_IDP_FAILED_TO_OPEN_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return
FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); //
start off with unmodified
return
TRUE;
}
8. 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);
LPCTSTR
lpszTitle = m_strTitle;
if
(!Create(lpszClass, lpszTitle,
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;
}
9. void DocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument*
pDoc,BOOL bMakeVisible)
{
//
just delagate to implementation in
CFrameWnd
pFrame->InitialUpdateFrame(pDoc,
bMakeVisible);
}
10. void CFrameWnd::InitialUpdateFrame(CDocument*
pDoc, BOOL bMakeVisible)
{
//
if the frame does not have an active view, set to first
pane
CView*
pView = NULL;
if
(GetActiveView() == NULL)
{
CWnd*
pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST,
TRUE);
if
(pWnd != NULL &&
pWnd->IsKindOf(RUNTIME_CLASS(CView)))
{
pView
= (CView*)pWnd;
SetActiveView(pView,
FALSE);
}
}
if
(bMakeVisible)
{
//
send initial update to all views (and other controls) in the
frame
SendMessageToDescendants(WM_INITIALUPDATE,
0, 0, TRUE, TRUE);
//
give view a chance to save the focus (CFormView needs
this)
if
(pView != NULL)
pView->OnActivateFrame(WA_INACTIVE,
this);
//
finally, activate the frame
//
(send the default show command unless the main desktop
window)
int
nCmdShow =
-1; //
default
CWinApp*
pApp = AfxGetApp();
if
(pApp != NULL && pApp->m_pMainWnd ==
this)
{
nCmdShow
= pApp->m_nCmdShow; // use the parameter from
WinMain
pApp->m_nCmdShow
= -1; // set to default after first time
}
ActivateFrame(nCmdShow);
if
(pView != NULL)
pView->OnActivateView(TRUE,
pView, pView);
}
//
update frame counts and frame title (may already have been
visible)
if
(pDoc != NULL)
pDoc->UpdateFrameCounts();
OnUpdateFrameTitle(TRUE);
}
B) OnFileOpen()执行过程分析
11. void CWinApp::OnFileOpen()
{
ASSERT(m_pDocManager
!= NULL);
m_pDocManager->OnFileOpen();
}
12. void CDocManager::OnFileOpen()
{
//
prompt the user (with all document
templates)
CString
newName;
if
(!DoPromptFileName(newName,
AFX_IDS_OPENFILE,
OFN_HIDEREADONLY
| OFN_FILEMUSTEXIST, TRUE, NULL))
return;
// open cancelled
AfxGetApp()->OpenDocumentFile(newName);
//
if returns NULL, the user has already been
alerted
}
13. CDocument* CWinApp::OpenDocumentFile(LPCTSTR
lpszFileName)
{
ASSERT(m_pDocManager
!= NULL);
return
m_pDocManager->OpenDocumentFile(lpszFileName);
}
14. CDocument* CDocManager::OpenDocumentFile(LPCTSTR
lpszFileName)
{
//
find the highest confidence
POSITION
pos = m_templateList.GetHeadPosition();
CDocTemplate::Confidence
bestMatch = CDocTemplate::noAttempt;
CDocTemplate*
pBestTemplate = NULL;
CDocument*
pOpenDocument = NULL;
TCHAR
szPath[_MAX_PATH];
ASSERT(lstrlen(lpszFileName)
< _countof(szPath));
TCHAR
szTemp[_MAX_PATH];
if
(lpszFileName[0] == '/"')
++lpszFileName;
lstrcpyn(szTemp,
lpszFileName, _MAX_PATH);
LPTSTR
lpszLast = _tcsrchr(szTemp, '/"');
if
(lpszLast != NULL)
*lpszLast
= 0;
AfxFullPath(szPath,
szTemp);
TCHAR
szLinkName[_MAX_PATH];
if
(AfxResolveShortcut(AfxGetMainWnd(), szPath, szLinkName,
_MAX_PATH))
lstrcpy(szPath,
szLinkName);
while
(pos != NULL)
{
CDocTemplate*
pTemplate =
(CDocTemplate*)m_templateList.GetNext(pos);
ASSERT_KINDOF(CDocTemplate,
pTemplate);
CDocTemplate::Confidence
match;
ASSERT(pOpenDocument
== NULL);
match
= pTemplate->MatchDocType(szPath,
pOpenDocument);
if
(match > bestMatch)
{
bestMatch
= match;
pBestTemplate
= pTemplate;
}
if
(match == CDocTemplate::yesAlreadyOpen)
break; //
stop here
}
if
(pOpenDocument != NULL)
{
POSITION
pos =
pOpenDocument->GetFirstViewPosition();
if
(pos != NULL)
{
CView*
pView = pOpenDocument->GetNextView(pos); // get first
one
ASSERT_VALID(pView);
CFrameWnd*
pFrame = pView->GetParentFrame();
if
(pFrame != NULL)
pFrame->ActivateFrame();
else
TRACE0("Error:
Can not find a frame for document to
activate./n");
CFrameWnd*
pAppFrame;
if
(pFrame != (pAppFrame =
(CFrameWnd*)AfxGetApp()->m_pMainWnd))
{
ASSERT_KINDOF(CFrameWnd,
pAppFrame);
pAppFrame->ActivateFrame();
}
}
else
{
TRACE0("Error:
Can not find a view for document to
activate./n");
}
return
pOpenDocument;
}
if
(pBestTemplate == NULL)
{
AfxMessageBox(AFX_IDP_FAILED_TO_OPEN_DOC);
return
NULL;
}
return pBestTemplate->OpenDocumentFile(szPath);
}
15. CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL
bMakeVisible)
{
CDocument*
pDocument = CreateNewDocument();
if
(pDocument == NULL)
{
TRACE0("CDocTemplate::CreateNewDocument
returned NULL./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
TRACE0("CDocument::OnNewDocument
returned FALSE./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
TRACE0("CDocument::OnOpenDocument
returned FALSE./n");
pFrame->DestroyWindow();
return
NULL;
}
pDocument->SetPathName(lpszPathName);
}
InitialUpdateFrame(pFrame,
pDocument, bMakeVisible);
return
pDocument;
}
16. CDocument* CDocTemplate::CreateNewDocument()
{
//
default implementation constructs one from
CRuntimeClass
if
(m_pDocClass == NULL)
{
TRACE0("Error:
you must override
CDocTemplate::CreateNewDocument./n");
ASSERT(FALSE);
return
NULL;
}
CDocument*
pDocument =
(CDocument*)m_pDocClass->CreateObject();
if
(pDocument == NULL)
{
TRACE1("Warning:
Dynamic create of document type %hs
failed./n",
m_pDocClass->m_lpszClassName);
return
NULL;
}
ASSERT_KINDOF(CDocument,
pDocument);
AddDocument(pDocument);
return
pDocument;
}
17. 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;
context.m_pCurrentDoc
= pDoc;
context.m_pNewViewClass
= m_pViewClass;
context.m_pNewDocTemplate
= this;
if
(m_pFrameClass == NULL)
{
TRACE0("Error:
you must override
CDocTemplate::CreateNewFrame./n");
ASSERT(FALSE);
return
NULL;
}
CFrameWnd*
pFrame =
(CFrameWnd*)m_pFrameClass->CreateObject();
if
(pFrame == NULL)
{
TRACE1("Warning:
Dynamic create of frame %hs failed./n",
m_pFrameClass->m_lpszClassName);
return
NULL;
}
ASSERT_KINDOF(CFrameWnd,
pFrame);
if
(context.m_pNewViewClass == NULL)
TRACE0("Warning:
creating frame with no default view./n");
//
create new from resource
if
(!pFrame->LoadFrame(m_nIDResource,
WS_OVERLAPPEDWINDOW
|
FWS_ADDTOTITLE, //
default frame styles
NULL,
&context))
{
TRACE0("Warning:
CDocTemplate couldn't create a frame./n");
//
frame will be deleted in PostNcDestroy
cleanup
return
NULL;
}
//
it worked !
return
pFrame;
}
18. BOOL CDocument::OnNewDocument()
{
if
(IsModified())
TRACE0("Warning:
OnNewDocument replaces an unsaved
document./n");
DeleteContents();
m_strPathName.Empty(); //
no path name yet
SetModifiedFlag(FALSE); //
make clean
return
TRUE;
}
19. BOOL CDocument::OnOpenDocument(LPCTSTR
lpszPathName)
{
if
(IsModified())
TRACE0("Warning:
OnOpenDocument replaces an unsaved
document./n");
CFileException
fe;
CFile*
pFile = GetFile(lpszPathName,
CFile::modeRead|CFile::shareDenyWrite,
&fe);
if
(pFile == NULL)
{
ReportSaveLoadException(lpszPathName,
&fe,
FALSE,
AFX_IDP_FAILED_TO_OPEN_DOC);
return
FALSE;
}
DeleteContents();
SetModifiedFlag(); //
dirty during de-serialize
CArchive
loadArchive(pFile, CArchive::load |
CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument
= this;
loadArchive.m_bForceFlat
= FALSE;
TRY
{
CWaitCursor
wait;
if
(pFile->GetLength() != 0)
Serialize(loadArchive); //
load me
loadArchive.Close();
ReleaseFile(pFile,
FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile,
TRUE);
DeleteContents(); //
remove failed contents
TRY
{
ReportSaveLoadException(lpszPathName,
e,
FALSE,
AFX_IDP_FAILED_TO_OPEN_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return
FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); //
start off with unmodified
return
TRUE;
}
20. void DocTemplate::InitialUpdateFrame(CFrameWnd* pFrame,
CDocument* pDoc,BOOL bMakeVisible)
{
//
just delagate to implementation in
CFrameWnd
pFrame->InitialUpdateFrame(pDoc,
bMakeVisible);
}
21. void
CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL
bMakeVisible)
{
//
if the frame does not have an active view, set to first
pane
CView*
pView = NULL;
if
(GetActiveView() == NULL)
{
CWnd*
pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST,
TRUE);
if
(pWnd != NULL &&
pWnd->IsKindOf(RUNTIME_CLASS(CView)))
{
pView
= (CView*)pWnd;
SetActiveView(pView,
FALSE);
}
}
if
(bMakeVisible)
{
//
send initial update to all views (and other controls) in the
frame
SendMessageToDescendants(WM_INITIALUPDATE,
0, 0, TRUE, TRUE);
//
give view a chance to save the focus (CFormView needs
this)
if
(pView != NULL)
pView->OnActivateFrame(WA_INACTIVE,
this);
//
finally, activate the frame
//
(send the default show command unless the main desktop
window)
int
nCmdShow =
-1; //
default
CWinApp*
pApp = AfxGetApp();
if
(pApp != NULL && pApp->m_pMainWnd ==
this)
{
nCmdShow
= pApp->m_nCmdShow; // use the parameter from
WinMain
pApp->m_nCmdShow
= -1; // set to default after first time
}
ActivateFrame(nCmdShow);
if
(pView != NULL)
pView->OnActivateView(TRUE,
pView, pView);
}
//
update frame counts and frame title (may already have been
visible)
if
(pDoc != NULL)
pDoc->UpdateFrameCounts();
OnUpdateFrameTitle(TRUE);
}
加载中,请稍候......