106
第第第 第第 MFC 第第第第第第第第第

第二章 揭开 MFC 应用程序框架的秘密

Embed Size (px)

DESCRIPTION

第二章 揭开 MFC 应用程序框架的秘密. 前一章我们已经学会了使用 Visual C++ 6.0 和 Visual C++ .NET 的 向导生成 Windows API 应用程序 的方法,并对 Windows 应用程序 的基本结构特点和运行机制有所了解。仔细分析这类程序,不 难发现,这类程序功能的实现是建立在对 API 函数的调用之上 的,而 API 函数是通过参数形式对 GUI 元素(如窗口、对话框、 菜单、设备场境等 Windows 类实例 )进行相应操作的。从程序 - PowerPoint PPT Presentation

Citation preview

第二章 揭开 MFC 应用程序框架的秘密

前一章我们已经学会了使用 Visual C++ 6.0 和 Visual C++ .N

ET 的

向导生成 Windows API 应用程序的方法,并对 Windows 应用程序

的基本结构特点和运行机制有所了解。仔细分析这类程序,不

难发现,这类程序功能的实现是建立在对 API 函数的调用之上

的,而 API 函数是通过参数形式对 GUI 元素(如窗口、对话框、

菜单、设备场境等 Windows 类实例)进行相应操作的。从程序

的组成上看,这些 Windows 类实际上只是用于描述 GUI 元素的

形状、尺寸、风格等属性的数据结构对象,而不是将属性和建

立在属性之上的操作封装在一起的 C++ 类对象。所有 Window

s

类的实例是由 Windows 系统统一管理,并通过系统的编程接口

( API 函数)提供对这些类实例的所有操作。

因此,实现对 GUI 元素的操作都必须首先通过 API 函数直接

或间接地在系统中注册并创建(分配内存空间并建立了索引)

所对应的 Windows 类的实例,并获得访问实例的句柄;然后以

句柄为参数调用特定 API 函数,以便对指定的 GUI 元素实现所

需要的操作。这种操作与被操作的数据的分离是面向过程设计

的基本特点,而是面向对象程序设计所不允许的。因此,虽然

也可以按照面向对象的设计方法在 API 应用程序中加入 C++ 类

的定义和使用,但不能从根本上改变程序的面向过程设计。

MFC (Microsoft Foundation Class Library) 是 Microsoft 公司提供的

建立在 Windows 类和 Win32 API 基础上的 C++ 类库。库中的 C++

类几乎涵盖了 Windows 程序所需要的主要 Windows 类和相应的

API 函数功能。 Visual C++ 集成环境中的 MFC AppWizard 能使用

MFC 中的框架类为编程者提供一个标准的面向对象的 Windows

应用程序框架。借助这个框架,编程者可以方便地使用 MFC

供的 C++ 类比较轻松地开发各类面向对象设计的 Windows 应用

程序。从面向对象程序设计的角度出发,对 Visual C++ 从入门到

精通的过程,主要是学习和熟悉 MFC 及其 MFC 应用程序框架的

过程,它将贯穿在本课程的整个学习过程中。

2.1 用 AppWizard 开发基于 MFC 的窗口程序 通过一个 MFC 窗口程序的生成过程,学习和了解:

· 如何使用 AppWizard 创建一个 MFC 窗口程序项目。

· 自动生成的 MFC 窗口程序框架的功能。

· 自动生成的 MFC 窗口程序框架由那些类组成。

· 自动生成的 MFC 窗口程序框架包括那些文件。

· 如何向框架中添加代码。

2.1.1 生成 MFC 窗口程序1 使用 Visual C++ 6.0 集成开发环境⑴ 在菜单 “ File” 中选择菜单项 “ New” 打开创建新项目的

向导。

⑵ 在该向导中选择应用程序项目的框架模板在 Project 中选择 MFC AppWizard(exe) 创建命名为 “ HellHell

oo” 的 MFC 窗口程序项目。

⑶ 使用 MFC AppWizard(exe) 设置应用程序项目的选项 ① MFC AppWizard(exe) - step 1 属性页:

选择程序类型和资源语言。

② MFC AppWizard(exe) - step 2 of 6 属性页:设置数据库。缺省选项 None ,表示不支持数据库

操作。

③ MFC AppWizard(exe) - step 3 of 6 属性页:设置 OLE 支持选项。缺省选项 None ,表示无 OL

E 支持。

④ MFC AppWizard(exe) - step 4 of 6 属性页:

设置应用程序外观。此例使用缺省选项,即:

Docking toolbar 支持靠边的工具栏

Initial Status bar 支持初始化状态栏

Printing and print preview 支持打印和打印预览

3D controls 支持 3D 控件

Normal 支持普通风格的工具栏,支持显示 4

个最近使用过的文件名。

⑤ MFC AppWizard(exe) - step 5 of 6 属性页:

设置项目风格和 MFC 的使用方式。缺省选项,表示:

MFC Standard 提供一个标准的 MFC 应用程序

Yes please 提供框架的程序注释

As a shared DLL MFC 被链接为共享动态链接库

⑥ MFC AppWizard(exe) - step 6 of 6 属性页:允许修改向导缺省创建的类名、基类、头文件名和

实现 文件名。

⑦ New Project Information 属性页:

显示所生成的应用程序的组成信息。

⑷ 应用程序项目的编译运行 一个具有标准窗口界面的单文档程序框架能成功运行。⑸ 查看项目中自动生成的信息 打开所生成的项目目录会发现 MFC AppWizard 自动创

建了 许多文件,这些文件包括: ① 项目信息文件 ·工作区文件( .dsw ):保存当前工作区所包含项目的信息。 · 项目文件( .dsp ):包含了当前项目的设置、项目中包含的

文件等信息。 ·make 文件( .mak ):用于在集成环境外生成可执行文件。

注意: make 文件只有在“ Project” 菜单中执行 Export Mak

efile…

命令时,才产生。

· 类信息文件( .clw ):该文件含有使用类向导( Class Wizar

d )

操作(编辑现有类、增加新类,创建和编辑消息映射,对

话框所需的数据,创建虚拟成员函数等) 时需要使用的类

信息。如果类向导文件 .clw 被删除,则在使用 Class Wiza

rd 时会出现如下信息:

此时如果按 “ Yes” 按钮,则选择重建 .clw 文件,即显示如下

操作对话框:

