目标:找到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。找到了!!!