MFC 类别主要可分为下列数大群组:

■ General Purpose classes - 提供字符串类别、数据处理类别(如数组与串行),异

常情况处理类别、文件类别...等等。

■ Windows API classes - 用来封包Windows API,例如窗口类别、对话框类别、

DC 类别...等等。

■ Application framework classes - 组成应用程序骨干者, 即此组类别, 包括

Document/View、消息邦浦、消息映射、消息绕行、动态生成、文件读写等等。

■ high level abstractions - 包括工具栏、状态列、分裂窗口、卷动窗口等等。

■ operation system extensions - 包括OLE、ODBC、DAO、MAPI、WinSock、ISAPI

等等

CObject

绝大部份类别库,往往以一个或两个类别,做为其它绝大部份类别的基础。MFC 亦复如

此。CObject 是万类之首,凡类别衍生自CObject 者,得以继承数个对象导向重要性质,

包括RTTI(执行时期型别鉴识)、Persistence(对象保存)、Dynamic Creation(动态生

成)、Diagnostic(错误诊断)。本书第3章对于这些技术已有了一份DOS 环境下的模

拟,第8章另有MFC 相关源代码的探讨。其中,「对象保存」又牵扯到CArchive,「诊

断」又牵扯到CDumpContext,「执行时期型别鉴识」以及「动态生成」又牵扯到

CRuntimeClass。

数据处理类别(collection classes)

所谓collection,意指用来管理一「群」对象或标准类型的资料。这些类别像是Array 或List

或Map 等等,都内含针对元素的「加入」或「删除」或「巡访」等成员函数。Array

(数组)和List(串行)是数据结构这门课程的重头戏,大家比较熟知,Map(可视之

为表格)则是由成双成对的两两对象所构成,使你很容易由某一对象得知成对的另一物

件;换句话说一个对象是另一个对象的键值(key)。例如,你可以使用String-to-String

Map,管理一个「电话-人名」数据库;或者使用Word-to-Ptr Map,以16 位数值做为

一个指针的键值。

最令人侧目的是,由于这些类别都支持Serialization,一整个数组或串行或表格可以单一一进程序代码就写到文件中(或从文件读出)。第8章的Scribble Step1 范例程序中你就会

看到它的便利。

MFC 支持的collection classes 有:

一进程序代码就写到文件中(或从文件读出)。第8章的Scribble Step1 范例程序中你就会

看到它的便利。

CRect - 封装Windows 的RECT 结构。这个类别在Windows 环境中特别有用,

因为CRect 常常被用作MFC 类别成员函数的参数。

■ CSize - 封装Windows 的SIZE 结构。

■ CPoint - 封装Windows 的POINT 结构。这个类别在Windows 环境中特别有用

因为CPoint 常常被用作MFC 类别成员函数的参数。

■ CTime - 表现绝对时间, 提供许多成员函数, 包括取得目前时间( static

GetCurrentTime)、将时间资料格式化、抽取特定字段(时、分、秒)等等。它

对于+、-、+=、-+ 等运算子都做了多载动作。

■ CTimeSpan - 以秒数表现时间,通常用于计时码表。提供许多成员函数,包括把

秒数转换为日、时、分、秒等等。

<!--[if !supportLists]-->■    <!--[endif]-->CString - 用来处理字符串。支持标准的运算子如=、+=、< 和>。

异常处理类别(exception handling classes)

所谓异常情况(exception),是发生在你的程序执行时期的不正常情况,像是文件打不

开、内存不足、写入失败等等等。我曾经在第2章最后面介绍过异常处理的观念及相

关的MFC 类别,并在第4章「Exception Handling」一节介绍过一个简单的例子。与「异常处理」

Windows API classes

这是MFC 声名最著的一群类别。如果你去看看源代码,就会看到这些类别的成员函数

所对应的各个Windows API 函数。

■ CWinThread - 代表MFC 程序中的一个执行线程。自从3.0 版之后,所有的MFC

类别就都已经是thread-safe 了。SDK 程序中标准的消息循环已经被封装在此

一类别之中(你会在第6章看到我如何把这一部份开膛剖肚)。

■ CWinApp - 代表你的整个MFC 应用程序。此类别衍生自CWinThread;要知

道,任何32 位Windows 程序至少由一个执行线程构成。CWinApp 内含有用

的成员变量如m_szExeName, 放置执行档档名, 以及有用的成员函数如

ProcessShellCommand,处理命令列选项。

■ CWnd - 所有窗口,不论是主框窗口、子框窗口、对话框、控制组件、view 视

窗,都有一个对应的C++ 类别,你可以想象「窗口handle」和「C++ 对象」

结盟。这些C++ 类别统统衍生自CWnd,也就是说,凡衍生自CWnd 之类别才

