Com Introduction

原创 2003年03月19日 17:40:00

Com Introduction

(wang hailong)

1神话<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

我两年前学习使用COM,现在想起那段经历,还有些困惑不解。

我不明白,人们为什么要把一些很明了的事情,弄得玄之又璇,而对一些真正的杰出特性却避而不谈?我写本文的目的,是希望对COM感兴趣的开发人员,不再重蹈我的覆辙,不再被一些说法和资料误导。


刚开始接触到
COM的概念,我虚心求教,从各方面得知了如下的COM神话:

1COM是位置无关的。你不用知道COM组件放在哪里。

2COM是二进制标准,语言无关。你可以用多种编程语言开发COM组件,调用COM组件。

等等。太神奇了。简直象魔术一般。

我这个一头雾水的初学者,对神秘的COM充满了敬仰,却又无从下手。


后来,我只好停止学习这些概念,直接从
MSDN入手。我运行所有的COM例子,阅读MSDN资料。不由得惊叹,COM的构思之巧妙,但这些巧妙之处,却鲜有人提及。而那些被传得沸沸扬扬的神话,有很多故弄玄虚的成分。

 

1COM是位置无关的。你不用知道COM组件放在哪里。

是的,你不用知道COM组件放在哪里。但是你需要知道一个COM组件的ID(一个保证独一无二的数字串),这个组件ID存放在windows注册表里,里面记载着这个COM组件的位置。当你调用这个组件的时候,你需要把COM组件ID作为参数,获取这个组件。Windows系统根据这个组件ID,查找注册表,找到组件的位置,启动或者返回对应的组件。


等一下,问题不是这么简单。
COM组件需要从组件工厂创建,所以,你获得的组件ID是组件工厂的ID,你先创建一个组件工厂,然后,通过这个组件工厂,创建你所需要的组件。(注意,你通过“工厂接口”使用组件工厂。)


组件工厂根据什么来创建你需要的组件呢?通过接口
ID。接口ID也是一个保证独一无二的数字串,这个接口ID对应一个接口的定义。你的头文件必须包含这个接口的定义。

你把接口ID传给组件工厂,组件工厂返回一个组件接口给你。你通过这个接口,调用组件的功能。这就是,“你的头文件必须包含这个接口的定义”的原因。


我们来看,我们不需要位置信息,那我们需要什么信息?组件
ID,接口ID,接口定义,(当然,还有“工厂接口”的定义)。

这种复杂的调用是一个优点?还是一个缺点?显然是一个缺点,却被粉饰成一个神话般的优点。这种方法,是为了把部署信息,尽量集中到注册表里面。你只要把组件正确注册,客户程序就可以正确运行。单纯为了部署的目的,这种代价是否值得?

如果只是为了部署的目的,我觉得,这种代价不值得。我们看看Java.Net工程里面各种配置文件的使用,就知道,有很多更灵活有效的部署方法。

COM的构思远远超过了部署的目的,下一章会讲到。

 

2COM是二进制标准,语言无关。你可以用多种编程语言开发COM组件,调用COM组件。

COM确实是二进制标准,核心是一个VTable(虚表),这个“虚表”的概念和C++类的虚函数表的概念一样。所以,用C++实现COM,非常自然。


前面提到,你如果想使用组件,你必须先知道这个组件的接口定义,你的头文件必须包含这个接口的定义。假如我们是用
C++实现COM,工程里面会包括一个C++头文件,头文件里面包括了接口的定义。如果客户端也使用C++,只要把这个C++头文件拷贝给用户就行了,用户把头文件包括在C++工程里面,就可以使用这个接口了。


如果你不用
C++呢?那也好办,我不是把提供C++头文件给你了吗?里面已经包含了接口的定义。你先研究一下,这个接口的虚表是怎么构成的,然后,你用你的语言,照样写一个头文件,只要遵守我的虚表结构就行了。

:-) 只是一个玩笑。


我还有个折衷的办法,您用过
CORBA吗?CORBA使用IDL进行接口定义,您可以用工具把IDL翻译成各种语言,C++Java,等等。我也用MIDL写一套接口定义,您也可以用工具把MIDL翻译成各种语言,C++VBDelphi等等。什么?您没有这种工具?那么您写一个这样的工具就行了,也不是很难,只不过是生成一个虚表结构。


好了,我们有
MIDL作为公用的交流语言,现在问题都解决了。您还有什么问题吗?哦,您需要头文件。您用什么语言?C++?好,我把C++头文件发给您。还有那位朋友,您使用什么语言?您用其它的语言,好,我把MIDL头文件发给您。您找到一个转换工具,把MIDL转换成您的语言就行了。


