COM重用-包容和集合

发布时间:2011-3-12 11:40
分类名称:COM


COM重用-包容和集合 - Dsliu - Dspace
包容
 

COM重用-包容和集合 - Dsliu - Dspace
聚合
 

对象A是已经被实现好的COM对象。

包容:

B实现ISomeInterfaceIOtherInterface接口,然后在ISomeInterface的实现中调用A对象提供的服务。一般的,A的生存期在B生存期内。

 

聚合:

B只实现了IOtherInterface,当客户要求B对象提供ISomeInterface时,由于A被聚合到了B中,B可以提供此服务。一般的,A的生存期在B生存期内。

 

聚合的复杂性在于,B虽然知道A实现了什么接口,但A不知道B实现了什么接口。这样就导致通过B获取到A的实例指针后,通过此指针调用的QueryInterfaceA的,也就无法QueryB中实现的接口来。而且AB的接口继承于俩个不同的IUnknown,获取回的指针也不一样。这样就违背了QueryInterface需要遵循的原则。

 

解决聚合复杂性的办法,在A中留下一个IUnknown 指针,通过外部(例如B)将其IUnknown传入给AA就可以利用此接口来代理B 来做Query Interface了。

 

实现:

class CB : public IOtherInterface

{

         ......

private:

         IUnknown *m_pUnknownInner; // Point to A's IUnknown

         ......

}

 

CB::QueryInterface(...)

{

         ......

         if (iid == IID_SomeInterface)

                   return m_pUnknownInner->QueryInterface(iid, ppv);

         ......

}

 

A 分被聚合和未被聚合俩种情况。

如果被聚合,A就使用内部这个指针(即B传入的自己实例指针)来Query Interface,相当于是BQuery Interface,获取的IUnknown都是B的。而且不存在A找不到BInterface

 

如果未被聚合,那么就什么都不做,不使用这个指针。

 

CoCreateInstance有一个参数,叫IUnknown *pUnknownOuter,这个指针,就是A中要保存的B实例指针。

 

A内部,为了区分聚合和非聚合,定了了俩个IUnknowndelegating unknown, undelegating unknown).这个俩个委托和非委托名词,曾经困扰了我很久,后来发现是因为这俩个词语本身的语义对我的误导。如果要以我自己的方式区分,我将其区分为一个IUnknownProxy(代理),一个IUnknown是正常的IUnknown。代理只是个中转站,负责分发,其内部其实就是一个判断,如果ApUnknownOuterNULL,那么就转发给正常的IUnknown。如果pUnknownOuter不为NULL,那么就调用它自身的接口函数。

 

class INondelegationUnknown

{

public:

         virtual HRESULT _stdcall NondelegationQueryInterface(...) = 0;

         virtual ULONG _stdcall NondelegationAddRef() = 0;

         virtual ULONG _stdcall NondelegationRelease() = 0;

};

class CA : public ISomeInterface, public INondelegationUnknown

{

         ......

public:

         NondelegationQueryInterface(...);

         NondelegationAddRef();

         NondelegationRelease();

        

         QueryInterface(...);

         AddRef();

         Release();

         ......

private:

         IUnknown *m_pUnknownOuter;

         ......

}

 

CA::NondelegationQueryInterface(...)

{ 正常Query,就像什么都没发生过 }

 

CA::NondelegationAddRef()

{ 正常AddRef,就像什么都没发生过 }

 

CA::NondelegationRelease()

{ 正常Release,就像什么都没发生过 }

 

CA::QueryInterface(...){

         if (NULL == m_pUnknownOuter) // 转发

                   Call NondelegationQueryInterface

         else

                   Call m_pUnknownOuter->QueryInterface

}

CA::AddRef(){

if (NULL == m_pUnknownOuter) // 转发

                   Call NondelegationAddRef

         else

                   Call m_pUnknownOuter->AddRef

}

CA::Release(){

if (NULL == m_pUnknownOuter) // 转发

                   Call NondelegationRelease

         else

                   Call m_pUnknownOuter->AddRef

}

 

再看看B何时将它自己的指针传递给A

HRESULT CB::Init()

{

         IUnknown *pUnknownOuter = (IUnknown *) this;

HRESULT result = ::CoCreateInstance(CLSID_ComponetA, pUnknownOuter, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&m_pUnknownInner);

......

传入pUnknownOuter(既Bthis),而且得到m_pUnknownInnerAthis)。

}