按 OK 按钮,就可以完成类信息文件的重建。

② 应用程序源文件和头文件

·头文件( .h ):包含应用程序类头文件、主窗口类头文件、

文档类头文件和视图类头文件,它们分别用于定义从 MFC

相应的基类派生出的应用程序框架类。

· 源文件( .cpp ):包含有应用程序类源文件、主窗口类源文

件、文档类源文件和视图类源文件,它们分别为相应头文

件中类定义提供实现文件。

③ 资源文件

· 资源描述文件( .rc ):保存所有被创建的资源描述信息。

· 资源头文件( resource.h ):主要用于定义资源描述文件中

的标识的定义。

· 资源文件目录 res 中包含了资源描述文件( .rc )中需要导入

的图标、光标、位图资源信息文件等。

④ 预编译头文件

StdAfx.h 和 StdAfx.cpp 这两个文件用于建立一个预编译头文

件( .pch ) 和一个预定义的类型文件 StdAfx.obj 。程序中常用

的 MFC 的头文件都放在 StdAfx.h 中,如 afxwin.h 、 afxe

xt.h 、

afxdisp.h 、 afxcmn.h 等。 Stdafx.h 被包含在 stdAfx.cpp 中。由于编

译器能够识别哪些头文件已被预编译过,如果不改变 Std

Afx.h

中所包含的头文件,则 StdAfx.cpp 只需被编译一次。如果在

StdAfx.h 中添加新头文件后,则必须重新编译 StdAfx.cpp ,

使

添加的头文件加入预编译头文件( .pch ) 。

⑤ 其他文件

⑥ 生成的 C++ 类

·CHelloApp :应用程序类,基类为 CWinApp ,负责程序的初

始化和结束处理;

·CMainFrame :主窗口类,基类为 CFrameWnd ,负责主窗口

和操作界面(菜单、工具栏、状态栏等)的创建、显示;

·CHelloDoc :文档类,基类为 CDocument ,负责应用程序的

数据存储、修改和管理;

·CHelloView :视图类,基类为 CView ,负责为数据提供显示

窗口。

2 使用 Visual C++ NET 集成开发环境⑴ 在子菜单 “ File” 中选择菜单项 “ New” 的子项 “ Project

…” 打开创 建新程序项目的 “ New Project” 属性表。

⑵ 在工程项目“ New Project” 属性表中选择 Visual C++ - MFC –

MFC AppWizard 创建一个命名为 Hello 的 MFC 窗口程序 。

⑶ 在项目向导“ MFC Application Wizard” 属性表中可以进行项目的

各个属性设置。该表的左边列出了各个分类属性页的选择,

右边显示当前所选分类属性的信息,并提供修改属性的交互

界面,右下部提供了该属性表的向导按钮。因此,该属性表

既可以按照一般属性表使用,也可以按照向导使用。

“① Overview” 属性页:

在该页中显示了工程项目的当前主要属性,例如本例中的

主要缺省属性为:

·Mutiple document interface MDI 多文档界面

·No database support 无数据库支持

·No compount document support 无复合文档支持

如果无须修改工程项目的当前属性和添加其他属性,则按

“Finish” 按钮完成工程项目创建,否则按 “ Next” 按钮,转换

到后一属性页,或通过右边的属性页分类选择,转换到任

意一个需要修改属性的页。本例只修改 Application Type 。

“② Application Type” 属性页:

在该页中可以确定工程项目类型的属性,这些属性分为三

部分:

·Application type :确定应用程序的界面类型。与 VC 6.0 的

AppWizard Step1 属性页比较,该属性页增加了

Mutiple top-level document 界面类型和 Use Unicode libraries 选

择。本例中只须将缺省界面类型 Mutiple documents 修改为

Single document 。

·Project style :确定项目的风格为 Windows Explorer 或 MFC

Standard ,本例为缺省风格: MFC Standard 。 VC 6.0 中,

该属性在 AppWizard Step 5 of 6 属性页中。

·Use of MFC :确定项目的 MFC 使用方式。在 VC 6.0 中,

该属性的设置也在 AppWizard Step 5 of 6 属性页中。

如果需要修改或添加其他属性,则可按“ Next” 或“ Previ

ous”

按钮,转换到前一或后一属性页,或通过右边的属性页分

类选择,转换到任意一个需要修改属性的页;否则可以直

接按“ Finish” 按钮完成工程项目的创建。

“③ Compound Document Support” 属性页:

该页中可以确定工程项目的复合文档属性,在 Visual C++

6.0 中,这些属性的设置在 AppWizard Step 3 of 6 属性页中。

本例为缺省属性“ None”无复合文档支持。

如果需要修改或添加其他属性,则可按“ Next” 或“ Previ

ous”

按钮,转换到前一或后一属性页,或通过右边的属性页分

类选择,转换到任意一个需要修改属性的页;否则可以直

接按 “ Finish” 按钮完成工程项目的创建。

“④ Document Template Strings” 属性页:

在该属性页中可以修改项目的文档描述串(文件扩展名、

主框架窗口标题、文档类型名等)。在 Visual C++ 6.0 中,

设置这些属性在 AppWizard Step 4 of 6 的 “ Advanced…”

附加

属性页中完成的。本例使用缺省的文档描述串。

如果需要修改或添加其他属性,则可按“ Next” 或“ Previ

ous”

按钮,转换到前一或后一属性页,或通过右边的属性页

分类选择,转换到任意一个需要修改属性的页;否则可以

直接按“ Finish” 按钮完成工程项目的创建。

“⑤ Database Supprot” 属性页: 在该页中可以确定项目的数据库属性,在 VC 6.0 中,该属 性的设置在 AppWizard Step 2 of 6 属性页中。

如果需要修改或添加其他属性,则可按 “ Next” 或 “ Pr

evious”

按钮,转换到前一或后一属性页,或通过右边的属性页分

类选择,转换到任意一个需要修改属性的页;否则可以直

接按 “ Finish” 按钮完成工程项目的创建。

“⑥ User Interface Features” 属性页:

在该页中可以确定工程项目的用户界面特征属性,在

VC 6.0 中,这些属性的设置在 AppWizard Step 4 of 6 属性页

中完成。本例为缺省的用户界面特征属性。

如果需要修改或添加其他属性,则可按“ Next” 或“ Previ

ous”

按钮,转换到前一或后一属性页,或通过右边的属性页