哎呀,这么多人来索要头文件,太麻烦了。我还有个方法。我把这些接口定义信息,和组件一起放在注册表里吧。我不是给了你组件
ID吗?你到注册表里查到这个组件,里面会有一个叫做“类型库”的东西。好了,现在您可以从“类型库”导出您的头文件了。什么,您问我怎么用“类型库”?对不起,我忘了告诉您,您得通过ITypeInfo接口使用它。


您嫌麻烦?一点都不麻烦,您看,
VCVBDelphi都提供了自动导出组件接口定义的向导。这些事情都不用您亲自动手。

现在,我们有了一套完整的解决方案。COM是二进制标准,语言无关。


您还有问题,
VB不支持指针,怎么调用虚表VTable?您为什么要用VB调用COM呢?好吧,我再多做一步工作,让我的COM组件支持IDispathch接口,IDispathch接口叫做自动化接口。IDispathch接口会查表,你把函数名交给IDispathch接口,IDispathch接口会自动把请求派发,进行处理。C++的用户也不用着急,我还保留以前的虚表VTable。现在,我给我的组件接口命名为“双接口”dual interface.


终于松了一口气,现在,我们有了一套完整的解决方案。
COM是二进制标准,语言无关。

2. “群件”—— powered by queryInterface

“群件”是Lotus莲花公司的概念,我这里借用一下,表达我对COM组件的赞叹。

COM组件的核心思想就是二进制接口”——VTable

我们来看IUnknow接口的三个方法。

addRefrelease两个方法,管理组件引用计数,我对这两个方法,持保留态度(negative opinion :-)。


第三个方法,
queryInterface,才是整个COM组件思想的精华体现。

通过queryInterface,你可以获取另一个接口,另一种组件服务。

为什么我把COM组件称为“群件”,原因就在于此。每个COM组件都支持一组接口,一“群”接口,一组功能服务,而不是单一的功能。

可能会有人说,这也太绝对了吧,有的时候,人们只需要一个简单功能的组件。我要说,最简单的COM组件,也要实现两个接口——其中一个是IUnkonw,另一个是自己定义的接口。(我这里有些抬杠了。:-)


queryInterface
如此出色。我在EJBCORBA中,都看不到类似的东西。也许有类似的情况,比如,组件的一个方法返回另一个组件。但远远做不到COM组件这种自然的程度。COM组件天生就支持一“群”接口。


下面我们来分析
queryInterface的工作原理。

为了说明白这个问题,我先引入一些javaDesign Pattern的概念。

Java对象能够实现多个接口。外部程序在使用Java对象的时候,有时候,就要判断Java对象是否支持某一个接口。比如,当外部程序要比较两个Java对象的大小的时候,就需要判断这些Java对象是否支持Comparable接口。诸如这样的语句if(obj instanceof Comparable)。我们来看,这个语句多么象queryInterfacequeryInterface也是用来查询组件是否支持某个接口的。

我们在进行类设计的时候,不希望只提供一个很“宽”的接口,包含所有操作。总是试图为不同的调用者分配不同的“角色”,即,提供一组比较“窄”的接口。为不同要求,不同权限的调用者,返回不同的接口。在Design Pattern中,这称为Adapter Pattern


COM
组件正是基于Adapter Pattern创建的。首先,你获得IUnknow接口,你需要某个服务的时候,才从IUnknow接口出发,去查找特定的接口。


通过上面的分析,我们可以看到,
Java对象和COM组件很相像。但两者的实现机制却大不相同,Java对象根据Java语言的特性实现,所有的接口实现都包含同一个类中。又有人要说了,Java对象也可以包含一些其它对象,把一些操作交给这些对象。我这里说的是,这同一个类必须显示地声明,实现所有的接口。比如

class MyObject implements Comparable, Serializable, Interface1, …, interface n.

只有这样,obj instanceof Comparableobj instanceof Interface1这样的语句才能返回真。


COM
组件没有这样的限制。COM组件只返回二进制的VTableCOM组件本身可以不实现这些VTable,可以返回其它组件的VTable。不同的接口,可以在同一个组件中实现,也可以在不同的组件中实现。这也就是COM重用的“聚合”和“包含”等概念。

而且,COM组件的生存状态也很灵活,可以存在于客户程序的进程空间,称为进程内组件,也可以存在于独立于客户程序的进程空间,称为进程间组件。


当一个
COM组件(我们称这个组件为A)的queryInterface方法返回其它组件(我们称这个组件为B)时,我们来看,现在,A组件的地位很像B组件的组件工厂,通过A组件创建B组件。我们现在可以明白,为什么不直接创建组件,而要采用一种不直观的方法,通过另一个组件——工厂组件来创建组件。这样,组件创建的概念就统一起来了——组件通过工厂组件创建。


我不知道,这是一种巧合,还是一种设计上的深思熟虑。不管怎样,
COM组件的设计构思给了我深深的震撼,真是巧夺天工。


