COM学习笔记(三)

  系列(二)里说明了一个进程内的COM组件实现的一般过程,可以看见COM的规范很严格,定义很细,写起来比较麻烦,但在二进制上得到了统一,没有语言关联性。我们之所以写组件,一是为了便于修改与升级,二是为了程序复用节省资源。下面说说COM组件间的复用,组件复用有两种模型:包容与聚合。包容比较简单就是接口转发,好处是转发前可以先判断处理,做一些修补工作类似于HOOK;缺点就是要实现每一个转发接口,哪怕功能只是单纯的转发,有点烦索。聚合则很干脆将查询到的组件接口直接返回给客户端,客户端使用获得的接口调用其方法。似乎聚合的实现容易的多,但是再想想,一个组件聚合了另一个组件的一个或多个接口,把聚合的接口传递给外部客户端,但是对于客户端来说并不知道哪些接口是聚合的哪些接口是原生的,客户端认为它只包含了一个组件,所有的这些接口都是属于该组件的。同时COM规范规定从一个组件的任意接口都能使用QueryInterface方法查询得到该组件的所有接口。


  这样看来,一个组件如果不作一些额外的处理工作是不支持被其他组件所聚合的。在支持聚合模型的组件(或称作内部组件)有两个IUnknown接口,一个是代理接口(IUnknown),一个是非代理接口(INondelegatingUnknown),代理接口IUnknown中的QueryInterface、AddRef、Release函数根据组件的状态,如果是在聚合状态下调用转发外部组件IUnknown接口对应的成员函数,如果在非聚合状态下则执行非代理接口INondelegatingUnknown对应的成员函数。组件如何判断是否在被聚合状态下呢,还记得创建组件的过程吗?组件是通过调用类厂的CreateInstance方法创建的,CreateInstance的第一个参数是外部组件IUnknown接口指针,内部组件判断该参数是否为NULL就知道该在聚合或非聚合状态下创建。


  深入想一下细节,一个外部组件要聚合内部组件的一个接口,先调用内部组件类厂接口CreateInstance函数,并传入外部组件的IUnknown接口指针作为第一个参数,内部组件便会在聚合状态下创建。接着外部组件向内部组件查询要聚合的接口,内部组件有2个IUnknown接口,一个是代理接口IUnknown,另一个是非代理接口INondelegatingUnknown,使用哪个接口的QueryInterface方法查询?当然是非代理接口INondelegatingUnknown,因为代理接口在聚合状态实际上会转发到外部组件的IUnknown接口,结果就是无限递归,皮球踢来踢去谁也不干正事。非代理接口只能(不应该有其他方法)在调用类厂CreateInstance函数创建内部组件时获得(第二个参数传入IID_IUNKNOWN),有了非代理接口,外部组件能查询到聚合接口返回给客户端使用,也可以控制内部组件对象的生存周期了。此时外部组件真正聚合了内部组件接口,很好地对客户端封装细节,客户端对外部组件所有接口的操作规范都符合COM标准。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值