黑夜传说1百度云:学习MFC框架如何创建的过程.CWnd::ProcessShellCommand.上部
来源:百度文库 编辑:九乡新闻网 时间:2024/05/06 05:24:03
系列快速导航:三要点
1、 CDocTemplate 学习MFC框架如何创建的过程.CDocTemplate
2、 CFrameWnd::LoadFrame 学习MFC框架如何创建的过程.LoadFrame
3、 CWnd::ProcessShellCommand
学习MFC框架如何创建的过程.CWnd::ProcessShellCommand.上部
学习MFC框架如何创建的过程.CWnd::ProcessShellCommand.下部
研究CWnd::ProcessShellCommand
第一个MDI子窗口是从这里面建立出来的,这实在是缺乏直观性。不过MFC就是这样,没办法。
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;
case CCommandLineInfo::FileOpen: // 忽略
case CCommandLineInfo::FilePrintTo: // 忽略
case CCommandLineInfo::FilePrint:
case CCommandLineInfo::FileDDE:
case CCommandLineInfo::AppRegister:
case CCommandLineInfo::AppUnregister:
}
return bResult;
}
进入到ProcessShellCommand,要处理很多种不同命令,我们忽略其它命令,单独看FileNew部分。
注意:实际进入到了AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)之中。
AfxGetApp()实际返回了CMDITestApp的唯一实例,它从CWinApp – CWinThread – CCmdTarget – CObject 派生而来。我们没有重载OnCmdMsg,所以进入到CCmdTarget的OnCmdMsg处理中。为了研究,我们删减了一些代码。
BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// 这里删减了一些代码
// determine the message number and code (packed into nCode)
const AFX_MSGMAP* pMessageMap;
const AFX_MSGMAP_ENTRY* lpEntry;
UINT nMsg = 0;
// 这里删减了一些代码,处理后 nMsg = WM_COMMAND
// 为了简化,删减了一些断言等。以下循环用于查找处理此消息的入口。
for (pMessageMap = GetMessageMap(); pMessageMap->pfnGetBaseMap != NULL;
pMessageMap = (*pMessageMap->pfnGetBaseMap)())
{
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
if (lpEntry != NULL)
{
// 找到了消息处理项入口,分发此消息。
return _AfxDispatchCmdMsg(this, nID, nCode,
lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
}
}
return FALSE; // 未找到则不处理
}
最终MFC很愉快地找到了一个入口项, CWinApp::OnFileNew(void) 要处理这个消息。继续进入到_AfxDispatchCmdMsg中去看看。
AFX_STATIC BOOL AFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode,
AFX_PMSG pfn, void* pExtra, UINT_PTR nSig, AFX_CMDHANDLERINFO* pHandlerInfo)
// return TRUE to stop routing
{
union MessageMapFunctions mmf;
mmf.pfn = pfn;
BOOL bResult = TRUE; // default is ok
if (pHandlerInfo != NULL)
{
// just fill in the information, don't do it
pHandlerInfo->pTarget = pTarget;
pHandlerInfo->pmf = mmf.pfn;
return TRUE;
}
switch (nSig)
{
case AfxSigCmd_v:
// normal command or control notification
ASSERT(CN_COMMAND == 0); // CN_COMMAND same as BN_CLICKED
ASSERT(pExtra == NULL);
(pTarget->*mmf.pfnCmd_v_v)(); // ? 实际调用 pTarget 指向的这个成员函数
break;
// 下面还有大量的多种 AfxSigCmd_xxx,忽略掉它们。
default: // illegal
ASSERT(FALSE); return 0; break;
}
return bResult;
}
其中 (pTarget->*mmf.pfn_Cmd_v_v)() 对CWinApp::OnFileNew() 产生调用,pTarget = CMDITestApp类实例。调用进入如下:
void CWinApp::OnFileNew()
{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}
进入进入到CDocManager::OnFileNew()
void CDocManager::OnFileNew()
{
if (m_templateList.IsEmpty())
// 提示没有模板并返回
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead(); // 第一个
if (m_templateList.GetCount() > 1)
// 弹出一个对话框(很难看的)提示用户选择一个文档模板
// 在这个例子里面,pTemplate 就是 CMDITestApp::InitInstance() 里面创建的那个模板
pTemplate->OpenDocumentFile(NULL);
}
在进入CMultiDocTemplate::OpenDocumentFile之前,我观察了一下调用堆栈,结果如下:
> mfc71d.dll!CDocManager::OnFileNew() 行852 C++
mfc71d.dll!CWinApp::OnFileNew() 行25 C++
mfc71d.dll!_AfxDispatchCmdMsg(CCmdTarget * pTarget=0x0042cae8, unsigned int nID=57600, int nCode=0, void (void)* pfn=0x0041153c, void * pExtra=0x00000000, unsigned int nSig=53, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) 行89 C++
mfc71d.dll!CCmdTarget::OnCmdMsg(unsigned int nID=57600, int nCode=0, void * pExtra=0x00000000, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) 行396 + 0x27 C++
mfc71d.dll!CWinApp::ProcessShellCommand(CCommandLineInfo & rCmdInfo={...}) 行27 + 0x1e C++
MDITest.exe!CMDITestApp::InitInstance() 行101 + 0xc C++
希望我还没有迷路:)
CMultiDocTemplate::OpenDocumentFile 又是很多很多代码,让我们选择一些。
CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)
{
// 以下代码删减了验证、断言部分
CDocument* pDocument = CreateNewDocument(); // 创建文档对象
CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL); // 创建框架窗口
if (lpszPathName == NULL)
{
pDocument->OnNewDocument(); // 初始化文档
}
else
// 打开已有文档
InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
return pDocument;
}
看一看CreateNewDocument()
CDocument* CDocTemplate::CreateNewDocument()
{
// default implementation constructs one from CRuntimeClass
if (m_pDocClass == NULL)
// 错误提示啦
// CRuntimeClass* m_pDocClass -> CreateObject 实例化文档类。
// 在此例子中既是 CMDITestDoc
CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();
AddDocument(pDocument); // 添加到模板里的文档列表,MultiDocTemplate 保存此一文档
return pDocument;
}