分类选择,转换到任意一个需要修改属性的页;否则可以

直接按“ Finish” 按钮完成工程项目的创建。

“⑦ Advanced Features” 属性页:

在该页中可以确定工程项目的高级属性如下:

·Context-sensitive Help 上下文相关的帮助文件集合

·Printing and print preview 打印和打印预览

·MAPI (Messaging API) 允许调用通讯功能 MAPI

·Windows Socket 允许使用 Windows Socket

·Number of files on recent file list 显示最近用过文件的数目

(在 VC 6.0 中,上述属性在 AppWizard 4 of 6 属性页中)

·Automation 允许成为其他程序或脚本的操作对

象(在 VC 6.0 中,该属性在 AppWizard 3 of 6 属性页中)

·Active Accessibility

·Common Control Manifest

(上述两项属性是 Visual C++ .NET 中新增的)

VC 6.0 中,这些属性的设置在 AppWizard Step 4 of 6 属性页

中完成。本例为缺省的用户界面特征属性。

如果需要修改或添加其他属性,则可按 “ Next” 或 “ Pr

evious”

按钮,转换到前一或后一属性页,或通过右边的属性页

分类选择,转换到任意一个需要修改属性的页;否则可以

直接按 “ Finish” 按钮完成工程项目的创建。

“⑧ Generated Classes” 属性页:

在该页中显示了工程项目自动生成的构成程序基本框架的

类的缺省命名、派生的基类以及这些类的定义文件和实现

文件的命名属性。这些属性中一部分是允许修改的,而另

一部分是不允许修改的。本例使用缺省命名属性,不做任

何修改。在 Visual C++ 6.0 中,这些命名属性的显示和修改

是在 AppWizard Step 6 of 6 属性页中完成。

⑷ 应用程序项目的编译运行

一个具有标准窗口界面的单文档应用程序成功运行,但视

窗中并不显示任何内容。

⑸ 查看项目中自动生成的信息

工程项目的所有信息文件被分别保存在三个不同层次的目

录中:

① 项目主目录

该目录与项目名同名,本例的项目主目录名为 Hello 。

在该目录中包含了一个与项目主目录同名的子目录(用

于存放项目的所有源文件)和三个项目管理信息文件:

· 项目 / 解决方案文件( .sln )

文件名与项目同名,用于打开和管理已建项目 / 解决方

案,该文件不可以删除。

·Intellisense database 文件( .ncb)

文件名与项目同名,用于保存已建项目 / 解决方案的辅助

信息,该文件可以删除。

· 用户选项信息文件( .suo)

文件名与项目同名,用于保存已建项目 / 解决方案的辅助

信息,该文件可以删除。

② 源代码子目录中包含了项目中所有的源代码文件( .h, .cpp,

.rc),命名为 res 的资源子目录和三个信息文件:

· 项目文件( .vcproj)

文件名与项目同名,用于打开和管理已建项目 / 解决方

案,该文件不可以删除。

· 用户选项信息文件( .vcproj.… )

文件名与项目同名,用于保存已建项目 / 解决方案的辅助

信息,该文件可以删除。

·readme 文件( .txt )

文件名与项目同名,用于阅读已建项目 / 解决方案的说明

信息,该文件可以删除,但建议不要删除。

③ 资源子目录 res

该目录中包含了资源描述文件( .rc )中需要导入的图标、

光标、位图资源信息文件等。

④ 预编译头文件 与 Visual C++ 6.0 中相同。

⑤ 生成的 C++ 类 与 Visual C++ 6.0 中相同。

⑥ 项目在 Debug 方式下编译链接后,会在项目主目录中和项

目源代码目录中分别创建一个以“ Debug” 命名的子目录。可

执行文件在主目录的 “ Debug” 子目录中;源代码目录中的

“Debug” 子目录中包含了编译链接过程中所产生的中间文

件。这两个子目录均可删除。

⑦ 项目在 Release 方式下编译链接后,会在项目主目录中和

项目源代码目录中分别创建一个以 “ Release” 命名的子目

录。可执行文件在主目录的 “ Release” 子目录中;源代码目

录中的 “ Release” 子目录中包含了编译链接过程中所产生的

中间文件。这两个子目录均可删除。

2.1.2 使用项目工作区窗口浏览和添加代码 MFC AppWizard 为我们提供一个面向对象的 Windows 应用程

序框架,它为程序的构造和运行建立了最基本的、优化的框架,使软件工作者避免了设计开发任何程序都需要的程序框架建造工作(该工作很烦琐,但具有一致性),而可以集中精力解决所设计程序需要完成的特定功能的设计上,并为实现设计在程序框架中添加新类、资源以及相应的消息消息映射和消息处理函数等等。这将大大有利于程序设计方案简化和优化。 为了便于向程序框架中添加正确的代码, VC 还提供了项

目工作区和 Class Wizard 这样的可视化管理工具,编程者可以借助

这些工具,方便地完成对项目中几乎所有代码的添加、浏览查看和修改。

1 使用项目工作区的 ClassView

·浏览和修改项目中已有类的定义和类成员函数的定义; · 为项目添加新类,并为类添加类数据成员和类成员函数; · 其他。 在本例中,为了实现在视窗中显示文本 “ Hello World!” 需要

在 类 CHelloView 的成员函数 OnDraw 中增加如下代码:

void CHelloView::OnDraw(CDC* pDC)

{

CHelloDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

// TODO: add draw code for native data here

pDC->TextOut(10, 10, "Hello World!");

}

2 使用项目工作区的 ResourceView

·浏览查看项目中的所有资源;

·修改项目中的已有资源;

· 为项目添加新资源。

3 使用项目工作区的 FileView

·浏览查看项目中与生成可执行程序有关的所有文件;

· 在被打开的文件中修改和添加代码;

· 为项目增加或删除文件。

在 Visual C++.NET 中相应的视图称为 Solution Explorer 。

2.1.3 设置程序环境参数 程序项目的编译、连接、运行需要在特定设置的系统环境

进行。系统环境的设置是通过修改各种环境参数完成的,其中

指定程序所需要的系统功能库就是最重要的设置之一。被链接

库的种类有两种:静态链接库和动态链接库。在程序项目建立

过程中,可以通过项目属性的设置确定使用哪一种的哪些功能

库。指定程序项目所需要的功能库的工作包括以下几个方面:

