《MFC框架程序剖析》由会员分享,可在线阅读,更多相关《MFC框架程序剖析(55页珍藏版)》请在金锄头文库上搜索。
1、本章将剖析基于 MFC的框架程序,探讨 MFC框架程序的内部组织结构。MFC(Microsoft Foundation Class,微软基础类库)是微软为了简化程序员的开发工作所开发的一套 C+类的集合,是一套面向对象的函数库,以类的方式提供给用户使用。利用这些类,可以有效地帮助程序员完成 Windows应用程序的开发。3.1 MFC AppWizardMFC AppWizard是一个辅助我们生成源代码的向导工具,它可以帮助我们自动生成基于 MFC框架的源代码。该向导的每一个步骤中,我们都可以根据需要来选择各种特性,从而实现定制应用程序。下面 我 们 就 利 用 MFC AppWizard来
2、创 建 一 个 基 于 MFC的 单 文 档 界 面 ( SDI) 应用 程 序 。启动 Microsoft Visual C+6.0,单击【File】菜单,选择【New】,在Projects选项卡下,选择 MFC AppWizard(exe),在右侧的【Project name】文本框中,输入我们的工程名:Test,如图 3.1所示。图 3.1 New对话框单击【OK】按钮,出现 MFC AppWizard-Step 1对话框,选择 Single document选项,如图 3.2所示。单击【Next】按钮,出现 MFC AppWizard-Step 2 of 6对话框,保持默认选择,如图
3、3.3所示。 图 3.2 MFC AppWizard - Step 1对话框 图 3.3 MFC AppWizard - Step 2 of 6对话框单击【Next】按钮,出现 MFC AppWizard-Step 3 of 6对话框,保持默认选择,如图 3.4所示。单击【Next】按钮,出现 MFC AppWizard-Step 4 of 6对话框,保持默认选择,如图 3.5所示。图 3.4 MFC AppWizard - Step 3 of 6对话框 图 3.5 MFC AppWizard - Step 4 of 6对话框单击【Next】按钮,出现 MFC AppWizard-Step 5
4、 of 6对话框,保持默认选择,如图 3.6所示。单击【Next】按钮,出现 MFC AppWizard-Step 6 of 6对话框,保持默认选择,如图 3.7所示。单击【Finish】按钮,出现 New Project Information窗口,如图 3.8所示。这里需要确认前面几步所做的选择。如果需要修改先前步骤的选择,可以单击 Cancel按钮返回到上一步。在这里,单击【OK】按钮,MFC AppWizard就为我们创建一个新工程:Test。 图 3.6 MFC AppWizard - Step 5 of 6对话框 图 3.7 MFC AppWizard - Step 6 of 6对
5、话框图 3.8 New Project Information对话框现在,按下 F7键编译程序,接着按下 Ctrl+F5键运行程序,可以看到如图3.9所示的运行结果。图 3.9 AppWizard创建的 SDI程序运行结果在这个程序中,我们自己没有编写任何代码,就生成了一个带有标题栏,具有最小化框、最大化框,具有系统菜单和一个可调边框的应用程序。这个程序和我们在第 1章中所创建的程序类似,但比后者多了菜单栏、工具栏以及状态栏。这一切都是通过 MFC AppWizard生成的。3.2 基于 MFC 的程序框架剖析MFC库是开发 Windows应用程序的 C+接口。MFC 提供了面向对象的框架,程
6、序开发人员可以基于这一框架开发 Windows应用程序。MFC 采用面向对象设计,将大部分的 Windows API封装到 C+类中,以类成员函数的形式提供给程序开发人员调用。下面我们看一下 MFC AppWizard帮助我们生成的这些代码。单击左边工作区窗格中的 ClassView(类视图)标签页,可以看到如图 3.10所示的五个类。图 3.10 ClassView 标签页提示:如果要查看某个类提供的信息,可以在 ClassView 标签页上单击该类前面的“+”符号,即可展开该类,显示该类拥有的函数和属性。在 MFC中,类的命名都以字母“C”开头,就像 Delphi中类名以 T开头,Orac
7、le的类名以 O开头一样,当然,这并不是必需的,这只是一种约定。对于一个单文档应用程序(即我们在创建工程时第二步所选的 Single document),都有一个 CMainFrame类,和一个以“C+工程名+App”为名字的类、一个以“C+工程名+Doc”为名字的类、一个以“C+工程名+View”为名字的类。作为读者,在刚接触 MFC的程序时,一定要逐步熟悉 MFC AppWizard所生成的这几个类,以及类中的代码。这样才能在阅读程序时,知道哪些类、哪些代码是向导生成的,哪些类、哪些代码是我们自己编写的。在 ClassView标签页中的类名上双击,右边工作区窗格就会打开定义该类的头文件。我
8、们可以发现 ClassView标签页中的这五个类都有一个基类,例如,CTestView 派生于 CView;CMainFrame 派生于 CFrameWnd这些基类都是 MFC中的类,可以查看一下这些基类的帮助信息。提示:如果想查看某个类或函数的帮助,可以把当前光标放在该类或函数所在位置,然后按 F1 键,即可打开 MSDN 中相应帮助。在 MSDN 帮助页中每个类的说明页底部都有一个“Hierarchy Chart”超链接,单击此链接,即可看到整个 MFC 类的组织结构图。图 3.11是 MFC类 组 织 结 构 图 中 的 一 部 分 , 可 以 发 现 CFrameWnd是 由 CWnd
9、派生 的 。 另 外 , 也 可以发现从 CWnd派生的还有 CView类。这就说明这个程序中的CMainFrame类和 CTestView类追本溯源有一个共同的基类:CWnd 类。CWnd 类是 MFC中一个非常重要的类,它封装了与窗口相关的操作。图 3.11 部分 MFC 类组织结构图3.2.1 MFC 程序中的 WinMain 函数读者还记得我们在第 2 章中讲述的创建 Win32 应用程序的几个步骤吗?当时,我们介绍 Win32 应用程序有一条很明确的主线:首先进入 WinMain 函数,然后设计窗口类、注册窗口类、产生窗口、注册窗口、显示窗口、更新窗口,最后进入消息循环,将消息路由到
10、窗口过程函数中去处理。遵循这条主线,我们在写程序时就有了一条很清晰的脉络。但在编写 MFC 程序时,我们找不到这样一条主线,甚至在程序中找不到 WinMain 函数。可以在当前 Test 工程中查找 WinMain 函数,方法是在 VC+开发环境中单击【Edit 】菜单,选择【Find in Files】菜单项,并在弹出的查找对话框中“Find What:”文本框内输入“WinMain ”,单击【Find】按钮,结果当然是找不到 WinMain 函数。读者可以在这个工程中,再查找一下 WNDCLASS、CreateWindow 等,你会发现仍然找不到。那么是不是MFC 程序就不需要 WinMa
11、in 函数,不需要设计窗口类,不需要创建窗口了呢?当然不是。我们之所以看不见这些,是因为微软在 MFC 的底层框架类中封装了这些每一个窗口应用程序都需要的步骤,目的主要是为了简化程序员的开发工作,但这也给我们在学习和掌握 MFC 程序时造成了很多不必要的困扰。为了更好地学习和掌握基于 MFC 的程序,有必要对 MFC 的运行机制,以及封装原 理有 所 了 解 。 在 第 1 章 就 讲 述 了 WinMain 函 数 是 所 有 Win32 程 序 的 入 口 函 数 , 就 像 DOS 下的main 函数一样。我们创建的这个 MFC 程序也不例外,它也有一个 WinMain 函数,但这个Wi
12、nMain 函数是在程序编译链接时,由链接器将该函数链接到 Test 程序中的。在安装完 Microsoft Visual Studio 6.0 后,在安装目录下(将 Microsoft Visual Studio 6.0 安装到了 D:Program Files 下) ,微软提供了部分 MFC 的源代码,我们可以跟踪这些源代码,来找出程序运行的脉络。机器上 MFC 源代码的具体路径为 D:Program FilesMicrosoft Visual StudioVC98MFC SRC,读者可以根据这个目录结构在自己机器上查找相应的目录。找到相应的目录后,在资源浏览器的工具栏上选择“搜索” 。然
13、后在搜索窗口的“包含文字”文本框中输入”WinMain”,单击“立即搜索(S) ”按钮,搜索结果如图 3.12 所示。图 3.12 包含“WinMain”文字的搜索结果我们 只 需 要 查 看 后 缀 名 为 CPP 的 源 文 件 即 可 , 实 际 上 , WinMain 函 数 在 APPMODUL.CPP 这个文件中。保持 Test 工程的打开状态,然后双击 APPMODUL.CPP 即可在 VC+环境中打开该文件,在其中可以找到如例 3-1 所示的这段代码。例 3-1extern C int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE
14、 hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)/ call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);WinMain 函数找到了。现在我们可以看看 Test 程序是否会进入这个 WinMain 函数。在 WinMain 函数中按下 F9 键设置一个断点,然后按下 F5 键调试运行当前程序。我们发现程序确实运行到该断点处停了下来,如图 3.13 所示。这说明 Test 这个 MFC 程序确实有WinMain 函数,在程
15、序编译链接时,WinMain 函数就成为该程序的一部分。图 3.13 程序运行到 WinMain 断点处但这个_tWinMain 函数和第 1 章所讲的 WinMain 函数有些不同,让我们先看看这个函数的定义。读者可以在_tWinMain 上单击鼠标右键,从弹出的快捷菜单中选择【Go To Definition Of _tWinMain】 菜 单 项 , 光 标 就 会 定 位 到 _tWinMain 函 数 的 定 义 处 , 代 码 如 例 3-2 所示,从中我们可以发现_tWinMain 实际上是一个宏,展开之后就是 WinMain 函数。例 3-2#define _tmain mai
16、n#define _tWinMain WinMain#ifdef _POSIX_#define _tenviron environ#else#define _tenviron _environ#endif#define _targv _argv1theApp 全局对象找到了 WinMain 函数,那么它是如何与 MFC 程序中的各个类组织在一起的呢?也就是说,MFC 程序中的类是如何与 WinMain 函数关联起来的呢?双击 ClassView 标签页中的 CTestApp 类,跳转到该类的定义文件(Test.h)中。可以发现 CTestApp 派生于 CWinApp 类,后者表示应用程序类。我们在 ClassView 标签页中打开 CTestApp 类前面的“+”符号,双击该类的构造函数,就跳转到该类的源文件(Te