能收到WM_ 窗口消息(WM_COMMAND 除外所谓「窗口handle」和「C++ 对象」结盟,实际上是CWnd 对象有一个成员变

m_hWnd,就放着对应的窗口handle。所以,只要你手上有一个CWnd 对象

CWnd 对象指针,就可以轻易获得其窗口handle:

HWND hWnd = pWnd->m_hWnd;

■ CCmdTarget CWnd 的父类别。衍生自它, 类别才能够处理命令消息

WM_COMMAND。这个类别是消息映射以及命令消息绕行的大部份关键,我将

在第9章推敲这两大神秘技术。

<!--[if !supportLists]-->■    <!--[endif]-->GDI 类别、DC 类别、Menu 类别。

Application framework classes

这一部份最为人认知的便是Document/View,这也是使MFC 跻身application framework

的关键。Document/View 的观念是希望把资料的本体,和资料的显像分开处理。由于文

件产生之际,必须动态生成Document/View/Frame 三种对象,所以又必须有所谓的

Document Template 管理之。

■ CDocTemplateCSingleDocTemplateCMultiDocTemplate - Document Template 扮演

黏胶的角色,把Document 和View 和其Frame(外框窗口)胶黏在一块儿。

■ CSingleDocTemplate 一次只支持一种文件类型,CMultiDocTemplate 可同时支持多

种文件类型。注意,这和MDI 程序或SDI 程序无关,换句话说,MDI 程序

也可以使用CSingleDocTemplate,SDI 程序也可以使用CMultiDocTemplate

但是,逐渐地,MDI 这个字眼与它原来的意义有了一些出入(要知道,这个字眼早

在SDK 时代即有了)。因此,你可能会看到有些书籍这么说:MDI 程序使用

CMultiDocTemplate,SDI 程序使用CSingleDocTemplate

■ CDocument - 当你为自己的程序由CDocument 衍生出一个子类别后,应该在其

中加上成员变量,以容纳文件资料;并加上成员函数,负责修改文件内容以及

读写档。读写文件由虚拟函数Serialize 负责。第8章的Scribble Step1 范例程序

有极佳的示范。

■ CView - 此类别负责将文件内容呈现到显示装置上:也许是屏幕,也许是打印

机。文件内容的呈现由虚拟函数OnDraw 负责。由于这个类别实际上就是你在

屏幕上所看到的窗口(外再罩一个外框窗口),所以它也负责使用者输入的第

一线服务。例如第8章的Scribble Step1 范例,其View 类别便处理了鼠标的

按键动作

High level abstractions

视觉性UI 对象属于此类,例如工具栏CToolBar、状态列CStatusBar、对话框列

CDialogBar。加强型的View 也属此类,如可卷动的ScrollView、以对话框为基础的

CFormView、小型文字编辑器CEditView、树状结构的CTreeView,支持RTF 文件格式

CRichEditView 等等。

Afx 全域函数

还记得吧,C++ 并不是纯种的对象导向语言(SmallTalk 和Java 才是)。所以,MFC

之中得以存在有不属于任何类别的全域函数,它们统统在函数名称开头冠以Afx

下面是几个常见的Afx 全域函数:

函数名称 说明

AfxWinInit WinMain(由MFC 提供)调用的一个函数,用做MFC GUI

程序初始化的一部份,请看第6章的「AfxWinInit - AFX 内部

初始化动作」一节。如果你写一个MFC console 程序,就得

自行调用此函数(请参考Visual C++ 所附之Tear 范例程序)。

AfxBeginThread 开始一个新的执行线程(请看第14 章,# 756 页)。

AfxEndThread 结束一个旧的执行线程(请看第14 章,# 756 页)。

AfxFormatString1 类似printf 一般地将字符串格式化。

AfxFormatString2 类似printf 一般地将字符串格式化。

AfxMessageBox 类似Windows API 函数MessageBox

AfxOutputDebugString 将字符串输往除错装置(请参考附录D,# 924 页)。

AfxGetApp 取得application object(CWinApp 衍生对象)的指针。

AfxGetMainWnd 取得程序主窗口的指针。

AfxGetInstance 取得程序的instance handle。

AfxRegisterClass 以自定的WNDCLASS 注册窗口类别(如果MFC 提供的数个

窗口类别不能满足你的话)。

MFC 宏(macros)

CObject 和CRuntimeClass 之中封装了数个所谓的object services,包括「取得执行时期

的类别信息」(RTTI)、Serialization(文件读写)、动态产生对象...等等。所有衍生自CObject的类别,都继承这些机能。我想你对这些名词及其代表的意义已经不再陌生-- 如果你没

有错过第3章的「MFC 六大技术仿真」的话。

■ 取得执行时期的类别信息(RTTI),使你能够决定一个执行时期的对象的类别

信息,这样的能力在你需要对函数参数做一些额外的类型检验,或是当你要针

对对象属于某种类别而做特别的动作时,份外有用。

■ Serialization 是指将对象内容写到文件中,或从文件中读出。如此一来对象的

生命就可以在程序结束之后还延续下去,而在程序重新激活之后,再被读入。

这样的对象可说是"persistent"(永续存在)。

■ 所谓动态的对象生成(Dynamic object creation),使你得以在执行时期产生一

个特定的对象。例如document、view、和frame 对象就都必须支持动态对象

生成,因为framework 需要在执行时期产生它们(第8章有更详细的说明)。

此外,OLE 常常需要在执行时期做对象的动态生成动作。例如一个OLE server 程序必

须能够动态产生OLE items,用以反应OLE client 的需求。

MFC 针对上述这些机能,准备了一些宏,让程序能够很方便地继承并实作出上述四大

机能。这些宏包括:

宏名称 提供机能 出现章节

DECLARE_DYNAMIC 执行时期类别信息 第3章、第8章

IMPLEMENT_DYNAMIC 执行时期类别信息 第3章、第8章

DECLARE_DYNCREATE 动态生成 第3章、第8章

IMPLEMENT_DYNCREATE 动态生成 第3章、第8章

DECLARE_SERIAL 对象内容的文件读写 第3章、第8章

IMPLEMENT_SERIAL 对象内容的文件读写 第3章、第8章

DECLARE_OLECREATE OLE 对象的动态生成 不在本书范围之内

IMPLEMENT_OLECREATE OLE 对象的动态生成 不在本书范围之内

我也已经在第3章提过MFC 的消息映射(Message Mapping)与命令绕行(Command

Routing)两个特性。这两个性质系由以下这些MFC 宏完成:

宏名称 提供机能 出现章节

DECLARE_MESSAGE_M A P 声明消息映射表数据结构 第3章、第9章

BEGIN_MESSAGE_MAP 开始消息映射表的建置 第3章、第9章

ON_COMMAND 增加消息映射表中的项目 第3章、第9章

ON_CONTROL 增加消息映射表中的项目 本书未举例

ON_MESSAGE 增加消息映射表中的项目 ???

ON_OLECMD 增加消息映射表中的项目 本书未举例

ON_REGISTERED_MESSAGE 增加消息映射表中的项目 本书未举例

ON_REGISTERED_THREAD_

MESSAGE

增加消息映射表中的项目 本书未举例

ON_THREAD_MESSAGE 增加消息映射表中的项目 本书未举例

ON_UPDATE_COMMAND_UI 增加消息映射表中的项目 第3章、第9章

END_MESSAGE_MAP 结束消息映射表的建置 第3章、第9章

事实上,与其它MFC Programming 书籍相比较,本书最大的一个特色就是,要把上述

这些MFC 宏的来龙去脉交待得非常清楚。我认为这对于撰写MFC 程序是非常重要

的一件事。

MFC 数据类型(data types)

下面所列的这些数据类型,常常出现在MFC 之中。其中的绝大部份都和一般的Win32

程序(SDK 程序)所用的相同。

下面这些是和Win32 程序(SDK 程序)共同使用的数据类型:

数据类型意义

BOOL Boolean 值(布尔值,不是TRUE 就是FALSE)

BSTR 32-bit 字符指针

BYTE 8-bit 整数,未带正负号

COLORREF 32-bit 数值,代表一个颜色值

DWORD 32-bit 整数,未带正负号

LONG 32-bit 整数,带正负号

LPARAM 32-bit 数值,做为窗口函数或callback 函数的一个参数

LPCSTR 32-bit 指针,指向一个常数字符串

LPSTR 32-bit 指针,指向一个字符串

LPCTSTR 32-bit 指针,指向一个常数字符串。此字符串可移植到Unicode 和DBCS(双

字节字集)

LPTSTR 32-bit 指针,指向一个字符串。此字符串可移植到Unicode 和DBCS(双位

组字集)

LPVOID 32-bit 指针,指向一个未指定类型的资料

LPRESULT 32-bit 数值,做为窗口函数或callback 函数的回返值

UINT 在Win16 中是一个16-bit 未带正负号整数,在Win32 中是一个32-bit

未带正负号整数。

WNDPROC 32-bit 指针,指向一个窗口函数

WORD 16-bit 整数,未带正负号

WPARAM 窗口函数的callback 函数的一个参数。在Win16 中是16 bits,在Win32

中是32 bits。

下面这些是MFC 独特的数据类型:

数据类型 意义

POSITION 一个数值,代表collection 对象(例如数组或串行)中的元素位置。常使用

于MFC collection classes。

LPCRECT 32-bit 指针,指向一个不变的RECT 结构。

前面所说那些MFC 数据类型与C++ 语言数据类型之间的对应,定义于WINDEF.H

中。我列出其中一部份,并且将不符合(_MSC_VER >= 800) 条件式的部份略去。

 
05-22 03:12