1 将项目需要链接的系统功能库的头文件通过 #include 命令包 含到预编译头文件 StdAfx.h 中(推荐),或者包含到需要使 用这些库功能的源文件中。 AppWizard 会根据相应的项目创

建 属性,在 StdAfx.h 中缺省添加所需要的缺省功能库头文件, 以便满足项目编译的需要。本例的 StdAfx.h 中缺省添加了: · afxwin.h 声明了所有的 MFC 的核心类和组件。 · afxext.h 声明了 MFC 的工具栏、状态栏等扩展类。 · afxdisp.h 声明了 MFC 自动化类。 · afxdtctl.h 提供 Internet Explorer 4 通用控件的 MFC 支持。 · afxcmn.h声明了 MFC 的通用控件类。 显然,如果创建工程项目的类型和各种可选择属性不同,则 StdAfx.h 中所包含的缺省功能库头文件也会有所不同;

2 把相应静态库文件( *.lib )或动态库对应的导入( Import )库 文件( *.lib )的设置添加到项目中。 AppWizard 会在程序项

目 中缺省加入基本设置。 MFC 应用程序需要的 MFC 功能库

和 SDK 功能库。主要有: ·Windows C Runtime 功能库

LIBC.LIB C Runtime 功能库的静态链接版本MSVCCRT.LIB C Runtime 功能库的动态链接版本MSVCCRTD.LIB C Runtime 功能库的动态链接调试版

· 系统核心模块的 DLL 功能库GDI32.LIB 与 GDI32.DLL 对应的导入库USER32.LIB 与 USER32.DLL 对应的导入库KERNEL32.LIB 与 KERNEL32.DLL 对应的导入库…

·MFC 功能库

MFC42.LIB MFC42.DLL 对应的导入库

MFC42D.LIB MFC42D.DLL 对应的导入库

注意,如果需要链接的是动态库,则相应的 DLL 文件( *.

dll )

应该存放在项目生成的可执行文件( *.exe )能够搜索的路径

中,即系统目录中( \…\include\ 或 Windows\system\ 目录)或

者应用程序的可执行文件所在的目录中。

编程者可以根据程序项目的具体需要,对上述链接库的缺

省设置进行必要的增加、删除。

Visual C++ 6.0 集成环境中为环境参数的设置操作提供各种工

具和方法,其中,通过菜单 Project -> Setting… 提供的 “ Project

Setting” 交互操作对话框就是最典型、最全面、最常用的环境

参数的设置操作界面。在该界面中可进行总体( General )、

调试( Debug )、编程语言( C/C++ )、链接库( Link )、资

源( Resource )等环境参数的设置。

注意,在 Visual C++.NET 中各种环境参数的设置、修改是在

工作区的参数管理器 Property Manager 中实现的。

2.1.4 VC 集成开发工具与应用程序生成1 利用 VC 的 AppWizard 生成一个新程序项目。

2 用 VC 的各类编辑器编辑项目的内容:

· 用集成编辑器编辑各类程序源文件;

· 用 ClassWizard 编辑 C++ 类(此时也可以修改源文件);

· 用资源编辑器编辑各种资源。

3 编译源代码:

· 用 C++ 编译器编译所有的程序源文件,生成相应的目标文

件 .obj ;

· 用资源编译器编译资源文件 .rc ,生成资源二进制文件 .re

s 。

4 链接器将 .obj 文件、 .res 文件和库文件链接成可执行文件。

2.2 MFC 应用程序框架与 Win32 程序的关联 在 MFC Appwizard(exe) 自动生成的应用程序的源代码中,没有

我们在第一章中已经熟悉的实现 Windows 程序运行的 WinMain

WndProc 函数代码。那麽这个自动生成的没有 WinMain 函数代码

应用程序框架是如何运行的呢? WinMain 和 WndProc 函数中那些

实现 Windows 程序运行机制的代码(主窗口定义、注册、创建、

显示,消息的获取、分发循环和对各类消息的响应等)功能还

存在吗?如果存在,它们被封装在 MFC 哪些框架类中了呢?

MFC AppWizard 又是如何将这些 MFC 框架类按照编程者在创建程

序项目过程中的选择,组成一个可以运行的程序框架呢?

2.2.1 MFC 应用程序框架对 Win32 程序主要逻辑的封装

1 Windows 程序的基本结构和执行流程

WinMain(…){ MSG msg; WNDCLASS wc; … RegisterClass(&wc); CreateWindow(…); ShowWindow(…); UpdateWindow(…); while(GetMessage(&msg…)) { TranslateMessage(&msg); DispatchMessage(&msg); } …}

WndProc(hwnd,msg,wParam,lParam){ switch(msg) { case WM_CREATE: … case WM_COMMAND: … case WM_PAINT: … case WM_CLOSE: … case WM_DESTROY: … default: return DefWindowProc(…); } return 0;}

人机交互 操作系统产生

消息队列

2 MFC 类对 WinMain 和 WndProc 函数功能的封装

⑴ 与应用程序框架相关的类

组成程序框架的四个类的 MFC 基类是 CWinApp 、 CFram

eWnd 、

CView 和 CDocument 。与这些框架基类有关的 MFC 类之间的

派生层次关系如下图所示:

图中各类的功能如下:

CObject

CCmdTarget

CWinthread CWnd CDocument

CWinApp CFrameWnd

CView

·CObject :提供了对象动态性、诊断性和持续性支持,因此 该类是所有需要这三大特性的 MFC 类的根基类。 ·CCmdTarget : CObject 的直接派生类,它增加了响应命令消 息的能力。因此它是所有需要响应消息的 MFC 类的直接或 间接基类,当然是所有程序框架类的直接基类。 ·CWinTread : CCmdTarget 的直接派生类,它增加了支持线程 创建、启动、运行和退出功能。线程是进程的最小单位, 因此该类是应用程序类 CWinApp 的直接基类。 ·CWnd : CCmdTarget 的直接派生类,它增加了支持窗口定 义、创建、显示更新、注销和窗口消息响应的功能。因此 它是 MFC 的各种特定窗口类 (包括主窗口类 CFrameWn

d )的直接或间接基类。

·CDocument : CCmdTarget 的直接派生类,它增加了支持文

档的各种操作。

·CWinApp : CWinTread 的直接派生类,它增加了进程的创

建、启动、消息循环的启动和进程的退出。

·CFrameWnd : CWnd 的直接派生类,它增加了进程主窗口所

