MFC SDI应用程序的启动顺序
来源:互联网 发布:软件行业销售招聘 编辑:程序博客网 时间:2024/05/21 07:58
跟踪了MFC SDI应用程序的源代码,搞清了其启动顺序
初始化工作:
void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)
...{
if (m_pDocManager == NULL)
m_pDocManager = new CDocManager;
m_pDocManager->AddDocTemplate(pTemplate);
}
void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
...{
if (pTemplate == NULL)
...{
if (pStaticList != NULL)
...{
POSITION pos = pStaticList->GetHeadPosition();
while (pos != NULL)
...{
CDocTemplate* pTemplate =
(CDocTemplate*)pStaticList->GetNext(pos);
AddDocTemplate(pTemplate);
}
delete pStaticList;
pStaticList = NULL;
}
bStaticInit = FALSE;
}
else
...{
ASSERT_VALID(pTemplate);
ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);// must not be in list
pTemplate->LoadTemplate();
m_templateList.AddTail(pTemplate);
}
}
POSITION CPtrList::AddTail(void* newElement)
...{
ASSERT_VALID(this);
CNode* pNewNode = NewNode(m_pNodeTail, NULL);
pNewNode->data = newElement;
if (m_pNodeTail != NULL)
m_pNodeTail->pNext = pNewNode;
else
m_pNodeHead = pNewNode;
m_pNodeTail = pNewNode;
return (POSITION) pNewNode;
}
class CNewTypeDlg : public CDialog
...{
protected:
CPtrList* m_pList; // actually a list of doc templates
public:
CDocTemplate* m_pSelectedTemplate;
public:
//{{AFX_DATA(CNewTypeDlg)
enum ...{ IDD = AFX_IDD_NEWTYPEDLG };
//}}AFX_DATA
CNewTypeDlg(CPtrList* pList) : CDialog(CNewTypeDlg::IDD)
...{
m_pList = pList;
m_pSelectedTemplate = NULL;
}
~CNewTypeDlg() ...{ }
protected:
BOOL OnInitDialog();
void OnOK();
//{{AFX_MSG(CNewTypeDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
POSITION CPtrList::Find(void* searchValue, POSITION startAfter) const
...{
ASSERT_VALID(this);
CNode* pNode = (CNode*) startAfter;
if (pNode == NULL)
...{
pNode = m_pNodeHead; // start at head
}
else
...{
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
pNode = pNode->pNext; // start after the one specified
}
for (; pNode != NULL; pNode = pNode->pNext)
if (pNode->data == searchValue)
return (POSITION) pNode;
return NULL;
}
Step1:
BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)
...{
BOOL bResult = TRUE;
switch (rCmdInfo.m_nShellCommand)
...{
case CCommandLineInfo::FileNew:
if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
OnFileNew();
if (m_pMainWnd == NULL)
bResult = FALSE;
break;
// If we've been asked to open a file, call OpenDocumentFile()
case CCommandLineInfo::FileOpen:
if (!OpenDocumentFile(rCmdInfo.m_strFileName))
bResult = FALSE;
break;
// If the user wanted to print, hide our main window and
// fire a message to ourselves to start the printing
case CCommandLineInfo::FilePrintTo:
case CCommandLineInfo::FilePrint:
m_nCmdShow = SW_HIDE;
ASSERT(m_pCmdInfo == NULL);
OpenDocumentFile(rCmdInfo.m_strFileName);
m_pCmdInfo = &rCmdInfo;
m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);
m_pCmdInfo = NULL;
bResult = FALSE;
break;
// If we're doing DDE, hide ourselves
case CCommandLineInfo::FileDDE:
m_pCmdInfo = (CCommandLineInfo*)m_nCmdShow;
m_nCmdShow = SW_HIDE;
break;
// If we've been asked to unregister, unregister and then terminate
case CCommandLineInfo::AppUnregister:
...{
UnregisterShellFileTypes();
BOOL bUnregistered = Unregister();
// if you specify /EMBEDDED, we won't make an success/failure box
// this use of /EMBEDDED is not related to OLE
if (!rCmdInfo.m_bRunEmbedded)
...{
if (bUnregistered)
AfxMessageBox(AFX_IDP_UNREG_DONE);
else
AfxMessageBox(AFX_IDP_UNREG_FAILURE);
}
bResult = FALSE; // that's all we do
// If nobody is using it already, we can use it.
// We'll flag that we're unregistering and not save our state
// on the way out. This new object gets deleted by the
// app object destructor.
if (m_pCmdInfo == NULL)
...{
m_pCmdInfo = new CCommandLineInfo;
m_pCmdInfo->m_nShellCommand= CCommandLineInfo::AppUnregister;
}
}
break;
}
return bResult;
}
Step2:
void CWinApp::OnFileNew()
...{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}//m_pDocManager是CWinApp类的CDocManager类型的成员函数,管理应用程序的文档模板列表
Step3:
void CDocManager::OnFileNew()
...{
if (m_templateList.IsEmpty())
...{
TRACE0("Error: no document templates registered with CWinApp. ");
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
}
Step4:
CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)
// if lpszPathName == NULL => create new file of this type
...{
CDocument* pDocument = NULL;
CFrameWnd* pFrame = NULL;
BOOL bCreated = FALSE; // => doc and frame created
BOOL bWasModified = FALSE;
if (m_pOnlyDoc != NULL)
...{
// already have a document - reinit it
pDocument = m_pOnlyDoc;
if (!pDocument->SaveModified())
return NULL; // leave the original one
pFrame = (CFrameWnd*)AfxGetMainWnd();
ASSERT(pFrame != NULL);
ASSERT_KINDOF(CFrameWnd, pFrame);
ASSERT_VALID(pFrame);
}
else
...{
// create a new document
pDocument= CreateNewDocument();
ASSERT(pFrame == NULL); // will be created below
bCreated = TRUE;
}
if (pDocument == NULL)
...{
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
return NULL;
}
ASSERT(pDocument == m_pOnlyDoc);
if (pFrame == NULL)
...{
ASSERT(bCreated);
// create frame - set as main document frame
BOOL bAutoDelete = pDocument->m_bAutoDelete;
pDocument->m_bAutoDelete = FALSE;
// don't destroy if something goes wrong
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;
}
}
if (lpszPathName == NULL)
...{
// create a new document
SetDefaultTitle(pDocument);
// avoid creating temporary compound file when starting up invisible
if (!bMakeVisible)
pDocument->m_bEmbedded = TRUE;
if (!pDocument->OnNewDocument())
...{
// user has been alerted to what failed in OnNewDocument
TRACE0("CDocument::OnNewDocument returned FALSE. ");
if (bCreated)
pFrame->DestroyWindow(); // will destroy document
return NULL;
}
}
else
...{
CWaitCursor wait;
// open an existing document
bWasModified = pDocument->IsModified();
pDocument->SetModifiedFlag(FALSE); // not dirty for open
if (!pDocument->OnOpenDocument(lpszPathName))
...{
// user has been alerted to what failed in OnOpenDocument
TRACE0("CDocument::OnOpenDocument returned FALSE. ");
if (bCreated)
...{
pFrame->DestroyWindow(); // will destroy document
}
else if (!pDocument->IsModified())
...{
// original document is untouched
pDocument->SetModifiedFlag(bWasModified);
}
else
...{
// we corrupted the original document
SetDefaultTitle(pDocument);
if (!pDocument->OnNewDocument())
...{
TRACE0("Error: OnNewDocument failed after trying to open a document - trying to continue. ");
// assume we can continue
}
}
return NULL; // open failed
}
pDocument->SetPathName(lpszPathName);
}
CWinThread* pThread = AfxGetThread();
if (bCreated && pThread->m_pMainWnd == NULL)
...{
// set as main frame (InitialUpdateFrame will show the window)
pThread->m_pMainWnd = pFrame;
}
InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
return pDocument;
}//OpemDocumentFile是CDocTemplate类的虚函数
Step5:
第一步:创建文档对象
CDocument* CDocTemplate::CreateNewDocument()
...{
// default implementation constructs one from CRuntimeClass
if (m_pDocClass == NULL)
...{
TRACE0("Error: you must override CDocTemplate::CreateNewDocument. ");
ASSERT(FALSE);
return NULL;
}
CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();
if (pDocument == NULL)
...{
TRACE1("Warning: Dynamic create of document type %hs failed. ",
m_pDocClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CDocument, pDocument);
AddDocument(pDocument);
return pDocument;
}
第二步:创建边框窗口
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. ");
ASSERT(FALSE);
return NULL;
}
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
if (pFrame == NULL)
...{
TRACE1("Warning: Dynamic create of frame %hs failed. ",
m_pFrameClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CFrameWnd, pFrame);
if (context.m_pNewViewClass == NULL)
TRACE0("Warning: creating frame with no default view. ");
// 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. ");
// frame will be deleted in PostNcDestroy cleanup
return NULL;
}
// it worked !
return pFrame;
}
Step6:
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;
}//LoadFrame注册了两个“窗口类”,一个为边框窗口,一个为视窗口,LoadFrame调用了CFrameWnd类的Create函数
Step7:
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)
...{
TRACE0("Warning: failed to load menu for CFrameWnd. ");
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))
...{
TRACE0("Warning: failed to create CFrameWnd. ");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
return TRUE;
}
Step8:
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);
(注: 此函数调用函数::SetWindowsHookEx,SetWindowsHookEx安装了一个WH_CBT类型的钩子,在调用CreateWindowEx时(在CreateWindowEx返回之前)窗口会发送WM_CREATE、 WM_NCCREATE等消息,钩子过程CBTProc会在窗口消息WM_CREATE、 WM_NCCREATE等发送前被调用,并提前得到窗口的句柄值。钩子过程CBTProc的任务是把窗口句柄赋给窗口对象(CWnd::m_hWnd),并调用SetWindowLong把窗口过程替换成AfxWndProc(如是控件还要保留原窗口过程,用CallWindowProc进行默认处理)。)
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)
...{
TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X ",
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;
}
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) && afxData.bWin4)
cs.style |= FWS_PREFIXTITLE;
if (afxData.bWin4)
cs.dwExStyle |= WS_EX_CLIENTEDGE;
return TRUE;}//发送WM_CREATE消息,从而创建视对象和视窗口
Step9:
int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)
...{
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;
return OnCreateHelper(lpcs, pContext);
}
Step10:
int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)
...{
if (CWnd::OnCreate(lpcs) == -1)
return -1;
// create special children first
if (!OnCreateClient(lpcs, pContext))
...{
TRACE0("Failed to create client pane/view for frame. ");
return -1;
}
// post message for initial message string
PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
// make sure the child windows have been properly sized
RecalcLayout();
return 0; // create ok
}
Step11:
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)
...{
// default create client will create a view if asked for it
if (pContext != NULL && pContext->m_pNewViewClass != NULL)
...{
if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL) return FALSE;
}
return TRUE;
}
Step12:
CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
...{
ASSERT(m_hWnd != NULL);
ASSERT(::IsWindow(m_hWnd));
ASSERT(pContext != NULL);
ASSERT(pContext->m_pNewViewClass != NULL);
// Note: can be a CWnd with PostNcDestroy self cleanup
CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
if (pView == NULL)
...{
TRACE1("Warning: Dynamic create of view type %hs failed. ",
pContext->m_pNewViewClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CWnd, pView);
// views are always created with a border!
if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0,0,0,0), this, nID, pContext))
...{
TRACE0("Warning: could not create view for frame. ");
return NULL; // can't continue without a view
}
if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))
...{
// remove the 3d style from the frame, since the view is
// providing it.
// make sure to recalc the non-client area
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
}
return pView;
}
void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)
...{
if (m_pDocManager == NULL)
m_pDocManager = new CDocManager;
m_pDocManager->AddDocTemplate(pTemplate);
}
void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
...{
if (pTemplate == NULL)
...{
if (pStaticList != NULL)
...{
POSITION pos = pStaticList->GetHeadPosition();
while (pos != NULL)
...{
CDocTemplate* pTemplate =
(CDocTemplate*)pStaticList->GetNext(pos);
AddDocTemplate(pTemplate);
}
delete pStaticList;
pStaticList = NULL;
}
bStaticInit = FALSE;
}
else
...{
ASSERT_VALID(pTemplate);
ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);// must not be in list
pTemplate->LoadTemplate();
m_templateList.AddTail(pTemplate);
}
}
POSITION CPtrList::AddTail(void* newElement)
...{
ASSERT_VALID(this);
CNode* pNewNode = NewNode(m_pNodeTail, NULL);
pNewNode->data = newElement;
if (m_pNodeTail != NULL)
m_pNodeTail->pNext = pNewNode;
else
m_pNodeHead = pNewNode;
m_pNodeTail = pNewNode;
return (POSITION) pNewNode;
}
class CNewTypeDlg : public CDialog
...{
protected:
CPtrList* m_pList; // actually a list of doc templates
public:
CDocTemplate* m_pSelectedTemplate;
public:
//{{AFX_DATA(CNewTypeDlg)
enum ...{ IDD = AFX_IDD_NEWTYPEDLG };
//}}AFX_DATA
CNewTypeDlg(CPtrList* pList) : CDialog(CNewTypeDlg::IDD)
...{
m_pList = pList;
m_pSelectedTemplate = NULL;
}
~CNewTypeDlg() ...{ }
protected:
BOOL OnInitDialog();
void OnOK();
//{{AFX_MSG(CNewTypeDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
POSITION CPtrList::Find(void* searchValue, POSITION startAfter) const
...{
ASSERT_VALID(this);
CNode* pNode = (CNode*) startAfter;
if (pNode == NULL)
...{
pNode = m_pNodeHead; // start at head
}
else
...{
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
pNode = pNode->pNext; // start after the one specified
}
for (; pNode != NULL; pNode = pNode->pNext)
if (pNode->data == searchValue)
return (POSITION) pNode;
return NULL;
}
Step1:
BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)
...{
BOOL bResult = TRUE;
switch (rCmdInfo.m_nShellCommand)
...{
case CCommandLineInfo::FileNew:
if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
OnFileNew();
if (m_pMainWnd == NULL)
bResult = FALSE;
break;
// If we've been asked to open a file, call OpenDocumentFile()
case CCommandLineInfo::FileOpen:
if (!OpenDocumentFile(rCmdInfo.m_strFileName))
bResult = FALSE;
break;
// If the user wanted to print, hide our main window and
// fire a message to ourselves to start the printing
case CCommandLineInfo::FilePrintTo:
case CCommandLineInfo::FilePrint:
m_nCmdShow = SW_HIDE;
ASSERT(m_pCmdInfo == NULL);
OpenDocumentFile(rCmdInfo.m_strFileName);
m_pCmdInfo = &rCmdInfo;
m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);
m_pCmdInfo = NULL;
bResult = FALSE;
break;
// If we're doing DDE, hide ourselves
case CCommandLineInfo::FileDDE:
m_pCmdInfo = (CCommandLineInfo*)m_nCmdShow;
m_nCmdShow = SW_HIDE;
break;
// If we've been asked to unregister, unregister and then terminate
case CCommandLineInfo::AppUnregister:
...{
UnregisterShellFileTypes();
BOOL bUnregistered = Unregister();
// if you specify /EMBEDDED, we won't make an success/failure box
// this use of /EMBEDDED is not related to OLE
if (!rCmdInfo.m_bRunEmbedded)
...{
if (bUnregistered)
AfxMessageBox(AFX_IDP_UNREG_DONE);
else
AfxMessageBox(AFX_IDP_UNREG_FAILURE);
}
bResult = FALSE; // that's all we do
// If nobody is using it already, we can use it.
// We'll flag that we're unregistering and not save our state
// on the way out. This new object gets deleted by the
// app object destructor.
if (m_pCmdInfo == NULL)
...{
m_pCmdInfo = new CCommandLineInfo;
m_pCmdInfo->m_nShellCommand= CCommandLineInfo::AppUnregister;
}
}
break;
}
return bResult;
}
Step2:
void CWinApp::OnFileNew()
...{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}//m_pDocManager是CWinApp类的CDocManager类型的成员函数,管理应用程序的文档模板列表
Step3:
void CDocManager::OnFileNew()
...{
if (m_templateList.IsEmpty())
...{
TRACE0("Error: no document templates registered with CWinApp. ");
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
}
Step4:
CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)
// if lpszPathName == NULL => create new file of this type
...{
CDocument* pDocument = NULL;
CFrameWnd* pFrame = NULL;
BOOL bCreated = FALSE; // => doc and frame created
BOOL bWasModified = FALSE;
if (m_pOnlyDoc != NULL)
...{
// already have a document - reinit it
pDocument = m_pOnlyDoc;
if (!pDocument->SaveModified())
return NULL; // leave the original one
pFrame = (CFrameWnd*)AfxGetMainWnd();
ASSERT(pFrame != NULL);
ASSERT_KINDOF(CFrameWnd, pFrame);
ASSERT_VALID(pFrame);
}
else
...{
// create a new document
pDocument= CreateNewDocument();
ASSERT(pFrame == NULL); // will be created below
bCreated = TRUE;
}
if (pDocument == NULL)
...{
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
return NULL;
}
ASSERT(pDocument == m_pOnlyDoc);
if (pFrame == NULL)
...{
ASSERT(bCreated);
// create frame - set as main document frame
BOOL bAutoDelete = pDocument->m_bAutoDelete;
pDocument->m_bAutoDelete = FALSE;
// don't destroy if something goes wrong
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;
}
}
if (lpszPathName == NULL)
...{
// create a new document
SetDefaultTitle(pDocument);
// avoid creating temporary compound file when starting up invisible
if (!bMakeVisible)
pDocument->m_bEmbedded = TRUE;
if (!pDocument->OnNewDocument())
...{
// user has been alerted to what failed in OnNewDocument
TRACE0("CDocument::OnNewDocument returned FALSE. ");
if (bCreated)
pFrame->DestroyWindow(); // will destroy document
return NULL;
}
}
else
...{
CWaitCursor wait;
// open an existing document
bWasModified = pDocument->IsModified();
pDocument->SetModifiedFlag(FALSE); // not dirty for open
if (!pDocument->OnOpenDocument(lpszPathName))
...{
// user has been alerted to what failed in OnOpenDocument
TRACE0("CDocument::OnOpenDocument returned FALSE. ");
if (bCreated)
...{
pFrame->DestroyWindow(); // will destroy document
}
else if (!pDocument->IsModified())
...{
// original document is untouched
pDocument->SetModifiedFlag(bWasModified);
}
else
...{
// we corrupted the original document
SetDefaultTitle(pDocument);
if (!pDocument->OnNewDocument())
...{
TRACE0("Error: OnNewDocument failed after trying to open a document - trying to continue. ");
// assume we can continue
}
}
return NULL; // open failed
}
pDocument->SetPathName(lpszPathName);
}
CWinThread* pThread = AfxGetThread();
if (bCreated && pThread->m_pMainWnd == NULL)
...{
// set as main frame (InitialUpdateFrame will show the window)
pThread->m_pMainWnd = pFrame;
}
InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
return pDocument;
}//OpemDocumentFile是CDocTemplate类的虚函数
Step5:
第一步:创建文档对象
CDocument* CDocTemplate::CreateNewDocument()
...{
// default implementation constructs one from CRuntimeClass
if (m_pDocClass == NULL)
...{
TRACE0("Error: you must override CDocTemplate::CreateNewDocument. ");
ASSERT(FALSE);
return NULL;
}
CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();
if (pDocument == NULL)
...{
TRACE1("Warning: Dynamic create of document type %hs failed. ",
m_pDocClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CDocument, pDocument);
AddDocument(pDocument);
return pDocument;
}
第二步:创建边框窗口
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. ");
ASSERT(FALSE);
return NULL;
}
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
if (pFrame == NULL)
...{
TRACE1("Warning: Dynamic create of frame %hs failed. ",
m_pFrameClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CFrameWnd, pFrame);
if (context.m_pNewViewClass == NULL)
TRACE0("Warning: creating frame with no default view. ");
// 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. ");
// frame will be deleted in PostNcDestroy cleanup
return NULL;
}
// it worked !
return pFrame;
}
Step6:
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;
}//LoadFrame注册了两个“窗口类”,一个为边框窗口,一个为视窗口,LoadFrame调用了CFrameWnd类的Create函数
Step7:
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)
...{
TRACE0("Warning: failed to load menu for CFrameWnd. ");
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))
...{
TRACE0("Warning: failed to create CFrameWnd. ");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
return TRUE;
}
Step8:
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);
(注: 此函数调用函数::SetWindowsHookEx,SetWindowsHookEx安装了一个WH_CBT类型的钩子,在调用CreateWindowEx时(在CreateWindowEx返回之前)窗口会发送WM_CREATE、 WM_NCCREATE等消息,钩子过程CBTProc会在窗口消息WM_CREATE、 WM_NCCREATE等发送前被调用,并提前得到窗口的句柄值。钩子过程CBTProc的任务是把窗口句柄赋给窗口对象(CWnd::m_hWnd),并调用SetWindowLong把窗口过程替换成AfxWndProc(如是控件还要保留原窗口过程,用CallWindowProc进行默认处理)。)
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)
...{
TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X ",
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;
}
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) && afxData.bWin4)
cs.style |= FWS_PREFIXTITLE;
if (afxData.bWin4)
cs.dwExStyle |= WS_EX_CLIENTEDGE;
return TRUE;}//发送WM_CREATE消息,从而创建视对象和视窗口
Step9:
int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)
...{
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;
return OnCreateHelper(lpcs, pContext);
}
Step10:
int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)
...{
if (CWnd::OnCreate(lpcs) == -1)
return -1;
// create special children first
if (!OnCreateClient(lpcs, pContext))
...{
TRACE0("Failed to create client pane/view for frame. ");
return -1;
}
// post message for initial message string
PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
// make sure the child windows have been properly sized
RecalcLayout();
return 0; // create ok
}
Step11:
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)
...{
// default create client will create a view if asked for it
if (pContext != NULL && pContext->m_pNewViewClass != NULL)
...{
if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL) return FALSE;
}
return TRUE;
}
Step12:
CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
...{
ASSERT(m_hWnd != NULL);
ASSERT(::IsWindow(m_hWnd));
ASSERT(pContext != NULL);
ASSERT(pContext->m_pNewViewClass != NULL);
// Note: can be a CWnd with PostNcDestroy self cleanup
CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
if (pView == NULL)
...{
TRACE1("Warning: Dynamic create of view type %hs failed. ",
pContext->m_pNewViewClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CWnd, pView);
// views are always created with a border!
if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0,0,0,0), this, nID, pContext))
...{
TRACE0("Warning: could not create view for frame. ");
return NULL; // can't continue without a view
}
if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))
...{
// remove the 3d style from the frame, since the view is
// providing it.
// make sure to recalc the non-client area
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
}
return pView;
}
- MFC SDI应用程序的启动顺序
- MFC SDI应用程序的启动顺序
- Visual C++中SDI应用程序启动顺序
- 定制MFC SDI应用程序外观
- MFC的SDI程序的用户命令的处理顺序
- MFC的SDI程序的用户命令的处理顺序
- 创建无边框的MFC单文档(SDI)应用程序
- MFC应用程序的处理顺序
- MFC SDI单文档应用程序贴图
- C++--MFC的SDI程序的用户命令的处理顺序
- C++--MFC的SDI程序的用户命令的处理顺序
- MFC应用程序中处理消息的顺序
- MFC应用程序中处理消息的顺序
- MFC应用程序中处理消息的顺序
- MFC应用程序中处理消息的顺序
- MFC应用程序中处理消息的顺序
- MFC应用程序中处理消息的顺序
- MFC 应用程序中处理消息的顺序
- showModalDialog和showModelessDialog
- 全选和全不选checkboxList
- package 与 import
- 清空SELECT的OPTION
- C#判断一个string是否为数字
- MFC SDI应用程序的启动顺序
- 应用ActionScript对放大镜的继续改进
- Dom4j递归解析XML实现JS的getElementsByName类似方法
- 学习CSS优化的十八项技巧
- 安装oracle10g
- 《JavaScript高级程序设计》学习笔记(表格排序)
- 鼠标滚轮缩放图片javascript
- JS操作select相关方法:新增 修改 删除 选中 清空 判断存在 等
- 类似msn的提示效果代码系列一:简单的脚本提示