COM笔记(2)

2.1 COM对象
2.1.1 COM对象的标识–CLSID
2.1.2 COM对象与C++对象的比较
2.2 COM接口
2.2.1 从API到COM接口
2.2.2 接口定义和标识
2.2.3 用C++语言定义接口
2.2.4 接口描述语言IDL
2.2.5 接口的内存模型
2.2.6 接口的一些特点
2.3 IUnknown接口
2.3.1 引用计算
2.3.2 实现引用计数
2.3.3 使用引用计数规则
2.3.4 接口查询
2.3.5 COM对象的接口原则
2.3.6 QueryInterface成员函数的实现
2.3.7 COM对象和接口图示法
2.4 字典组件例子子程序
2.4.1 组件程序DictComp
2.4.2 客户程序DictCtrl

客户程序与COM组件程序进行交互的实体是COM对象,它并不关心组件模块的名称和位置(即位置透明性),但它必须知道自己在与哪个COM对象进行交互。

类似于C++语言中类(class)的概念,COM对象也包括属性(也称为状态)和方法(也称为操作),对象的状态反映了对象的存在,也是区别于其他对象的要素;而对象所提供的方法就是对象提供给外界的接口,客户必须通过接口才能获得对象的服务。对于COM对象来说,接口是它与外界进行交互的唯一途径,因此,封装特性是COM对象的基本特征。

CLSID是用来标识COM对象的GUID,因此CLSID在结构定义上与GUID一致。
IID是用来标识接口的,IID在结构定义上也与GUID一致。

在COM对象中,数据是完全封装在对象内部的,外部不可能直接访问对象的数据属性,因为COM对象和客户程序可能在不同的模块中甚至在不同的进程中或不同的机器上,因此,客户直接访问COM属性不仅不合理,有时也不太可能。而且,通过COM对象提供的接口成员函数访问对象的属性,为COM对象对属性的控制提供了机会,对象可以在成员函数中对新的属性值进行有效性判断,若新值合理则接受,否则便拒绝,还可以引发一些相应的事件。

可重用性是面向对象系统的重要特性,因此也是COM对象和C++对象的共同特性,但两者的表现形式不同,COM对象的可重用性表现在COM对象的包容和聚合,一个对象可以完全使用另一个对象的所有功能;而C++对象的可重用表现在C++类的继承性,派生类可以调用其父类的非私有成员函数。

平面型的API接口层可以很好地把两个程序连接起来,但存在以下一些问题:
1. 当API函数非常多时,使用会非常不方便,需要对函数进行组织。例如Windows API有300多个函数,一般的SDK也有几十个之多,编程“接口面”太宽不利于接口层的管理。
2. API函数需要标准化,按照统一的调用方式进行处理,以适应不同的语言编程实现。参数的传递顺序、参数类型、函数返回处理都需要标准化。
COM定义了一套完整的接口规范,不仅可以弥补以上API作为组件接口的不足,还充分发挥了组件对象的优势,并实现了组件对象的多态性。

客户程序用一个指向接口数据结构的指针来调用接口成员函数。接口指针实际上又指向另一个指针,这第二个指针指向一组函数,称为接口函数表,接口函数表中每一项为4个字节长的函数指针,每个函数指针与对象的具体实现连接起来。通过这种方式,客户只要获得了接口指针,就可以调用到对象的实际功能。
通常,我们把接口函数表称为虚函数表(vtable),指定vtable的指针称为pVtable。

对于一个接口来说,它的虚函数表vtable是确定的,因此接口的成员函数个数是不变的,而且成员函数的先后顺序也是不变的;对于每个成员函数来说,其参数和返回值也是确定的。在一个接口的定义中,所有这些信息都必须在二进制一级确定,不管什么语言,只要能支持这样的内存结构描述,就可以定义接口。

如果客户程序要使用一个COM对象的某个接口,则它必须知道该接口的IID和接口所能够提供的方法(即接口成员函数)

class IDictionary的说明使用了纯虚函数,因为接口只是一种描述,并不提供具体的实现过程。如果COM对象要实现接口IDictionary,则COM对象必须以某种方式把它自身与类IDictionary联系起来,然后把IDictionary的指针暴露给客户程序,于是客户程序就可以调用该对象的字典功能了。

COM规范在采用OSF的DCE规范描述远程调用接口IDL(interface description language)的基础上,进行扩展形成了COM接口的描述语言。
如:
interface IDictionary
{
HRESULT Initialize();
HRESULT LoadLibrary([in] string);
};
Microsoft Visual C++提供了MIDL工具,可以把IDL接口描述文件编译成C/C++兼容的接口描述文件(.h)。如果我们编写了一个包含上述字典接口定义的IDL文件idict.idl,则利用MIDL编译工具可以生成对应的idict.h,它可以被组件程序和客户程序所使用。

根据COM规范,所有的接口都必须从IUnknown派生,可以是直接派生,也可以是间接派生。

多态性是面向对象系统的重要特性,COM对象也具有多态性,其多态性通过COM接口体现。多态性使得客户程序可以用统一的方法处理不同的对象,甚至是不同类型的对象,只要它们实现了同样的接口。如果几个不同的COM对象实现了同一个接口,则客户程序可以用同样的代码调用这些COM对象。

COM定义的每一个接口都必须从IUnknown继承过来,其原因在于IUnknown接口提供了两个非常重要的特性:生存期控制和接口查询。

interface IUnknown
{
HRESULT QueryInterface([in] REFIID iid, [out] void ** ppv);
ULONG AddRef(void);
ULONG Release(void);
}

按照COM规范,一个COM组件可以实现多个COM对象,并且每个COM对象又可以支持多个COM接口。

在C++语言中,实现多接口COM对象有两种简便的办法,一种方法是使用多重继承,把所支持的接口作为其基类,然后在对象类中实现接口成员函数;另一种方法是使用内嵌接口类成员。

COM对象和接口有一种特殊的图形描述方法,COM对象用一个矩形来表示,对象所支持的每一个接口用一个小圆圈表示,在矩形和小圆圈之间用一条线相连,这样可以很好地表达对象和接口之间的关系。因为IUnknown接口是所有COM对象都应该支持的接口,所以IUnkown接口的小圆圈被放在最上面,其余的接口一般放在左边。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值