需要的菜单、子窗口管理等各种功能。

·CView : CWnd 的直接派生类,它增加了与 CDocument 类的

关联操作。

显然, CWinApp 、 CFrameWnd 、 CView 和 CDocument 是构造典

型的文档视图结构程序项目的框架类。但 MFC AppWizard

不直接使用这些类生成程序框架 , 而是使用它们的派生类,

例如本例中:

基类 派生类 CWinApp CHelloApp

CFrameWnd CMainFrame

CDocument CHelloDoc

CView CHelloView

使用派生类的优点:

·继承了基类的基本功能;

·继承了 MFC 已经确定的由基类关联建造的应用程序框架;

· 可以方便地增加不同应用程序框架类的特定新功能,特别

重要的是借助虚函数和动态链编实现的动态多态性。

API 程序中的主函数 WinMain 和主窗口函数 WndProc 所完成的

功能是由这些 MFC 类的相应功能替代的。其中 CWinApp

封装

了与应用程序相关的程序启动、消息循环启动、消息的获取

和分发、部分消息的处理和程序退出等功能; CFrameWnd

封装了程序主窗口创建、部分消息的处理和窗口销毁等功能。

查看 Afxwin.h 中 CWinApp 和 CFrameWnd 类的定义,并单步跟

踪 MFC 框架应用程序的执行,便可以了解到这种替代是如何

实现的。

class CWinApp : public CWinThread

{

DECLARE_DYNAMIC( CWinApp )

public:

// hooks for your initialization code

virtual BOOL InitApplication();

// Command Handlers

protected:

// map to the following for file new/open

afx_msg void OnFileNew();

afx_msg void OnFileOpen();

public:

virtual BOOL InitInstance();

virtual int ExitInstance(); // return app exit code

virtual int Run();

virtual BOOL OnIdle( LONG lCount );

// return TRUE if more idle processin

g

};

CWinApp 类的定义很长 , 它提供了丰富的功能接口供应用程序

使用,我们现在只需要关心那些直接起到替代 WinMain 功能

的成员函数:

·InitApplication() 初始化应用程序

·InitInstance() 初始化进程实例

·Run() 启动消息循环,获取和分发消息

·OnIdle( LONG lCount ) 无消息时的空闲循环

·ExitInstance() 退出进程实例

注意:这些函数都是虚函数,因此可以在 CWinApp 的派生类

中对这些函数的重新定义,以便在相同的进程点实现不同应

用程序的特定操作需求。

class CFrameWnd : public CWnd {

DECLARE_DYNCREATE( CFrameWnd )

public:

BOOL Create( LPCTSTR lpszClassName,

LPCTSTR lpszWindowName,

DWORD dwStyle = WS_OVERLAPPEDWINDOW,

const RECT& rect = rectDefault,

CWnd* pParentWnd = NULL, // != NULL for pop

ups

LPCTSTR lpszMenuName = NULL,

DWORD dwExStyle = 0,

CCreateContext* pContext = NULL );

protected:

virtual BOOL PreCreateWindow( CREATESTRUCT& cs );

virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam );

virtual void PostNcDestroy(); // default to delete this.

//{{AFX_MSG(CFrameWnd)

// Windows messages

afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );

afx_msg void OnDestroy();

afx_msg void OnClose();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

friend class CWinApp;

};

与 CWinApp 一样 CFrameWnd 也提供了丰富的功能接口,以满

足程序主窗口的操作需求,这里我们也只需关注那些与窗口

的创建、消息响应、关闭和销毁有关的主要成员函数。

·Create 、 PreCreateWindow 和 OnCreate 用于窗口的创建;

·OnCommand 用于命令消息的响应处理;

·OnClose 用于窗口的关闭;

·PostNcDestroy 和 OnDestroy 用于窗口的销毁。

不难发现,这些成员函数都是 CFrameWnd 的保护成员,是不

能被类对象的使用者直接调用的,因此,这些功能的执行是

通过消息映射机制(替代 WndProc 中的 switch - case 结构)被

直接或间接触发的。

2.2.2 MFC 应用程序的启动流程1 MFC 框架进程创建过程的时序图

2 MFC 应用进程的初始化流程 通过对一个实际 MFC 应用程序流程的分析揭示 MFC 应

用程序 框架的秘密。⑴ 实际 Hello 程序的流程

theApp:CHelloApp :CMainFrame :CHelloDoc :CHelloView

InitInstance()

[InitInstance() == TRUE]Run()

[PumpMessage() ==WM_QUIT]ExitInstance()

[Open a file] or [Create a new file]

[Close a file]

[Open a file] or [Create a new file]

[Close a file]

程序开始

初始化全局对象 theApp:CHelloApp

CHelloApp 构造函数

CWinApp 构造函数

AfxWinMain 函数{ …

…}

InitInstance(){ …

}

销毁窗口

程序结束

WM_QUITCHelloApp::ExitInstance

创建主窗口CMainFrame::CMainFrame();

CMainFrame::Create(…);

构造文档对象CHelloDoc::CHelloDoc();

创建视图对象CHelloView::CHelloView();

CHelloView::Create(…);

空闲

① ③

②⑤

CHelloApp::OnIdle()

CHelloApp::InitApplication();

CHelloApp::InitInstance();

CHelloApp::Run();

ProcessShellCommand(…);

主窗口 ->ShowWindow(…);

主窗口 -> UpdateWindow();

⑵ 分析 CHelloApp 的成员函数 InitInstance

BOOL CHelloApp::InitInstance()

{

AfxEnableControlContainer();

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need.

#ifdef _AFXDLL

Enable3dControls(); // Call this when using MFC in a shared DLL

#else

Enable3dControlsStatic(); // Call this when linking to MFC statica

lly

#endif

// Change the registry key under which our settings are stored.

// TODO: You should modify this string to be something appropriate

// such as the name of your company or organization.

SetRegistryKey( _T("Local AppWizard-Generated Applications" ) );

LoadStdProfileSettings(); // Load standard INI file options (including MRU)

// Register the application's document templates. Document templates

// serve as the connection between documents, frame windows and views.

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS( CHelloDoc ),

RUNTIME_CLASS( CMainFrame ), // main SDI frame windo

w

RUNTIME_CLASS( CHelloView ) );

AddDocTemplate( pDocTemplate );

// Parse command line for standard shell commands, DDE, file open

