COM简介
COM是什么
COM是由Microsoft提出的组件标准,它不仅定义了组件程序之间进行交互的标准,并且也提供了组件程序运行所需的环境。在COM标准中,一个组件程序也被称为一个模块,它可以是一个动态链接库,被称为进程内组件;也可以是一个可执行程序(即EXE程序),被称作进程外组件。
一个组件程序可包含一个或多个组件对象,因为COM是以对象为基本单元的模型,所以在程序与程序之间进行通信时,通信的双方应该是组件对象,也叫做COM对象,而组件程序(或称作COM程序)是提供COM对象的代码载体。COM对象不同于一般面向对象语言(如C++语言)中的对象概念,COM对象是建立在二进制可执行代码级的基础上,而C++等语言中的对象是建立在源代码级上,因此COM对象是语言无关的。这一特性使用不同编程语言开发的组件对象进行交互成为可能。
COM对象与接口
类似于C++中对象的概念,对象是某个类的一个实例;
- 类则是一组相关的数据和功能组合在一起的一个定义。使用对象的应用(或另一个对象)称为客户,有时也称为对象的用户。
- 接口是一组逻辑上相关的函数集合,其函数也被称为接口成员函数。按照习惯,接口名常是以I为前缀。COM对象通过接口成员函数为客户提供各种形式的服务。
在COM模型中,对象本身对客户来说是不可见的。客户请求服务时,只能通过接口进行。每个接口都由一个128位的全局唯一标识符来标识。客户通过GUID来获得接口指针,再通过接口指针,客户就可调用其成员函数。
与接口类似,每个组件也用一个128位GUID来标识,称为CLSID(类标识或类ID),用CLSID标识对象可保证(概率意义上)在全球范围内的唯一性。实际上,客户成功地创建对象后,它得到的是一个指向对象某个接口的指针,因为COM对象至少实现一个接口(没有接口的COM对象是没有意义的),所以客户就可调用该接口提供的所有服务。根据COM规范,一个COM对象如果实现了多个接口,则可从某个接口得到该对象的任意其它接口。从这个过程也可看出,客户与COM对象只通过接口打交道,对象对客户来说只是一组接口。
从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,客户代码可调用组件对象的功能。接口定义了一组成员函数,这组成员函数是组件对象暴露出来的所有信息,客户程序利用这些函数获得组件对象的服务。
通常把接口函数表称为虚函数表(vtable),指向vtable的指针为pVtable。对一个接口来说,它的虚函数表是确定的,因此接口的成员函数个数不变,成员函数的先后顺序也不变;对每个成员函数来说,其参数和返回值也是确定的。在一个接口的定义中,所有这些信息都必须在二进制一级确定,不管什么语言,只要能支持这样的内存结构描述,就可使用接口。
每一个接口成员函数的第一个参数为指向对象实例的指针(=this),这是因为接口本身并不独立使用,它必须存在于某个COM对象上,因此该指针可提供对象实例的属性信息,在被调用时,接口可知道是对哪个COM对象在进行操作。
在接口成员函数中,字符串变量必须用Unicode字符指针,COM规范要求使用Unicode字符,且COM库提供的API函数也使用Unicode字符。所以,如果在组件程序内部使用了ANSI字符,就应进行两种字符的转换。当然,在既建立组件程序又建立客户程序的情况下,可使用自定义参数类型,只要它们与COM所能识别的参数类型兼容。VC++提供两种字符串的转换:
namespace _com_util {
BSTR ConvertStringToBSTR(const char *pSrc)throw(_com_error);
BSTR ConvertBSTRToString(BSTR pSrc)throw(_com_error);
}
BSTR是双字节串,是最常用的自动化数据类型
COM优点
用ATL写一个COM组件,在组件中实现了一个自定义接口(当然可把200个函数都加到这一个接口中,果真如此的话,恐怕就没有人使用这个组件了)。
一个组件既然可提供多个接口,那么在设计时,就应按函数功能进行分类,把不同功能分类的函数用多个接口表现出来。优点是:
1.一个接口中的函数个数有限、功能集中,便于学习使用;
2.容易维护和升级。