荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Deny (中秋快乐!!!!!!!!!!!!!!!), 信区: Program
标  题: 组件、COM和ATL(1)
发信站: 荔园晨风BBS站 (Wed Sep 26 22:05:37 2001), 转信

COM是什么?

    您打算解释 COM 吗?以前不是已经有人解释过了吗? 医生听到您说:“您要
干什么?解释 COM?已经有人写了这方面的书!” 确实有书了,而且 GUI 医生还
可以推荐很多好书。他很喜欢 Dale Rogerson 的 Inside COM (Microsoft Press,
 1997) 和 Don Box 的 Essential COM (Addison-Wesley, 1998) 。Adam Denning
 的 ActiveX Controls Inside Out (Microsoft Press, 1996),Sing Li 和
Panos Economopoulos 的 Professional Visual C++ 5 ActiveX/COM Control
Programming (WROX Press, 1997) 也是好书。当然,您也应该看 Kraig
Brockschmidt 的 Inside OLE, 2nd Edition (Microsoft Press, 1995),这是
OLE 参考的最好印刷品 。(当然,MSDN 也是最好的参考,不只是医生这样认为。
)另外,如果您想要看客观地 解释组件软件的书,请参考 Clemens Szyperski 的
新书 Component Software: Beyond Object-Oriented Programming
(Addison-Wesley, 1998)。

    “那又怎么样,”您问到,“GUI 医生还能比这些书说得更好吗?” “根本
不会。”医生这样回答。这些作者(和其他作者)再加上文档确实已经全说到了。
 如果您有时间看这些书,就是这样。“那么您要做的就是,”您叫道,“为我们
轻描淡写地介绍一番 COM 和 ATL,而且每周只有一小段!” GUI 医生回敬道:“
您很聪明。这样就比我预料的要容易多了。” 组件?我是在编写一个立体声系统
吗?

    如果您很熟悉 Visual Basic,您就会很熟悉使用组件编写程序:您既使用
visual ActiveX 控件(例如微调按钮),也使用非可视的 ActiveX 组件(例如数
据库访问对象)。很难找到一个没有频繁使用预制的可重用组件的重要 Visual
Basic 程序。但是,虽 然您重用了大量的组件,大多数人并没有为自己编写过完
整的可重用组件。

    如果您使用 C++ 进行编程,那么您对重用会有不同的感受。人们说 C++ 和面
向对象编程可以很容易地实现对象重用,但是您的经验怎么样?您编写过可重用对
象库吗?无疑少数人确实编写过,但是大部分人并非如此。并且,就算有了这样的
一个库,我们能很好地利用它吗?并不只是由于缺乏规则从而使我们难以重用代码
;事实是,代码很难重用(代码好象从不按我们需要的方式执行),而编写可重用
代码则更难(很难既足够通用又足够实用)。结果是,C++ 并没有使创建可重用二
进制组件变得容易,而是使重用源代码变得相对容易。要知道,大多数主要的 C++
 库是以源代码形式发布的,而不是编译后的形式。为了正确地继承一个对象,很
有必要查看这些源代码,并且依赖于原库的实现细节来进行重用是很容易的(也是
有必要的)。更糟的是,修改源代码并自己连编原库是很诱人的(或是必 要的)
。(到底有多少自连编的 MFC?谁也不知道 . . . .)

    那么让我们重用二进制对象,而不是源代码 那么又怎能重用二进制对象呢?
Windows 程序员首先想到的答案很简单:使用动态链接库(DLL)。使用 DLL 确实管
用,毕竟 Windows 本身就主要是一组 DLL。但是,还有一些问题。

    首先,DLL 不是独立于编程语言的。即使是使用 C 语言编写的 DLL,也很容
易更改调用约定(按什么顺序将什么参数入栈),从而使该 DLL 只能用在 C 程序
中。就算Windows 使用的调用约定已作为 Windows 系统的标准规定得很完备,但
是,医生仍遇到过由于调用约定不匹配而导致的 DLL 失败。为 DLL 编写一个 C
语言的接口有一些重要限制。首先,这限制了您进行面向对象编程,因为,C++ 的
面向对象特性需要对函数名进行修饰,名称修饰没有统一的标准。有些情况 下,
甚至同一编译器的不同版本对名称的修饰也会不同。第二,实现多态性将很困难。
通 过创建包装类,您可以解决这些问题,但是这样做是痛苦的。GUI 医生没有痛
苦过。(起码没有太痛苦过。)即使您解决了名称修饰问题,并进而成功地链接到
了 DLL,当更新对象时也会出现其他问题。

    首先,如果当您更新对象时要向其中添加任何虚函数,那么您就会像浑身插满