CCommandLineInfo cmdInfo;

ParseCommandLine( cmdInfo );

// Dispatch commands specified on the command line

if ( !ProcessShellCommand( cmdInfo ) ) return FALSE;

// The one and only window has been initialized, so show and update it.

m_pMainWnd->ShowWindow( SW_SHOW );

m_pMainWnd->UpdateWindow();

return TRUE;

}

从流程图可知: CMainFrame 、 CHelloDoc 和 CHelloView 对象以

及与 CMainFrame 关联的主窗口和与 CHelloView 关联的视图窗

口是函数 ProcessShellCommand 执行时被创建的,具体如何被

创建的呢?

⑶ 动态创建对象 MFC 程序中,主框架窗口对象、视图对象和文档对象是动态 创建的,即在程序运行中创建的。原因在于应用程序无法预

见用户何时需要创建这些类对象。能实现动态创建对象的类

需要建立如下动态创建机制(以 CMainFrame 为例): ① 在类定义中增加宏定义 DECLARE_DYNCREATE 代码,

例如: class CMainFrame : public CFrameWnd

{

protected: // create from serialization only

CMainFrame();

DECLARE_DYNCREATE( CMainFrame )

}

其中宏 DECLARE_DYNCREATE( CMainFrame ) 的作用相当于在

编译类定义时,用如下(方框中的)宏定义代码进行替换:

class CMainFrame : public CFrameWnd {

protected: // create from serialization only

CMainFrame();

DECLARE_DYNCREATE( CMainFrame )

}

static CRuntimeClass classCMainFrame;

// 用于保存动态创建对象所需要的全部参数。virtual CRuntimeClass* GetRuntimeClass() const;

// 用于获取 CRuntimeClass 变量的地址。static CObject* PASCAL CreateObject();

// 用于动态创建类对象,并返回对象地址。

其中数据结构 CRuntimeClass 用于描述类的动态创建信息,其 定义如下: struct CRuntimeClass

{LPCSTR m_lpszClassName; // 类名int m_nObjectSize; // 类对象的大小

UINT m_wSchema; // 类的版本号,不支持持续性的类为 -1

CObject* ( PASCAL* m_pfnCreateObject )( );

// 指向能动态创建类对象的函数CRuntimeClass* m_pBaseClass; // 指向基类的 CRuntimeClass

static CRutimeClass *pFirstClass;

// 指向动态创建类链中第一个类的 CRuntimeClass

CRuntimeClass *m_pNextClass;

// 指向动态创建类链中下一个类的 CRuntimeClass

};

对于 DECLARE_DYNCREATE 定义的结构变量 classCMainF

rame

和函数 GetRuntimeClass() 、 CreateObject() ,系统使用另一个宏

定义 IMPLEMENT_DYNCREATE 为它们提供了实现代码。 ② 在类实现代码中增加宏 IMPLEMENT_DYNCREATE ,例

如: IMPLEMENT_DYNCREATE( CMainFrame, CFrameWnd )

该宏定义在编译时,被如下宏定义代码替换: CObject* PASCAL CMainFrame::CreateObject()

{ return new CMainFrame; }

static char _lpszCMainFrame = “CMainFrame”;

CRuntimeClass CMainFrame::classCMainFrame = {

_lpszCMainFrame, sizeof( CMainFrame ), 0xffff,

CMainFrame::CreateObject(), RUNTIME_CLASS( CFrameW

nd ),

NULL, NULL}; // 初始化静态结构变量 classCMain

Frame

static AFX_CLASSINIT _init_

CMainFrame( &CMainFrame::classCMainFrame );

// 连接应用程序中所有支持动态创建的类的 CRuntimeClass

// 变量用于动态判断对象的所属类和消息映射。

CRuntimeClass* CMainFrame::GetRuntimeClass() const

{ return &CMainFrame::classCMainFrame; }

其中 RUNTIME_CLASS 是一个宏定义:

#define RUNTIME_CLASS( ClassName )

&ClassName::classClassName

③ 只要类中有了反映类动态创建的变量,并且已经初始化,

则如下的代码就可以实现动态创建该类对象,例如: CRuntimeClass *pMainFrame = RUNTIME_CLASS( CMainFrame );

CMainFrame *pMainFrameObject = pMainFrame->CreateObject();

⑷ 文档模板类管理动态创建信息 在 MFC 的文档视图结构的应用程序框架中,主窗口对象、视

图窗口对象和文档对象都是需要动态创建的,它们的动态创

建信息是通过一个文档模板类来管理的。文档视图结构的应

用程序中至少有一个文档模板, SDI 应用程序中只有一个, 而 MDI 应用程序中就可能有一个以上文档模板。应用程序

定 义了一个文档模板链表,用于管理文档模板。应用程序类

的 初始化成员函数 InitInstance 是通过以下步骤完成上述管

理:

① 定义文档模板类指针;

② 动态创建文档模板对象,并将主窗口类、视图窗口类和文

档类的动态创建信息和相应的资源索引标识作为创建参数;

③ 将创建的文档模板对象加入文档模板对象链表。

例如: CHelloApp::InitInstance() 中完成上述步骤的代码如下:CSingleDocTemplate* pDocTemplate; // 定义文档模板指针

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS( CHelloDoc ),

RUNTIME_CLASS( CMainFrame ), // main SDI frame windo

w

RUNTIME_CLASS( CHelloView ) ); // 动态创建文档模板对象

AddDocTemplate( pDocTemplate ); // 将文档模板添加到文档模板链表

⑸ 创建 “三个对象” 和 “两个窗口”

应用程序类的初始化成员函数 InitInstance 通过如下代码完成

这些动态创建工作:

// Parse command line for standard shell commands, DDE, file open

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line

if ( !ProcessShellCommand( cmdInfo ) ) return FALSE;

① CCommandLineInfo cmdInfo 用于保存程序启动的命令行信息(可通过合法修改对象的数据成员改变启动命令行)。

② ParseCommandLine( cmdInfo ) 解析命令行,填写程序的启动

标志。

③ ProcessShellCommand( cmdInfo ) 根据命令行信息标志,启动

不同种类的任务,如打开文档、创建新文档、启动打印机、

启动自动化程序等,当然可将命令行修改为不启动任务。

动态创建 “三个对象” 和 “两个窗口” 的任务就是在执行创建新

文档(调用 CWinAPP::OnFileNew )或者执行打开文档(调用

CWinApp::OnFileOpen )任务中完成的。

