您的位置:首页 > 产品设计 > 产品经理

探索MFC中单文档中m_pMainWnd的初始化过程

2013-10-03 11:51 337 查看
目标:找到m_pMainWnd的赋值的地方

m_pMainWnd

定义于 C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/include/afxwin.h

class CWinThread : public CCmdTarget
{

CWnd* m_pMainWnd;
// main window (usually same AfxGetApp()->m_pMainWnd)
}

绪:我的单文档DEMO

BOOL CtestApp::InitInstance()
{
InitCommonControls();
CWinApp::InitInstance();
AfxEnableControlContainer();
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CtestDoc),
RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CtestView));
AddDocTemplate(pDocTemplate);

CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
ProcessShellCommand(cmdInfo);

// 唯一的一个窗口已初始化,因此显示它并对其进行更新

m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();

// 仅当存在后缀时才调用 DragAcceptFiles

// 在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生

return TRUE;
}

MFC的主函数

Microsoft Visual Studio .NET 2003/Vc7/atlmfc/src/mfc/winmian.cpp

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
pApp->InitApplication();
pThread->InitInstance();
nReturnCode = pThread->Run();
AfxWinTerm();
return nReturnCode;
}

上面构造了 pThread ,pApp;其中pApp指向theApp

AfxGetApp 在AfxWin1.inl中

AfxGetThread在AfxWin.h中定义,实现于

C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/src/mfc/thrdcore.cpp

为了简化过程,上面的代码中的判断语句被我删掉了!

开始

第一步:

搜索到 m_pMainWnd 的赋值的地方

C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/src/mfc/docsingl.cpp

(1.1)
CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible)
{
............
if (bCreated && pThread->m_pMainWnd == NULL)
{
// set as main frame (InitialUpdateFrame will show the window)

pThread->m_pMainWnd = pFrame;
}
......................

}

C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/src/mfc/thrdcore.cpp

(1.2)
UINT APIENTRY _AfxThreadEntry(void* pParam)
{
if (pApp != NULL &&pThread->m_pMainWnd == NULL && pApp->m_pMainWnd->GetSafeHwnd() != NULL)
{
// just attach the HWND
threadWnd.Attach(pApp->m_pMainWnd->m_hWnd);
pThread->m_pMainWnd = &threadWnd;
}
}

初步估计,可能是在(1.1)中初始化。猜测理由:初始化的时候,可能需要打开一个默认的空文档。

第二步:

2.1 查找OpenDocumentFile调用的地方,
如果我的猜测方向没有错的话,那么在搜索到的文件中,应该是void CDocManager::OnFileNew()中调用的

void CDocManager::OnFileNew()
{
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
CNewTypeDlg dlg(&m_templateList);
INT_PTR nID = dlg.DoModal();
if (nID == IDOK)
pTemplate = dlg.m_pSelectedTemplate;
else

return; // none - cancel operation

pTemplate->OpenDocumentFile(NULL);

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

}
上述函数位于C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/src/mfc/docmgr.cpp中

2.2 接着找OnFileNew的调用地方。

这个可能比较多,具体什么地方调用的我还不敢估计;先全部找出来在说!

呵呵,很幸运,我在MFC目录下搜索,只有两个文件调用过这个函数;

C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/src/mfc/apppdlg.cpp

void CWinApp::OnFileNew()
{

if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}

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;
……...…………………………………………………………………..
}

OK ,找到了,CWinApp::ProcessShellCommand调用CWinApp::OnFileNew,CWinApp::OnFileNew调用
CDocManager::OnFileNew()

现在找到了什么地方初始化的m_pMainWnd,但是这个消息循环是怎么调用的呢?难道初始化的时候,一开始CCommandLineInfo::FileNew:就有这个消息?

2.3 再接再厉
C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/include/afxwin.h中有这个定义

enum { FileNew, FileOpen, FilePrint, FilePrintTo, FileDDE, AppRegister,AppUnregister, FileNothing = -1 } m_nShellCommand;

C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/atlmfc/include/appcore.cpp中有如下定义:

CCommandLineInfo 的构造函数如下:

CCommandLineInfo::CCommandLineInfo()
{
m_bShowSplash = TRUE;
m_bRunEmbedded = FALSE;
m_bRunAutomated = FALSE;
m_nShellCommand = FileNew;
}

void CWinApp::ParseCommandLine(CCommandLineInfo& rCmdInfo)
{
for (int i = 1; i < __argc; i++)
{
LPCTSTR pszParam = __targv[i];
BOOL bFlag = FALSE;
BOOL bLast = ((i + 1) == __argc);
if (pszParam[0] == '-' || pszParam[0] == '/')
{
// remove flag specifier
bFlag = TRUE;
++pszParam;
}
rCmdInfo.ParseParam(pszParam, bFlag, bLast);
}
}

OK,搞定了,在初始化的时候,就把rCmdInfo.m_nShellCommand的值赋为FileNew,那么在调用的时候就很自然的执行Switch中的第一个case了哈。

于是调用CWinApp::OnFileNew,在调用CDocManager::OnFileNew(),接着调用pTemplate->OpenDocumentFile(NULL);最后在这个函数中初始化了m_pMainWnd。找到了!!!


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: