COM的实现

4.COM实现

4.1IUnknown接口

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


4.1.1生存周期

客户程序在与COM对象通信过程中,也要控制对象的存在与否,如果客户还需要继续对对象进行操作,在他须保证对象能一直存在于内存中;如果客户对对象操作已完成,以后不再需要改对象,则它必须及时地把对象释放掉,以提高资源利用率。但是如果客户程序由多个逻辑模块使用了同一个COM对象,由于每个逻辑模块并不知道其他的逻辑模块是否继续在使用COM对象,他们只知道自己是否还需要改对象。而对于COM对象来说,只要任一个逻辑模块还需要使用它,它就必须驻留在内存中,不能释放自己。

COM采用了“引用计数”技术来解决内存管理问题,COM对象通过引用计数来决定是否继续生存下去。客户需要正确的操作COM对象的引用计数来很好的控制对象的生存期。

引用计数的实现

按照COM规范,一个COM组件可以实现多个COM对象,并且每个COM对象又可以支持多个COM接口,这种层次结构为我们实现引用计数提供了多种选择方案。可以在COM组件一级,可以在COM对象一级,也可以在COM对象的接口一级。如下图:




 

如果在组件一级实现应用计数,可以选择全局变量;如果在对象一级实现应用计数,可以使用C++类的成员变量;如果在接口一级实现引用计数,可以为对象的每个接口设置一个类成员变量作为引用计数变量。当然了在不同级别上实现应用计数,对应的实现机制会有所差别,组件一级太粗,接口一级太细,所以综合考虑在COM对象级别实现应用技术。如下列代码: 






 

 

按照引用计数的原理,我们可以制定最基本的客户控制规则:

(1)      客户创建了组件对象并获得了第一个接口指针之后,引用技术应该为1;

(2)      在客户程序中,当把接口指针赋给其他变量时,应该调用AddRef,使引用计数增1;

(3)      在客户程序中,当一个接口指针被使用完成之后,应该调用Release,使引用计数减1。

以上只是使用引用计数的基本原则,在实际应用中会遇到更复杂的情况,但最核心的原则就是,要保证AddRef的调用和Release的调用成对出现以保证COM对象能够成功释放。

4.1.2接口查询

如下图,假设当前有这样一个继承关系的COM对象,




 

接口查询需要遵循一些原则:

(1)      同一个对象的不同接口指针,查询到的IUnknown接口必须完全相同;

(2)      接口对称性。对于一个接口可查询其自身。

(3)      接口自反性。如果从一个接口查询到另一接口,则从另一接口也可查到前一个接口;

(4)      接口传递性。接口可以循环式互查;

从上图的继承关系,我们不难想到一个非常让人头疼的问题,那就是COM对象调用IUnknown中的函数时会不会出现二义性的问题,再加上COM规范中还规定在继承层次中不能使用虚继承,以便能构建如下图是的内存结构,这就更添加了我们的疑问。嘿嘿,不用担心,别忘了二义性解决的另一个办法就是,在调用函数或属性时使用基类指定的方式。

 

在QueryInterface函数实现中就采用了这种方式,如下为实现代码: 


 

注:在第一个if语句块中,我们并没有把this指针直接转换成IUnknown指针。根据C++语法,由于在CDictionary的基类树中,有两个IUnknown节点,因此,直接把this指针转换成IUnknown指针存在二义性,所以通常把this转换成第一个接口的指针,返回后在转换成IUnknown,以保证每次查到的IUnknown接口完全一致。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值