发布时间 : 星期六 文章深入浅出话VC++(2) - MFC的本质更新完毕开始阅读d5741c2a52d380eb62946d53
点,然后按F5再运行下该程序,将发现程序首先停在CSDIMFCApp类的构造函数处,然后进入到_tWinMain函数(该断点是我们之前设置的断点)。这里又引起另外一个疑问了——为什么程序会首先调用CSDIMFCApp的构造函数呢?既然构造函数被调用了,肯定定义了该类的一个对象,然后,我们可以发现在CSDIMFCApp类中,定义了一个
CSDIMFCApp类型的全局对象theApp,存在于SDIMFC.cpp文件中,具体定义代码如下:
// 唯一的一个 CSDIMFCApp 对象
CSDIMFCApp theApp; // 初始化对象,这种方式为调用类的无参数构造来初始化,所以会调用类的无参构造函数
然后我们在这个全局对象处设置一个断点,然后再按F5调试运行下该程序,你将发现程序执行的顺序为:theApp全局对象—>CSDIMFCApp构造函数(调用派生类的构造函数之前会调用其父类的构造函数)—>_tWinMain函数。在MFC程序中,theApp对象是用来唯一标识应用程序实例的,每个MFC程序有且仅有一个应用程序对象(这里为theApp对象)。
3.2 设计和注册窗口类
现在我们已经找到MFC中的WinMain函数了,根据前一专题的内容,接下来就是找到MFC应用程序中的窗口类和注册窗口类的代码,在上一专题中,窗口类和注册都是在WinMain函数中定义的,下面让我们看下MFC中WinMain函数都帮我们封装了什么,在MFC中的WinMain函数中只是简单对AfxWinMain函数进行调用,下面让我们看看AfxWinMain具体代码:
1 // AfxWinMain函数
2 int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 3 _In_ LPTSTR lpCmdLine, int nCmdShow) 4 {
5 ASSERT(hPrevInstance == NULL); 6
7 int nReturnCode = -1;
8 CWinThread* pThread = AfxGetThread(); 9 CWinApp* pApp = AfxGetApp(); 10
11 // AFX internal initialization
12 if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) 13 goto InitFailure; 14
15 // App global initializations (rare)
16 if (pApp != NULL && !pApp->InitApplication()) 17 goto InitFailure; 18
19 // Perform specific initializations 20 if (!pThread->InitInstance())
21 {
22 if (pThread->m_pMainWnd != NULL) 23 {
24 TRACE(traceAppMsg, 0, \m_pMainWnd\\n\);
25 pThread->m_pMainWnd->DestroyWindow(); 26 }
27 nReturnCode = pThread->ExitInstance(); 28 goto InitFailure; 29 }
// PThread->Run函数是完成消息循环任务的 30 nReturnCode = pThread->Run(); 31
32 InitFailure:
33 #ifdef _DEBUG
34 // Check for missing AfxLockTempMap calls
35 if (AfxGetModuleThreadState()->m_nTempMapLock != 0) 36 {
37 TRACE(traceAppMsg, 0, \(%ld).\\n\,
38 AfxGetModuleThreadState()->m_nTempMapLock); 39 }
40 AfxLockTempMaps(); 41 AfxUnlockTempMaps(-1); 42 #endif 43
44 AfxWinTerm(); 45 return nReturnCode; 46 }
上面代码首先调用AfxGetThread函数获得一个指向CWinThread类型的指针,然后再调用了AfxGetApp函数获得一个指向CWinApp类型的指针,再继续调用AfxWinInit函数进行AFX(以AFX为前缀的函数为应用程序框架函数,Application Framework)内部初始化,接着pApp调用InitApplication函数,该函数主要完成MFC内部管理方面的工作,该函数为虚函数,在CWinApp中的实现为(函数实现代码查找按照前面介绍的方式进行查看):
// 主要完成MFC内部管理工作 BOOL CWinApp::InitApplication() {
if (CDocManager::pStaticDocManager != NULL) {
if (m_pDocManager == NULL)
m_pDocManager = CDocManager::pStaticDocManager; CDocManager::pStaticDocManager = NULL; }
if (m_pDocManager != NULL)
m_pDocManager->AddDocTemplate(NULL); else
CDocManager::bStaticInit = FALSE;
LoadSysPolicies();
return TRUE; }
接着继续调用pThread的InitInstance函数,按F12可知,该函数声明为虚函数,根据类的多态性,这里AfxWinMain函数中调用的InitInstance函数为调用子类CSDIMFCApp的InitInstance函数,该函数的定义代码为:
1 / CSDIMFCApp 初始化
2 BOOL CSDIMFCApp::InitInstance() 3 {
4 // 如果一个运行在 Windows XP 上的应用程序清单指定要 5 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, 6 //则需要 InitCommonControlsEx()。否则,将无法创建窗口。 7 INITCOMMONCONTROLSEX InitCtrls; 8 InitCtrls.dwSize = sizeof(InitCtrls);
9 // 将它设置为包括所有要在应用程序中使用的 10 // 公共控件类。
11 InitCtrls.dwICC = ICC_WIN95_CLASSES; 12 InitCommonControlsEx(&InitCtrls); 13
14 CWinAppEx::InitInstance(); 15 16
17 // 初始化 OLE 库 18 if (!AfxOleInit()) 19 {
20 AfxMessageBox(IDP_OLE_INIT_FAILED); 21 return FALSE; 22 } 23
24 AfxEnableControlContainer(); 25
26 EnableTaskbarInteraction(FALSE); 27
28 // 使用 RichEdit 控件需要 AfxInitRichEdit2() 29 // AfxInitRichEdit2(); 30
31 // 标准初始化
32 // 如果未使用这些功能并希望减小
33 // 最终可执行文件的大小,则应移除下列 34 // 不需要的特定初始化例程 35 // 更改用于存储设置的注册表项 36 // TODO: 应适当修改该字符串, 37 // 例如修改为公司或组织名
38 SetRegistryKey(_T(\应用程序向导生成的本地应用程序\));
39 LoadStdProfileSettings(4); // 加载标准 INI 文件选项(包括 MRU) 40 41
42 InitContextMenuManager(); 43
44 InitKeyboardManager(); 45
46 InitTooltipManager();
47 CMFCToolTipInfo ttParams;
48 ttParams.m_bVislManagerTheme = TRUE; 49
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL, 50 RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams); 51
52 // 注册应用程序的文档模板。文档模板 53 // 将用作文档、框架窗口和视图之间的连接 54 CSingleDocTemplate* pDocTemplate;
55 pDocTemplate = new CSingleDocTemplate( 56 IDR_MAINFRAME,
57 RUNTIME_CLASS(CSDIMFCDoc),
58 RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口 59 RUNTIME_CLASS(CSDIMFCView)); 60 if (!pDocTemplate) 61 return FALSE;
62 AddDocTemplate(pDocTemplate); 63 64
65 // 分析标准 shell 命令、DDE、打开文件操作的命令行 66 CCommandLineInfo cmdInfo;