COM原理与应用学习笔记(二章)

第二章 COM 对象和接口

 

1 COM 对象的理解

       COM 对象类似于 C++ 语言中类的概念,类的每个实例代表一个 COM 对象,它也包括属性(即状态)和方法(即操作),状态放映对象的存在,方法就是接口。

 

2 COM 对象的标识- CLSID

       GUID 是一个 128 位的随机数,重复概率极低。它的值来源于两部分:空间值(网卡地址或随机数)和时间值。

       获得 GUID 值可以 使用 VC++ 提供的工具: GUIDGen.exe UUIDGen.exe 。或者使用 COM 库的 API 函数 CoCreatGuid

 

3 COM 对象与 C++ 对象的比较

       COM 对象将数据完全封装在对象的内部。 C++ 对象的封装是在语义上的封装,通过不同的数据类型实现数据的封装。

       COM 对象的可重用性通过包容和聚合实现。 C++ 对象的可重用性通过类的继承来实现。

       COM 对象的多态性通过其接口体现, C++ 对象的多态性通过其虚函数体现。

 

4 COM 接口的作用和意义

COM 规范的核心内容是关于接口的定义,虽然 COM 本身并不复杂猫蛋围绕 COM 接口有很多内容值得仔细探讨,包括接口的标识、接口函数的调用习惯、参数处理、接口与对象的关系以及接口与 C/C++ 的关系、 COM 接口多具有的特性等。

       COM 定义了一套完整的接口规范,不仅可以弥补 API 作为组件接口的不足,还从分发挥 了组件对象的优势,并实现了组件对象的多态性。

 

5 、接口定义和标识

       从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,客户代码可以调用组件对象的功能。

       客户程序用一个指向接口函数结构的指针来调用接口成员函数。实际上接口指针指向另一个指针 pVtable

接口函数表称为虚函数表( Virtual Function Table ,简称 vtable ),指向 vtable 的指针为 pVtable 。对于一个接口来说,它的虚函数表 vtable 是确定的。

 

6 、接口设计的问题

       在接口成员函数中,字符串变量必须用 Unicode 字符指针,这是 COM 规范的要求。

       COM API 函数使用大多数语言惯用的 _stdcall 调用习惯。

       C 语言定义 COM 接口,需要有结构体 struct 定义其接口结构,接口成员函数必须有一个 this 指针。

       C++ 语言定义 COM 接口,因为由 C++ 语言 class 的实现机理可以看出, COM 接口结构中的 vtable class vtable (类的虚函数表)完全一致,因此,用 class 描述 COM 接口是最方便的手段。此时,接口成员函数隐藏了 this 指针。

class 型接口的说明要比 struct 型接口的说明简捷得多。

 

7 COM 接口与对象的联系

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

       class 型接口通过把接口指针( this )与对象数据绑定在一起的方法实现对 COM 接口的支持比较直观、简捷易于理解。实际上,也可以采用其他的方法来实现接口,只要接口成员函数中 this 指针(即接口指针)与对象数据能建立确定的连接,在接口成员函数中可以访问到对象数据即可。例如, VC++ MFC 库和 ATL active template library ,活动模板库)模板库分别采用了不同的机制来提供对 COM 接口的支持。

 

8 、接口描述语言 IDL

       COM 规范在采用 OSF DCE 规范描述远程调用接口 IDL interface description language ,接口描述语言)的基础上,进行扩展形成了 COM 接口的描述语言。接口描述语言提供了一种不依赖于任何语言的接口描述方法,因此, 它可以成为组件程序和客户程序之间的共同语言。

       COM 规范使用的 IDL 接口描述语言不仅可用于定义 COM 接口,同时还定义了一些常用的数据类型,也可以描述自定义的数据结构,对于接口成员函数,我们可以制定每个参数的类型、输入输出特性,甚至支持可变长度的数组的描述。 VC++ 提供了 MIDL 工具,可以把 IDL 接口描述文件编译成 C/C++ 兼容的接口描述头文件( .h )。

 