软管的病人一样动弹不得。您可能会认为在对象的末尾添加新函数不会出问题,但
是实际上并非如此 :这样会将所有从您的对象派生的对象的虚函数表入口平移。
并且,因为调用虚函数需要使用虚函数表中的固定偏移,以便调用正确的函数,所
以您不能对虚函数表进行任何更改 ——至少不重新编译每个有关的程序(这些程
序使用您的对象或任何从您的对象派生的对象),就不能进行更改。很明显,每次
更新您的对象时都重新编译全世界,不是个好主意 。

    其次,如果您在客户程序中使用 new 来分配对象,那么您要更改该对象的大
小(即添加任何数据),就必须重新编译全世界。

    最后(也是最重要的),更新 DLL 简直就是一场恶梦,因为您处于两难境地
,两种选择都很令人倒胃口:要么通过覆盖 DLL 来“就地”更新该 DLL,要么重
新命名一个新的版本。就地更新 DLL 很糟糕:即使您保持接口的统一, DLL 的某
些用户程序也会被破坏,这样的几率很高。GUI 医生就不必一一告诉您业界(包括
 Microsoft 在内)因此问题而遇到的所有麻烦了。

    另一种方法,即使用一个新的 DLL 名称,至少能让原来正常运转的系统继续
正常运转。但是,代价是需要占用硬盘空间(也许当普通的硬盘有 3GB 左右大小
时,这不是个大问题),而第二个代价是:增加了内存的使用。如果用户使用了两
种版本的 DLL,那么在用户的工作集内就会存在两个代码极其相似的复本。例如,
通常,当您检查用户内存的使用情况时,就会发现两三个版本的 Visual Basic 运
行时模块或 Microsoft Foundation Class (MFC) DLL。既然几乎所有的
Windows 系统通常都使用比物理内存更多的虚拟内存,增加工作集的大小就意味着
严重的性能问题,表现在增加了交换到硬盘上的虚拟内存的大小。(这就为 Brook
 定律提供了反例:向一个慢的系统添加更多的内存反而会使它更快。) 在理想情
况下,您希望能让用户(或应用程序)来选择使用哪个版本。这对于静态链接的
DLL 是极其困难的,但是对动态加载的 DLL 就很容易了。公平地讲,应该指出,
C++ 从来也没打算解决这类问题。 C++ 的原本用途是在只有一个文件的程序中重
用代码,这样所有的对象是同时编译的。 C++ 并不打算提供一种建立可重用二进
制组件的方法,以便可以混合使用不同版本和时间的组件。顺便说一句,Java 的
缔造者注意到了这些问题,这些不足是开发 Oak 的主要原因,Oak 后来变成了
Java。

    Java 的情况又如何?

    Java 确实解决了这些问题中的一部分,但是它也引入了一些自己的问题。最
大的问题是Java 组件(通常是 JavaBeans)只能用于使用 Java 编写的程序。现
在,Microsoft 虚拟机 (VM) 确实允许您将 JavaBeans 用作 COM 对象,从而可以
在任何语言中使用它们而且,Sun 确实有一个 Java/ActiveX bridge。但是,总的
说来,除非在 Windows 中运 行程序,否则 Java 仍是一个单语言的系统:Java
组件只能用于 Java 程序。并且,大 多数情况下,为了使用 Java,您必须从头开
始重新编写系统。(是的,您可以进行本地调用,但是,使用 Java Native
Interface (JNI) 非常麻烦,而且程序将再也无法移植调用)GUI 医生认为这很不
可取,所以他很高兴 Microsoft 虚拟机 (VM) 更为灵活,至少 对 Windows 而言
是这样。没有哪种语言,甚至包括 C++、Visual Basic 或 Java,能适 合于每位
程序员和解决每个问题。 当您用 Java 编写程序时,还必须确定要使用的组件是
本地的(在您的计算机上)还是远程的(在另一台计算机上),而且使用本地和远
程组件的方法很不相同。

     Java 还有一些其他问题,使它还不能成为满足所有组件需要的理想工具。首
先,它还没有真正可靠的方法解决版本问题。(Microsoft VM 中的打包管理程序
对此会有很大帮助 。)其次,Java 多少要比 C++ 慢一些。GUI 医生注意到,在
一种 Java 联机杂志上出版的“象 C++ 一样快”的性能测试中,遗漏了 Java 会
表现不好的测试。能想到的两个例子是字符串和数组操作(Java 必须在每次访问
时进行越界检查),以及初始的方法程序调用(在第一次调用时,Java 必须在类中
的一个表内按签名查找该方法程序。当然在后续的调用会很快,那个 Java 杂志所
测试的正是后续的调用。)。最后,Java 的“一次一个类”的加载机制会比一次
加载所有的代码慢得多(即使代码很少!),因为它需要更多的文件或 HTTP 事务
,这些都需要极高的开销。

    即使您是按能够获得良好性能的方法使用 Java,当您从另一种语言中使用