注意,由于
queryInterface的自反性要求,实际上的处理要复杂一些。queryInterface的自反性:组件AqueryInterface返回组件B的接口,那么,调用这个组件BqueryInterface,也能够查到组件A的接口。还有甚者,如果组件BqueryInterface返回组件C的接口,组件CqueryInterface,也能够查到组件A的接口。

想到queryInterface的种种好处,这些复杂程度,还是可以忍受的。:-)

 

这还不是COM的全部,只是COM的基础原理。更精彩的是建立在COM基础的一系列技术,Structured StorageOLE DocumentAutomationActiveX等等。每一种技术都非常出色,构思之巧妙,令人赞叹不已。COM标准给我们带来的这么多麻烦,似乎都可以忍受了。


强烈建议使用这些建立在
COM基础上的技术,至少尝试体会其中的思想,会有很多启发。从头开始,定义开发自己的基础COM组件?:-) 我不知道。限于眼界,我还从来没有看到过任何出色的基础COM组件,至少没有IStorageIDispatch等微软自己定义的接口出色。


微软很多杰出的应用程序都是
COM组件。Office系列,Word, Excel, PowerPoint, IE等等。其他的应用程序厂家,以前提供自己的插件标准,现在提供自己的COM组件。

 

【读书笔记】《推荐系统(recommender systems An introduction)》第三章 基于内容的推荐

基于内容的推荐的基本推荐思路是:用户喜欢幻想小说,这本书是幻想小说,则用户有可能喜欢这本小说 两方面要求:(1)知道用户的喜好;(2)知道物品的属性 基于内容的推荐相比协同过滤方法(个人观...
  • xceman1997
  • xceman1997
  • 2014年12月07日 21:51
  • 1116

【读书笔记】《推荐系统(recommender systems An introduction)》第一章 引言

很久没上来写blog,前两个月赶上校招季节,都忙校招去了。 这本书我早就买来了,不过我从前看过项亮的《推荐系统实践》,看这本书的目录结构和项亮那本差不多,就一直放着没看。最近在做一个推荐系统...
  • xceman1997
  • xceman1997
  • 2014年12月02日 22:57
  • 1339

小论文之旅(2)——introduction与related work

今天总结一下自己看的文献内容和查看的一些建议。 首先,在不确定你的文章的main idea的时候,不要着急写introduction,可以先写body部分内容,之后再写introduction部分...
  • u013408431
  • u013408431
  • 2016年08月27日 20:22
  • 2956

【读书笔记】《推荐系统(recommender systems An introduction)》第十章至第十三章

第十章 在线消费决策 这一张主要写消费者的心理,更贴近于心理学,而不是技术方面。 1. 传统的决策模型是认为人们的兴趣始终如一,不会发生变化;不过现代研究表明,用户在决策过程中偏好...
  • xceman1997
  • xceman1997
  • 2015年01月18日 12:32
  • 831

机器学习入门系列01,Introduction 简介

我们将要学习什么东东? 什么是机器学习? 有右边这样非常大的音频数据集,写程序来进行学习,然后可以输出音频“Hello” 有右边这样非常大的图片数据集,写程序来进行学习,然后可以...
  • zmx729618
  • zmx729618
  • 2017年03月28日 11:26
  • 323

编程式实现Spring AOP 引入(Introduction)和切面(Advisor)

Spring Introduction(引入),Spring Advisor(切面)
  • zyhlwzy
  • zyhlwzy
  • 2017年04月21日 14:03
  • 226

台大李弘毅机器学习课程(2017春季)——1.introduction

今天上B站的时候突然间看到居然有阿婆主上传了台大李弘毅教授的机器学习课程的视频,点开进去看了一下,发现这个老师真的是挺逗的,对于我这个初学者来说,课讲的也很棒(课程主页)。所以打算在这里做一个课程的学...
  • u014712516
  • u014712516
  • 2017年12月29日 09:18
  • 27

Java - 你如何理解AOP中的连接点(Joinpoint)、切点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)这些概念?

a. 连接点(Joinpoint):程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring仅...
  • chimomo
  • chimomo
  • 2017年11月09日 09:51
  • 263

Boost.Interprocess使用手册翻译之一:介绍 (Introduction)

写在最前: 1. 原文来源:http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/interprocess.html#interprocess....
  • flyingleo1981
  • flyingleo1981
  • 2017年05月02日 15:13
  • 297

并行计算介绍(Introduction to Parallel Computing ) ——我主张阅读英文原著

      串行计算,分为“指令”和“数据”两个部分,在程序执行时“独立地申请和占有”内存空间,所有计算均局限于该内存空间。      并行计算,则将进程相对独立的分配在不同的节点上,由各自独立的操作...
  • geneculture
  • geneculture
  • 2011年06月09日 01:18
  • 3082
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Com Introduction
举报原因:
原因补充:

(最多只允许输入30个字)