动态创建文档对象、文档框架对象和窗口、视图对象和窗口

以及初始化工作是调用文档模板对象的 OpenDocumentFile

()

成员函数完成的。例如 Hello 应用程序中该函数的执行流程

如下:

CWinApp::OnFileNew() CWinApp::OnFileOpen()

CWinApp::OpenDocumentFile()

用户选择文件名

根据文件类型选择文档模板

有多个文档模板?

提示用户选择一种文档模板

得到确定的文档模板对象

CSingleDocTemplate::OpenDocumntFile()或

CMultiDocTemplate::OpenDocumentFile()

否否

构造文档对象

构造文档边框窗口对象(SDI: CMainFrame, MDI: CChildFrame)

创建视图对象 (CHelloView)

CHelloView::Create(…)or

CHelloView::CreateEx(…) ③

CHelloView::PreCreateWindow()

调用 ::CreateWindowEx(…)

建立视图窗口

CHelloView::OnCreate()

是否打开文档?

CHelloDoc::OnNewDocument()

CHelloDoc::DeleteContents()

文档对象可用

CHelloView::OnInitialUpdate()

CMainFrame::Create(…) ①or

CMainFrame::CreateEx(…) ②

CMainFrame::PreCreateWindow()

调用 ::CreateWindowEx(…)

建立文档边框窗口

CMainFrame::OnCreate()

CMainFrame::OnCreateClient()

CHelloDoc::OnOpenDocument()

CHelloDoc::Serialize(CArchive& ar)

关闭 CArchive 对象和 CFile 对象

发出 WM_CREATE

Yes

No

打开文件并创建 CFile 和 CArchive 对象

图中标注:

① CWnd::Create 是虚函数, CFrameWnd::Create 也是虚函数

(在 VC 6.0 中该函数不是虚函数),但不是 CWnd::Creat

e 的

重定义版本。一般在 CMainFrame 中既不定义 CWnd::Crea

te 的

新版本,也不定义 CFrameWnd::Create 的新版本,而是调用

CFrameWnd::Create 。

②③ CWnd::CreateEx 是虚函数(在 VC 6.0 中该函数不是虚函

数),并且在 CMainFrame 和 CHelloView 中都没有定义该函数

的新版本。因此,调用 CMainFrame 类的 CreateEx 和 调用

CHelloView 类的 CreateEx , 实际上是调用 CWnd::CreateEx 。

⑹ 窗口的显示与更新

如果 ProcessShellCommand( cmdInfo ) 执行成功,则应用程序对

象的 InitInstance 继续执行 ,即显示和更新已经动态创建的窗

口,否则应用程序终止。窗口的显示和更新操作是通过指向

成功创建的文档边框窗口的指针 CWinThread::m_pMainWnd 调

用窗口的显示和更新函数实现的。例如:if (!ProcessShellCommand(cmdInfo))

return FALSE;

// The one and only window has been initialized, so show and update it.

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

return TRUE;

⑺ 启动消息循环

应用程序类对象的 InitInstance 成功返回,应用程序框架将立

即调用应用程序类对象的 Run() 函数从消息队列接收消息,

分送消息到各个窗口类对象,以便得到相应的响应处理。如

果应用程序类对象的 InitInstance 失败返回,则不启动消息循

环。

2.2.3 MFC 应用程序的启动顺序标记 为了验证 MFC 文档视图结构应用程序的启动顺序,我们在

“Hello1Hello1” 应用程序中与启动顺序有关的类成员函数中添加相应

的消息框输出语句,以便观察应用程序的启动顺序。需要添加

消息框输出语句的函数顺序如下:CHelloApp::CHelloApp()

CHelloApp::InitInstance()

CHelloDoc::CHelloDoc()

CMainFrame::CMainFrame()

CMainFrame::PreCreateWindow( CREATESTRUCT& cs )

CMainFrame::OnCreate( LPCREATESTRUCT lpCreateStruct )

CMainFrame::OnCreateClient(…) *

CHelloView::CHelloView()

CHelloView::Create(…) *

CHelloView::PreCreateWindow( CREATESTRUCT& cs )

CHelloView::OnCreate( LPCREATESTRUCT lpCreateStruct ) **

CHelloDoc::DeleteContents() *

CHelloDoc::OnNewDocument() *

CHelloDoc::OnOpenDocument() *

CHelloView::OnInitialUpdate() *

CHelloApp::InitInstance()

其中:

* 需要新增的重载虚函数。

注意,在 Visual C++ .NET 中, CHelloDoc::OnNewDocument()

已被

缺省重载了。

** 需要增加的消息响应函数。

编译运行添加标记的 Hello 应用程序,这不但可以了解应用程

序的启动顺序还可以了解每个被标记函数的主要功能,这对于

了解向框架的什么地方增加代码很有帮助。

2.3 MFC 应用程序框架的基本类 MFC 是一个非常庞大(类的数量大,类所涉及的领域多),

层次结构分明、合理的基类集合。它为程序工作者提供了从构

造程序框架到完成程序的每一个细节的丰富的标准基类和构造

用户自定义类的规则和方法。 MFC 中的绝大部分类都是从根基

类 CObject 派生的,该根基类支持绝大多数 MFC 类所需要的动

态性、诊断性和持续性三大性能的基础功能:

· 动态性:在程序运行时,可以动态获取类的大小、类名等信

息,可以动态创建类的实例;这种特性要解决的问题相当于

在运行时,询问 “我是谁,如何创建我?” 。

·诊断性:能把对象的状态转移给调试机构(通过 AssertValid

和 Dump 方法实现);这种特性要解决的问题相当于对当前

对象询问 “我的数据成员是什么,合法有效吗?”。

·持续性:能把对象的数据存入文件或从文件提取数据重建对

象。相当于在运行时,询问 “如何保存和读取我?” 。

这是因为 CObject 的派生类对三大性能所需要具备的功能是

不一致的,因此希望派生类从 CObject 只直接获得三大性能的

支持机制和基本功能,而借助宏定义工具为那些需要具有更强

大的三大性能支持的派生类提供不同程度扩展功能。这种方法

不但有利于根据功能需要确定类的规模,还有利于系统的功能

扩展。

从前面的叙述中,可以清楚地知道类对象的动态创建功能就

是通过 DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE 这对