Java 组件时 ,性能也会很糟,因为需要存在翻译层,以连接不相似的语言和对象
模型。 Java 的闪光之处在于存在这样一种可能,即您可以在不同的计算机上使用
编译好的组件,而不必为每种计算机的处理器和操作系统重新编译。但是,这经常
并不是那么回事,在要支持的每种平台上,都需要测试和调试您的组件。 那么,
还有别的选择吗?

    正如所证实的,可以使用 C++ 连编 DLL 和其他可重用的二进制组件。在
Dale Rogerson 的书 Inside COM 和 Don Box 的书 Essential COM 中,他们都以
一个要重用的C++ 类开始,然后使用一些聪明的技巧解决了我上面列出的每个问题
(还有其他一些问题)。毫不奇怪地,他们最后都得出了同样的结果,即 COM。也
就是说,二进制代码重用的每个问题的解决方法都是 COM 的一个重要特性。(如
果您想要现在就查看这个过程,请查阅 Markus Horstmann 的文章“从 CPP 到
COM”。) 虽然 COM 的“母语”是 C++,从 C 程序中也可以很方便地使用 COM
——甚至头文件就 支持这样做。而且,通过一些技巧,在任意一种语言中都可能
实现双向 COM 支持,例如 Visual Basic、Java、Delphi 等等。(“双向 COM 支
持”的意思是指,有可能既在一种 语言中使用 COM 对象,又使用这种语言编写
COM 对象。)在语言的运行时模块中实现 COM 兼容性的工作并不简单,但是好处
是巨大的:一旦这样做了,您就拥有了大量已经编 写和调试好的 COM 对象,以供
您使用。而且,COM 组件会有广阔的市场——Giga Information Group 估计当前
的市场是每年 4 亿美元,在三年后预计为 30亿美元。( COM 组件市场比
Microsoft 的增长还要快!)要注意,这些市场预测是针对第三方 COM 对象的,
不包括由 Microsoft 提供的 COM 组件。

    COM 的另一个关键特性是支持三种类型的对象:进程内 (DLL)、本地(同一计
算机上不同进程中的 EXE)以及远程(不同计算机中的 DLL 或 EXE,通过分布式
 COM 或称 DCOM 来 进程中的 EXE)以及远程(不同计算机中的 DLL 或 EXE,通
过分布式 COM 或称 DCOM 来 通讯)。您在编写使用 COM 组件的代码时,不必考
虑(甚至知道)最后要使用哪种 COM 对象,因此可使用完全相同的代码来连接进
程内、本地或远程对象。COM 是怎样连接到正 确的对象上的呢?是这样,它在注
册表中查找对象的 Class ID——注册表项告诉 COM 哪 种对象可用。COM 做其余
的工作,包括启动进程和通过网络通讯。(注意:不同种类的 COM 对象存在性能
差异,对此您需要心中有数——但是,不管您最后使用哪种对象,至少 用于连接
和使用对象的代码是完全相同的。)

    但是,COM 并不能解决世界上的所有问题。例如,当您更新一个组件时,仍有
可能破坏使 用该组件的程序。(可能由于 COM 强制地为组件赋予“黑盒子”视图
,从而不可能了解 组件的实现细节,也就使得这种破坏并不普遍,但是仍会发生
。)所以,您仍需要选择是 就地更新组件而承担破坏的风险,还是为新组件使用
新的 Class ID。但是,有了 COM, 确实可以较为容易地编写一些代码,以使用户
(或应用程序)能够选择使用哪种版本的组 件,而不必重新编译。

    回忆一下,几乎可以使用任何语言来编写和使用 COM 组件,而且它们可以存
放在任何计 算机上。这很好。但是,跨平台支持又怎样呢? 跨平台的情况是喜忧
参半的。忧的是,现在除了 Win32,还没有太多其他平台上的 COM。 有一些移植
到非 Windows 平台的 COM,但是不多。不过,这只是忧的一面。

     好消息是,很快会进行很多的移植,包括对最常见的 UNIX 版本和对 MVS 的
移植。而且 ,Microsoft 在亲自进行一些移植工作。COM 和 DCOM 在您最喜欢的
主机和 UNIX 计算机 中可用的日子不会太远了,按计划,用于 UNIX 的 COM 在二
月份发布。想想看,在一些 快速的主机上运行使用任意的语言编写的远程 COM 对
象,而您可以通过您的计算机上的 任何语言(Visual Basic、Java、Delphi、
C++)访问该主机,这是多么酷啊!请查阅 Microsoft COM Web 站点 (http:
//www.microsoft.com/com/)上的最新信息。

    所以,如果您正在为 Windows 编程,您一定会考虑编写 COM 对象,而不管您
是使用 Visual Basic、Java、C++、Delphi 还是其他 COM 兼容语言进行开发的。
您编写的对象 可以用在本地计算机上或远程使用,而不用重新连编您的组件或组
件的客户程序,这多亏 了 COM 和 DCOM 的魔力。而且如果您想要让您的方案在非
 Windows 平台上运行,COM 正 越来越成为一种合适的手段,所以很值得认真地探
究和考虑一下。






--

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.201]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店