深入浅出话VC++(2) - MFC的本质 联系客服

发布时间 : 星期六 文章深入浅出话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;