宏定义扩展实现的,其他方面性能的扩展实现与此类同。

从 CObject 直接派生的类 CCmdTarget 除了能支持三大性能,

还支持命令消息的响应处理,因此, CCmdTarget 类成为 MFC

所有需要响应和处理消息的类的直接或间接基类,例如 CWnd 、

CWinThread 、 CDocument 等。其中 CWnd 由于拥有窗口的基本功

能,又成为 MFC 中所有需要窗口功能支持的类的基类。

2.3.1 基本类及其作用 MFC ApppWizard 创建 MFC 应用程序时,是从以下四个基本类

派生的。

1 CWinApp

应用程序类,负责程序的初始化和运行。在进程中第一个被

创建,最后一个被撤消,负责创建程序框架的其他类对象,

例如主窗口对象、视图对象和文档对象。

派生类的缺省命名规则: CXXXApp 。

2 CFrameWnd

框架窗口类,负责进程主窗口的创建、显示以及相应消息的

响应、处理。

SDI :直接使用 CFrameWnd 框架窗口的基类。

MDI :使用 CFrameWnd 的派生类 CMDIFrameWnd 作为主框架

窗口的基类,还需要使用 CFrameWnd 的另一个派生类

CMDIChildWnd 作为子框架窗口的基类。

派生类的缺省命名规则:

SDI : CMainFrame

MDI :主框架窗口 CMainFrame ,子框架窗口 CChildFrame 。

3 CDocument

文档类,负责装载、保存和维护文档,文档包括应用程序的

工作数据或环境设置数据等,即程序需要保存和装载的任何

内容并处理相应的消息。 派生类的缺省命名规则: CXXXDoc 。4 CView

视图类,负责为文档提供一个或多个视图,视图的作用是为

修改、查询文档数据提供人机交互界面并处理相应的消息。 应用程序的视图类可以直接从 CView 派生,也可将 CVie

w 的 直接或间接派生类:

CTreeView 、 CEditView 、 CFormView 、 CListView 、 CScrollView

等 作为基类。 派生类的缺省命名规则: CXXXView 。

2.3.2 基本类与 SDI 、 MDI 的程序框架 对于 SDI 应用程序,应用程序类、文档模板与三个基本

类的

关系如下图:应用程序类 (CXXXApp) 对象 文档模板类 (CSingleDocTemplate) 对象

文档类(CXXXDoc)

对象

框架窗口类 (CMainFrame) 对象

视图类 1(CXXXView1) 对象

视图 2(CXXXView2) 对象

视图 n(CXXXViewn) 对象

对于 MDI 应用程序,应用程序类、文档模板与三个基本类的

关系如下图: 应用程序类 (CXXXApp) 对象

文档模板链表

文档模板类 (CMultiDocTemplate) 对象 1 文档模板类对象 2 文档模板类对象 n

文档类 (CXXXDoc)对象

框架窗口 (CMainFrame ,基类为 CMDIFrameWnd)

子框架窗口 n(CChildFramen, 基类为 CMDIFrameWnd)对象

子框架窗口 2(CChildFrame2, 基类为 CMDIFrameWnd)对象

子框架窗口 1(CChildFrame1, 基类为 CMDIFrameWnd)对象

视图类 1(CXXXView1) 对象

视图类 2(CXXXView2) 对象

视图类 n(CXXXViewn) 对象

文档类 (CXXXDoc)

2.4 MFC 应用程序框架的基本类之间的相互访问

2.4.1 SDI 应用程序框架中基本类对象之间的相互访问

POSITIONpos=GetFirstViewPosition()GetNextView(pos)

AfxGetMainWnd() AfxGetApp()

视图类 (CXXXView)

框架窗口类 (CMainFrame)

应用程序类(CXXXApp)

GetActiveDocument()

GetActiveView()

GetParent()

GetParentFrame()

GetDocument()

UpdateAllViews()

m_pMainWnd

1 所谓访问关系仅限于同一进程中。

2 各类图中的函数均为该类的成员函数,类图外的函数为全程

函数。

3 箭头所指方向表示该函数或能返回箭头所指类对象的指针或

能对所指类进行某种操作:·AfxGetApp()

在程序的任何处能返回应用程序类对象指针;例如:CWinApp *App = AfxGetApp();

CXXXApp *TheApp = (CXXXApp *)AfxGetApp();

·AfxGetMainWnd()

在程序的任何处能返回框架窗口类对象指针;例如:CWnd *pWnd = AfxGetMainWnd();

CMainFrame *pMainWnd = (CMainFrame *)AfxGetMainWnd();

·GetActiveDocument()

从框架窗口对象中返回文档对象指针;例如:CDocument *pDoc = GetActiveDocument();

CXXXDoc pDocu = (CXXXDoc*)GetActiveDocument();

·GetActiveView()

从框架窗口对象中返回当前视图对象指针;例如: CView *pView = GetActiveView();

CXXXView pV = (CXXXView*)GetActiveView();

·GetParent()

从视图对象中返回框架窗口对象指针;例如:CFrameWnd *pFrame = GetParent();

CMainFrame pFrameWnd = (CMainFrame*)GetParent();

·GetParentFrame()

从视图对象中返回框架窗口对象指针;·GetDocument()

从视图类对象中返回文档类对象指针;例如:CDocument *pDoc = GetDocument();

CXXXDoc *pDocu = (CXXXDoc*)GetDocument();

·GetFirstViewPosition()

在文档对象的第一个视图对象中的位置;例如:POSITION pos = GetFirstViewPosition();

·GetNextView(pos)

根据参数 pos 中的视图类对象的位置,获取下一个视图类对象指针。

CView *pView = GetNextView(pos);

CXXXView *pV = (CXXXView*)GetNextView(pos);

·UpdateAllView()

在文档对象中,按文档当前内容更新与其相关的所有视图窗口的显示。

文档类 (CXXXDoc)

框架窗口类 (CMainFrame)

2.4.2 MDI 应用程序框架中基本类对象之间的相互访问

POSITIONpos=GetFirstViewPosition()GetNextView(pos)

AfxGetMainWnd() AfxGetApp()

应用程序类(CXXXApp)

视图类 (CXXXView)

子框架窗口类 (CChildFrame)

MDIGetActive()GetActiveFrame()

GetActiveDocument()

GetActiveView()

GetParent()GetParentFrame()

GetDocument()

UpdateAllViews()

m_pMainWnd