From COM to COM
-- 侯捷
摘要:
本文简介 C++ Object Model 和 Component Object Model 的基本概念,并引介
四本书籍:
1. Inside The C++ Object Model
2. Essential COM
3. Inside COM
4. Understanding ActiveX and OLE -- A Guide for Developers & Managers
将近 8 年的时间,我把自己放逐在 Windows 领域里,纵情学习与研究。我应该
算是幸运的一群人之一,在 PC 软体工业起飞的年代,一步步地抓住技术提升上
来。我的那一票工程师朋友们,因为在职的缘故,整天但求把专案完工了结尚不
可得,实在难有好好沉淀心得、充电进修的时光。有一位朋友苦於整体技术的盘
根错节,就曾感慨地说,如果能够循序渐进地学习,该有多好!还有一位读者写
信来对我说:沉浸在书籍里的学习滋味,真是曼妙。
可惜,世界不等待我们。我们也只好采取「跳岛策略」。
在这麽多年的技术研究中,我感觉自己像在玩拼图游戏。以程式语言始,以作业
系统终,其间包括 C、C++、Java、SDK、MFC、VxD、Win32 OS、Multithreading
、C++ STL、Internet Protocol...。我望着手上这块拼图,感觉外界的一切变化
,差不多可以在我的手心里头掌握了。不管再有新发展出的什麽物件导向语言、
什麽 application framework、或是什麽新的driver model、新的 protocol,我
都觉得因为掌握了基本知识,而得以触类旁通,举一隅以三隅反。就算是换一个
作业系统,我都觉得由於我对 processes、threads、modules、address space、
executable file format 的认识,使我可以轻而易举地易地而行。是的,我感觉
一种前所未有的安定。
然後我审视我的技术蓝图,发现还有一块空白没有填上。那其实是多年来的梦魇
叫做 OLE 的东西。那东西从面世到今天,不断地成长,已经和大树一样了。它不
但分割出 COM 底层架构,又在 Internet 当道之际,加入更多特质,幻化为 Ac
tiveX。
过去我也曾经在 OLE 身上下了很大的功夫,甚至也得到一些至今看来仍觉不错的
成果。我常常在检阅以前读过的 OLE 书籍时,看到密密麻麻的心得眉批以及用
Word 和 Powerpoint 做出来的精美心得,还有已经完成的部份书稿,惊讶地发现
自己原来也已经钻研到那样的一个程度。然而也总是在片刻的陶醉之後,心里深
处浮现一个小小的声音问自己:为什麽现在全都忘了?
●Know How 与 Know Why
就好像骨钙的补充一样,重要的不在吸收多少,而在留下多少。 我一再遗忘曾经
掌握的 COM/OLE 技术,原因恐怕是,我并没有扎扎实实地把相关知识奠定好基础
。我也许学到了不少 how,但我不知道 why。对於原理的不了解,使我没有办法
留住我所吸收的养份。
这与我向来的研究精神悖离。但寻寻觅觅好久,我并没有找到理想的文献,能够
把 OLE(其实应该说是 COM)基本原理交待清楚。我甚至不知道是否真的有那样
的文章或书籍。其实我只需要最根源的那一部份。悟了最根源的部份,我就有能
力度化自己了。
在很偶然的情况下,我凑齐了两本书,才终於整合出潜意识寻寻觅觅而不自知的
东西。
说是偶然,何尝不是日积月累的周边知识所导至的因缘俱足?
●两本好书
我所说的这两本书是 Inside The C++ Object Model 和 Essential COM。请注意
,它们都在讲 object model,一本针对 C++,一本针对 components(软体元件
)。
早些年我曾经对 C++ objects 在记忆体中的布局有很大的兴趣,也整理出虚拟机
制底层建设的一些心得(当时我并不知道这个知识领域被称为 C++ Object Mode
l)。所以当我翻看 Inside The C++ Object Model 三两页,直觉告诉我,这正
是我一直希望拥有的一本书。事实上它已出版两年了,我真是後知後觉!
拿到上一本书的同一时间,我也拿到了最新出版的Essential COM。此书前两章介
绍 COM 的 "why",正是我所亟需。我感觉讨论「为什麽需要 COM」这一主题所需
要的技术背景之中,好多正是 C++ Object Model 所涵盖的范围。而且,Essent
ial COM 的作者 Don Box 竟然也在书中第 16 页大力向读者推荐 Inside The C
++ Object Model 一书。这不是因缘俱足吗?我自己的发掘与 Don Box 的推荐,
两相映和,快乐难以形容。
这一次,就让我为大家铺一条从 C++ Object Model 通往Component Object Mod
el 的大道。
●倒叙
恐怕我得用倒叙的方式,才能让你明了(并且认同),为什麽学习标榜着「与程
式语言无关」的 COM,却需要先有 C++ 语言的某种非常深层结构的(属於编译器
层次的)基础。
认真地想想这个问题:我的硬碟中同时存在有MFC20.DLL、MFC40.DLL、MFC41.DL
L、MFC42.DLL、MFC50.DLL...,为什麽会这样?因为版本更新时,我懒得去整理
硬碟。现在我想到了,看到了,但是我敢动手砍掉它们,只保留最新版本吗?我
不敢,因为我不确定我的哪一个应用软体使用哪一版 DLLs。我宁愿多花一点磁碟
空间来放置所有历史陈迹 -- 反正硬碟也便宜!
一个回避的方法就是,乾脆软体开发人员都不要使用DLLs,都用静态联结(stat
ic linking)算了!这是「因噎废食」的最佳写照。有这种念头,我就走入历史
的反动了。要知道,DLLs 是一种可重复使用的模组,不必因为 client(呼叫端
)的改变而重新编译联结。反方向说,DLL 若更新也不必与 client 重新联结(
如果介面未改的话)。不使用 DLLs,每一个应用软体都会变成超级大胖子,这是
问题之一。不使用 DLLs,应用软体的开发过程会遭受重大阻碍,执行时严重浪费
资源(尤其是记忆体),这是问题之二。
所以软体工程师们决定继续使用 DLLs。假设我出厂一批DLL 1.0,一年後决定修
改其中的某个 class,为它加上一笔 private data。当与 1.0 同档名的 DLL 2
.0 被安装到使用者硬碟中,旧版 DLL 被覆盖掉。对於新的应用程式(DLL 2.0
的呼叫者),这当然没问题。但当那些原本呼叫 DLL 1.0 的应用程式被执行起来
,系统可能当掉!
为什麽?C++ 不是支援资料封装吗?新加的 DLL 资料不是 private 吗?client
永远不可能直接存取那笔资料呀!话虽不错,但 C++ 向来只靠 private 和 pr
otected 两个保留字提供语意上的封装,并没有提供二进位层次(binary level
)的封装。C++ 编译器必须对物件的实体布局有完全的掌握(二进位上的掌握)
,才有办法制造出一个物件实体;上述例子新加入的一笔 private 资料改变了物
件实体的记忆体布局,旧的 client 呼叫新的 DLL,呵呵,不当掉是运气!
解决方法就是目前习用的「以不同的 DLL 档名代表不同的版本」,像 Microsof
t 对其 Visual C++、Visual Basic 的所做所为一样。这是一种锯箭法,回避了
问题,但没有解决问题。
●Binary Level
真正要解决这个问题,必须让 DLL 这一端的任何改变,都不必引起 client 端的
任何变化。真正的封装,必须把「物件看起来像什麽」和「物件实际上如何工作
」彻底分隔开来。这样的原则在一般的 C++ object 二进位层级(bineary leve
l)中无法施行(为什麽?说来话长,这属於 C++ Object Model 的范畴)。但如
果我们把原本的 C++ class 改装为一个 interface class 和一个 implementat
ion class 的组合,就可以办到。Implementation class 以 DLL 的形式出现,
而 interface class 成为 implementation class 的一个基础类别,其间没有任
何资料(data members),只有欲开放之 implementation class methods 的各
个函式宣告。你猜对了,这些宣告统统被设计为纯虚拟函式。纯虚拟函式并不是
唯一一种作法,却是最佳作法。
Interface class 负责和 client 联结,形成 client 和object DLL(implemen
tation class)之间的一道防火巷,完成所谓的二进位封装!
除了软体版本冲突,另一个问题也有待解决。由於各家 C++ 厂商对於 mangling
(函式名称改装)的作法不一,没有标准,在 C++ 平台A中所制作的 classes
DLL,不保证能在 C++ 平台B中被使用。上述把 interface 和implementation
分开的作法,可以解决所谓编译器不相容的问题。此外,对於 runtime polymor
phism 也有帮助,对於 object extensibility 也有帮助。
●所谓 Components
受到二进位防火巷保护,并且免除 name mangling 困扰的objects,就是所谓的
components。它不自限於使用哪一种C++ 编译器来开发,甚至不自限於使用哪一
种程式语言。事实上,Component Object Model 是一个规格,只不过这个规格最
贴近 C++ 虚拟函式的实作方式罢了。同类型的规格还有 System Object Model(
SOM)和 Common Object Request Broker Architecture(CORBA)。
我想你已经看到了,要了解 COM,唯有先了解「为什麽需要 COM」。要了解「为
什麽需要 COM」,又必须先了解「C++(或目前的任何语言)为什麽做不到」。而
要了解「C++ 为什麽做不到」,就必须了解「C++ 物件模型」是怎麽一回事。
■Inside the C++ Object Model
作者:Stanley B. Lippman
出版公司:Addison Wesley
出版日期:1996 页数:7 章,280 页
售价:书上没有标示定价(本书无磁片)
1. Object Lessons
2. The Semantics of Constructors
3. The Semantics of Data
4. The Semantics of Function
5. Semantics of Construction, Destruction, and Copy
6. Runtime Semantics
7. On the Cusp of the Object Model
在 C++ 成山似海的书籍堆中,这一本并不是婴幼儿奶粉,也不是较大婴儿奶粉,
它是成人专用的低脂高钙特殊奶粉。
我曾经在几次 C++ 课程或 MFC 课程中,为学员补充一些有关於 C++ objects 在
记忆体中的长像与栏位布局的资料、以及虚拟函式的实作技术、类别继承後的物
件内容、隐藏的 this 指标...等等议题,受到很大的欢迎。这些反应,都不脱我
的预料:工程师渴望知道底层的东西。
很多人疑惑我为什麽知道这些底层知识(早些年还有人认为我大概拥有Microsof
t 或其他什麽公司的後门管道 -- 这是我的朋友在某个技术研讨会场上听到讲师
当众说的)。这些知识一部份是从各式各样的技术文件或某一本书或某一篇文章
断简残篇地获得,一部份是自己实际写点小程式做实验而得。
我以杂学的方式对 C++ 物件模型所整理出来的轮廓,说起来还粗浅得很。1997
年底不经意地发现了这本Inside The C++ Object Model,这才把自己的缺憾完全
弭补过来。
这本外表毫不起眼的小书,又薄又窄,比一般原文书的大号尺码小得多。乾乾瘦
瘦,才 280 页。「俗艳的」封面设计再加上微黄的纸张,原本引不起我多大的兴
趣。但是作者大名使我在上面多瞧了两眼(Lippman 着有 C++ Primer,与Bjarn
e Stroustrup 的 The C++ Programming Language 齐名,目前已是第三版)。这
一瞧不得了,开始有点「漫卷诗书喜欲狂」的感觉。後来在 Essential COM 身上
看到 Don Box 推荐这本书:"...Consult Stan Lippman's most excellent Ins
ide the C++ Object Model for a great discussion of both techniqies." 我
同意 Don Box 所言,这本书的确 "most excellect"。
本书返朴归真,不仅外貌如此,内容也如此。所谓 C++ 物件模型,闻之令人丧胆
,彷佛和什麽 OOA/OOD 有关。Lippman 在其前言中谈到,C++ 物件模型有两个切
入点:
1. 对於语言所提供之物件导向程式设计的直接支援
The direct support for object-oriented programming provided within the
language
2. 用以实作出上述支援的底层机制
The underlying mechanisms by which this support is implemented
本书谈的是第二个切入点。如果你对於物件和资料的组成有浓烈兴趣,第一章的
Object 和第三章的 Data 一定可以满足你。不管类别继承方式是 virtual、si
ngle 或 multiple,资料属性是 static、global 或 local,这两章都有所讨论
,并在关键处以图片表示。这部份如果没有以图片来表示,就不值得我的推荐了
,毕竟要从文字叙述中构想出资料栏位的布局,委实太过辛苦。本书示意图虽然
从美学的角度上可用「丑陋」来形容,不过尚足够清楚表现出作者的意念,於功
能上我想也够了。
如果你对几个基本的成员函式如 default constructor、copy constructor、vi
rtual destructor,以及对於各类型函式如 global、virtual、static 的底层运
作感兴趣,第二章的 Constructor、第四章的 Function、以及第五章的「建构、
解构和拷贝」绝对可以满足你。第六章续谈函式,并谈到 new 和 delete 两个运
算子。第七章谈 C++ 的三大扩充:template、Exception、runtime type ident
ification(RTTI)。
针对各个主题,Lippman 都涵盖设计的由来、版本的演进、以及标准和实务两种
作法,并对某些主题提出不同平台(platform)的效率测试结果。这本书基本上
是以较学术的方式来撰写,所以在数据的处理以及叁考资料的整理方面,都很仔
细。
说到学术,应该就是严谨的代名词。但是这本书的笔误大约有 100 个。我不敢乱
说,侯俊杰先生正在译这本书,他列了一份原文勘误表出来,密密麻麻。其中的
C++ 明显语法错误,比较无伤大雅,杀伤力也有限,然而像程式码符号名称与内
文叙述不一致,或是物件布局的图解与程式码的宣告不一致,都会严重误导读者
的心力。以此观之,说实在,本书虽然到处都有牛肉,但某些部位的烹调水准,
实在有损 Lippman 的大师声誉。
280 页的厚度,以现今动辄千儿八百页的满汉大餐来说,宛如一盘小菜。但是呛
辣带劲儿,不是练家子不易下咽。这不是一本 C++ 初学者看的书,对於没有专案
压力、没有考试压力、有治学精神的人,侯捷强力推荐。
■Essential COM
作者:Don Box
出版公司:Addison Wesley
出版日期:1998
页数:7 章,440 页
售价:US$ 34.95(无磁片)
1. COM as a Better C++
2. Interfaces
3. Classes
4. Objects
5. Apartments
6. Applications
7. Miscellanea
A. The Evolution of Objects
B. Selected Code Fragements
所有在 Microsoft 平台上讨生活的软体工程师,没有人不知道 COM/OLE/Active
X 的重要性,没有人不想了解并进而熟练这项技术。坊间不是没有好书,例如 I
nside OLE (Fraig Brockschmidt/Microsoft Press/1995)就几乎是每一本相关
着作都要列入 Bibliography 或 Reference 的经典。但是该书很像一本「有许多
字的天书」,侯捷也在上面爬得很辛苦。
究其因,早期大家对於 Object Model 的程度不够,学习起 COM/OLE 来很吃力。
慢慢大家书看得多了,在实际开发工作上运用 C++/OO,也有一些经验了,再来学
习 COM/OLE,比较能够渐入佳境。
另一个原因是,能够把 COM 来龙去脉说得一清二楚的好书,过去绝少。我不能够
说没有这样的书,也许是自己孤漏寡闻。众里寻它千百度,现在它来了,就是这
本 Essential COM。
●关於 Don Box
作者 Don Box 在 COM/OLE 这一领域可说是赫赫有名。他在 Microsoft Systems
Journal(MSJ)主持一个 ActiveX/COM 问答专栏,早就显露了卓越的实力。让
我节录本书两篇序文对於 Don Box 的赞誉给你瞧瞧。你说得对,序文哪有不吹捧
作者的,欢乐一家亲嘛,不过用词遣字之间你还是可以感受胡乱吹捧和诚恳推荐
之间的大不同:
第一篇序文:Charlie Kindel COM guy, Microsoft Corporation
如果有一本英文书谈的是 COM、DCOM、OLE 或 ActiveX,而我也读过它,你几乎
一定会发现我的名字被列在技术检阅那一栏,做为信誉保证。我自己也写了许多
这方面的技术文章,我同时也是 COM Specification 的主要编辑。我给过无数的
COM 简报,不管对象是技术人员或非技术人员。很明显,我花了许多时间和精力
,尝试找出 COM 的最佳说明方法。
当我读过这本书的最後草稿,我明白我所有的努力都白费了。关於 COM,没有任
何人能阐释得比 Don Box 更棒!
第二篇序文:Grady Booch
一本书的好东西如果太多,就值得说两次。这是为什麽Don 这本书有两篇序的原
因。
如果你正在 Windows 95 或 NT 上建立系统,你不可能远离 COM 的范畴。如果你
想要 (1) 了解台面下发生什麽事 (2) 利用 COM 的强大威力,Don 这本书很适合
你。
我特别喜欢这本书的一点是,Don 在说明 COM 时的组织方式。如果阅读本书时你
对 COM 一无所知,你会被一个清晰简单的 COM 观念模式导引,使你了解问题之
所在,以及 COM 之所以获得其结构和行为的原因。如果你是一位有经验的 COM
开发者,那麽你一定会特别赏识 Don 以 COM 解决一些常见问题时,提出的各种
角度的讨论。
注意,第二篇序的执笔人是 Grady Booch,享誉全球的物件导向大师人物。
●为什麽需要 COM
COM 的全名是 Component Object Model,是微软为了解决软体版本冲突、物件跨
平台冲突...等等问题而设计并主推的一种物件模型。它是一份规格,而 C++ 的
抽象类别与虚拟函式的实作方式最贴近这份规格。
我相信,在学习如何运用 COM/OLE 技术之始,所有人的疑问都相同:为什麽要有
COM?是呀,说到物件导向技术,C++ 不是提供了物件封装、继承、多型的特性
了吗?COM 所为何来?
本书第一章可以让你清楚 COM 的设计动机,包括interface、reference count、
CreateObject...。只要通晓 C++ 语言,在形式上,看这一章就没什麽困难。如
果你有 C++ Object Model 的基础,第一章更可以给你醍醐灌顶的感觉。
第二章介绍 COM interfaces。作者在前一章步步经营演化而来的一个 virtual
base class 此时摇身一变成为功能对等的 COM IUnknown interface。这一章介
绍了IDL(一种 interface 描述语言)、MIDL(微软的一套IDL 编译器)、GUID
(保证亿万年不重复的一个 128-bit 数字)、HRESULT(任何平台通用的一种回
返值型态)、IUnknown(所有 COM interfaces 的基础)。由於许多COM progra
mmer 不能够恰到好处地呼叫 IUnknown 的AddRef 和 Release 两函式,Don Box
特别整理出好青年十大守则,并提供一个实例,告诉读者什麽时候适用哪一条守
则。很贴心!
第三章开始,本书往深涩的方向走去。这时候我建议你先跳看另一本书:Inside
COM,然後再回头接续看後面的章节。
本书用词比较学术化(我的意思是艰涩)。这会使不习惯的读者在攻击发起时进
度受阻。阅读时请特别留心前两章,它们是学习 COM 的关键。这两章内文有系统
地围绕一个例子打转,循序渐进。可惜本书并没有分阶段地附上各级程式码(从
抽象基础类别的设计开始、然後是 interface 与 implementation 的分离、DLL
的加入、reference counting 的设计、QueryInterface 的设计...)。我强烈
建议你要有实作的欲望和精神,依书中的指示一步一步实地靠近 COM。这当中你
可能会吃点苦头,因为书中没有给你所有的资讯(例如 console DLL 的设计..,
基本上那算是你的必要基础)。也许你会卡在某一个小小关卡上进不得、退不甘
。但无论如何,你必须尝试实作,才会有最踏实的收获。这是我的真人实证。
本书相关程式码可以从 Don Box 的网站中取得,不过并不包含上面所说的 COM
骨干程式的各个发展阶段实作码。
■Inside COM
作者:Dale Rogerson
出版公司:Microsoft Press
出版日期:1996
页数:12 章,376 页
售价:US$ 34.99(含 CD 一片)
1. Components
2. The Interfaces
3. QueryInterface
4. Reference Counting
5. Dynamic Linking
6. HRESULTs, GUIDs, the Registry, and Other Details
7. The Class Factory
8. Component Reuse : Containment and Aggregation
9. Making It Easier
10. Servers in EXEs
11. Dispatch Interfaces and Automation
12. Multiple Threads
13. Putting It All Together
这本书文字浅显,义理精确,前进速度适中,每一个阶段附有一个完整的程式。
只可惜起头不够好,没有像Essential COM 一样地从 COM 起源开始分析。万一一
开始的基础没有打好,对整个 COM 的基本精神尚自摇摇晃晃,後面的推进速度恐
怕就无法打到五档了。
我的经验是,当我看完 Essential COM 前两章,并在其第三章匍匐前进,磨得双
膝微颤,舌头发苦时,回过头来看这本 Inside COM,一个晚上刷刷刷看掉了 13
0 页(前六章),而且掌握得相当不错。
本书每一章每一节的前後转承文字说明接续得非常不错,每一个句子的语意也很
清晰(不会用一大串一长串的子句连接词),让我们一路读来顺畅快意,不需要
多花心思在其文章架构,可以把全付精神用来对付 COM 技术。
拿 Inside COM 和 Essential COM 搭配着看,可得最大效益。
■Understanding ActiveX and OLE -- A Guide for Developers & Managers
作者:David Chappell
出版公司:Microsoft Press
出版日期:1996
页数:11 章,328 页
售价:US$ 22.95(无碟片)
1. Introducting ActiveX and OLE
2. The Component Object Model
3. Marshaling and Type Information
4. Automation
5. Persistence
6. Monikers
7. Uniform Data Transfer and Connectable Objects
8. OLE Compound Documents
9. ActiveX Controls
10. Distributed COM
11. ActiveX, the Internet, and the World Wide Web
这本书的副标明白告诉了我们,它是一本可以给经理人看的书。既然是为经理人
而写,书中就不会有太多的 code,反倒是抽象观念的文字说明比较多。
我从来不相信「抽象的文字说明」能够让不具「具象技术基础」的人看得懂。我
敢把话说死,是的,上面这句话对99.99999% 的工业界人士适用。所以,这本书
其实只适合给受过 COM/OLE/ActiveX 训练的工程师看。你已经会了,你才看得懂
它。
会的人才看得懂,不会的人都看不懂,那这本书不是一点用处也没有了吗?不,
它的内容整理得不错,并附予一些设计良好的图,可以使我们的观念更清晰,甚
至修正我们可能存在的一些模糊的、似是而非的盲点。书侧留白处很细心地标示
出段落文字的重点,有点领袖嘉言录的味道。双色印刷,令人赏心悦目。
本文地址:http://com.8s8s.com/it/it3701.htm