9 、接口的内存模型

       COM 对象往往有自己的属性数据,它们反映对象的状态,并用于区分不同的对象。对于有多个对象的客户,数据属性是不能公用的。

 

10 、接口的特点

       二进制特性

       接口不变性

       继承性(扩展性):类似于 C++ 中类的继承性,接口也可以继承发展,但方式 不同。类继承不仅是说明继承,也是实现继承,即派生类可以继承基类的 函数实现,而接口继承只是说明继承,即派生的接口只继承了基接口的成员函数说明,而没有继承基接口的实现。类继承允许多重继承,但接口继承只允许单继承。根据 COM 规范,所有接口都必须从 IUnknown 派生,可以直接派生,也可以间接派生。但大多数都是直接派生。 OLE 系统中,接口最后字母是“ 2 ”或“ Ex ”的,标煤它是一个继承接口。

       多态性: COM 对象具有多态性,其通过 COM 接口体现。

 

11 IUnknown 接口提供了两个非常重要的特性 :生存期控制(使用引用计数)和接口查询。

 

12 IUnknown 接口引用计数的设置层级

       引用计数在组件一级实现则计数分辨率太粗(选择全局变量),在对象一级实现恰好(使用 C++ 类的成员变量),在接口一级实现则计数分辨率太细(使用类成员变量)。

 

13 、使用引用计数的规则

       根据不同场合使用或者传递接口指针标量进行分类,并给出相应的规则:

       1 )函数的参数中使用接口指针变量。

输入参数:由于输入参数由调用函数控制,因此被调用函数执行过程中,接口指针一定保持有效,引用计数不需要改变。

输出参数:输出参数是指在被调用函数执行过程中进行赋值的参数,而且被调用函数并没有用到函数初始化传进来的值,输出参数相当于函数的一个返回值。在 C/C++ 语言中,输出参数为一个指针变量( COM 中不使用引用变量)。因为输出参数相当于在被调用函数中生成了一个新的接口指针变量,因此,在被调用函数返回之前,对输出参数应该调用 AddRef 使接口引用计数增 1 。这条规则也适用于函数返回值为接口指针变量的情况。

输入-输出参数:在参数被修改之前,对原来传进来的接口指针调用 Release 以使引用计数减 1 ,在参数被修改之后,对新的接口指针变量调用 AddRef ,以标记对新的接口指针的引用。如果在函数执行过程中参数没有被修改,则不需要改变。

       2 )局部接口指针变量:因为在局部函数块中,接口指针总是有效的,所以,一个局部接口指针变量被赋了 值并调用了接口成员函数,引用计数不需要改变。

       3 )全局接口指针变量:把全局接口指针变量作为输入参数传给某个函数之前,应该调用 AddRef 以保证在函数调用中可以使用给接口指针变量,因为它是全局变量,其他的函数有可能会调用 Release 函数。在函数返回之后应该调用 Release 函数。

       4 C++ 中类成员变量为接口指针变量:因为对于类 的作用域来讲,成员变量相当于全局变量,因此适用于规则( 3 )。

       5 当以上 情形都不适合时,使用以下一般的规则:

                在顺序执行过程中,如果要对一个接口指针变量赋值,则对赋值后的接口指针变量调用 AddRef ,并且,如果赋值前的接口指针变量还没有结束,则赋值前必须对它调用 Release 以便先结束 它的使用。

                如果要结束使用一个接口指针变量,以后不再用到它了,则调用 Release 函数。

 

14 、接口查询

       使用 QueryInterface 函数查询接口,其返回值有 S_OK E_NOINTERFACE E_UNEXPECTED

 

15 COM 对象的接口原则

       1 )对于同一个对象的不同接口指针,查询得到的 IUnknown 接口必须完全相同。即每个对象的 IUnknown 接口指针是唯一的。

       2 )接口对称性。即对一个接口查询其自身总应该成功。

       3 )接口自反性。

       4 )接口传递性。

       5 )接口查询时间无关性。

 

16 、多接口 COM 对象的实现方法

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值