{C++} COM 组件多层聚合嵌套原理


    大四的课还是蛮有意思的,其中有一个COM组件的课,感觉挺有收获,做了一个小Demo,是关于COM聚合的, 

 聚合和包容是COM的基本特征,老师上课没把这俩的关系讲清楚,也不大知道为啥放着简单的包容不用,用聚合写模块。

通过做这个Demo,俺算是理解了。因为包容只是单向调用接口,也就是从外到内,不能从内到外。而聚合则是双向调用的,

非常的灵活。下面通过具体的例子说说。

 

    这个小Demo是控制台调用三个动态链接库的,每个链接库中都有一个方法,最外面的库CompB.dll里面是减法运算, 

 聚合CompC.dll里面的乘法,CompC.dll聚合CompA.dll里面的加法。CompB.dll调用接口是OtherInterface,CompC.dll

调用接口是AnyInterface,CompA.dll调用接口是SomeInterface。 CompB内部指针Inner指向CompC,CompC内部指针 

Inner指向CompA,Outer指针指向CompB,CompA内部指针Outer指针指向CompC,通过这四个指针,可以使接口查询

双向传递。也就是说我可以通过OtherInterface拿到CompA的Add方法,也可以通过SomeInterface拿到CompB的Minus

方法,调用方式非常灵活。三个接口无论调用哪一个都可以访问到三个动态链接库中的所有方法。每一个方法都可以通过不同

接口调用,原理也很清晰和简单。多层聚合调用的中间层dll就需要一对指针指向上层dll和下层dll,就像CompC一样。实现也不

复杂,每个动态链接库都有一个查询接口方法,CompC和CompA通过非委托查询接口,进行调用传递。初始化过程是这样的,

CompB初始化CompC实例,CompC初始化CompA实例。CompB如果希望调用CompA就必须先初始化CompC,初始化过

程也很清晰。为了模块的灵活性,多写些代码还是值得滴。


基本原理如图:


 

我本地的执行输出: 

 

 

 

多层聚合嵌套核心方法是CompC的两个查询方法:

QueryInterface: 

 1 HRESULT CC::QueryInterface(const IID& iid, void **ppv)
 2 {
 3     printf("---------------------excute CompC QueryInterface!!!\n");
 4     if ( iid == IID_OtherInterface ) 
 5     {
 6         if(m_pUnknownOuter != NULL){
 7             printf("CompC m_pUnknownOuter is not null!\n");
 8             return m_pUnknownOuter->QueryInterface(iid, ppv);
 9         }else{
10             return NondelegationQueryInterface(iid, ppv);
11         }
12     }
13     if ( iid == IID_SomeInterface ) {
14         if  ( m_pUnknownInner != NULL ){
15             printf("CompC m_pUnknownInner is not null!\n");
16             return m_pUnknownInner->QueryInterface(iid, ppv);
17         } else{
18             return NondelegationQueryInterface(iid, ppv);
19         }
20     } else {
21         return NondelegationQueryInterface(iid, ppv);
22     }
23 }

 

 NondelegationQueryInterface:

 

 1 HRESULT CC::NondelegationQueryInterface(const IID& iid, void **ppv)
 2 {
 3     printf("---------------------excute CompC NondelegationQueryInterface!!!\n");
 4     if ( iid == IID_IUnknown )
 5     {
 6         *ppv = (INondelegatingUnknown *this ;
 7         ((IUnknown *)(*ppv))->AddRef() ;
 8     } else if ( iid == IID_AnyInterface ) 
 9     {
10         *ppv = (IAnyInterface *this ;
11         ((IAnyInterface *)(*ppv))->AddRef() ;
12     } else if ( iid == IID_SomeInterface ) 
13     {
14         return m_pUnknownInner->QueryInterface(iid, ppv) ;
15     } else if ( iid == IID_OtherInterface ) 
16     {
17         return m_pUnknownOuter->QueryInterface(iid, ppv) ;
18     } else
19     {
20         *ppv = NULL;
21         return E_NOINTERFACE ;
22     }
23     return S_OK;
24 }

 

网上这方面东西不多,发篇帖子填补一下。 为这方面不太清楚的同学提供下帮助。


posted on 2010-12-04 15:35  施杨  阅读(...)  评论(... 编辑 收藏

导航