COM复用的中Containment(包容)和Aggregation(聚合)的实现

  1. Containment是一种比较简单的复用方法,如果Component B复用Component A,Component B实际上是Component A的一个客户,Component B向客户提供的Component A的功能实际上是Component B直接调用Component A完成的。当然Component B可以扩充Component A的功能。Component B可以直接使用已经存在的Component A,而不需要对Component A做任何改动
  2. Containment的例子实现略(潘爱民《COM原理与应用》第四章)
  3. Aggregation则比较复杂,Component A必须能够适应被Aggregation下的特殊处理。其核心在于QueryInterface函数。Aggregation涉及到聚合对象和被聚合对象双方的协作,体现了真正意义上的COM复用,而Containment只是客户程序和Component的嵌套这是Containment和Aggregation的本质区别
  4. Aggregation的实现(摘自潘爱民《COM原理与应用》)。
    Component A的Code
    class INondelegatingUnknown
    {
    public:
           virtual HRESULT  __stdcall  NondelegationQueryInterface(const IID& iid, void **ppv) = 0 ;
           virtual ULONG       __stdcall  NondelegatingAddRef() = 0;
           virtual ULONG       __stdcall  NondelegationRelease() = 0;
    };
    class CA : public ISomeInterface, public INondelegatingUnknown
    {
    protected:
         ULONG           m_Ref;
    public:
         CA(IUnknown *pUnknownOuter);
         ~CA();
    public :
           // Delegating IUnknown
           virtual HRESULT      __stdcall  QueryInterface(const IID& iid, void **ppv) ;
           virtual ULONG         __stdcall  AddRef() ;
           virtual ULONG         __stdcall  Release() ;
           // Nondelegating IUnknown
           virtual HRESULT   __stdcall  NondelegationQueryInterface(const IID& iid, void **ppv);
           virtual ULONG         __stdcall  NondelegatingAddRef();
           virtual ULONG         __stdcall  NondelegationRelease();
           virtual HRESULT   __stdcall SomeFunction( ) ;
           private :
                  IUnknown  *m_pUnknownOuter;  // pointer to outer IUnknown
    };
    // Implemention of class CA
    CA::CA (IUnknown *pUnknownOuter)
    {
           m_Ref = 0;
           g_CompANumber ++ ;
           m_pUnknownOuter = pUnknownOuter;
    }
    CA::~CA()
    {}
    ULONG CA::NondelegatingAddRef()
    {
           m_Ref ++;
           return  (ULONG) m_Ref;
    }
    ULONG CA::NondelegationRelease ()
    {
           m_Ref --;
           if (m_Ref == 0 )
           {
                  g_CompANumber -- ;
                  delete this;
                  return 0;
           }
           return  (ULONG) m_Ref;
    }
    HRESULT CA::NondelegationQueryInterface(const IID& iid, void **ppv)
    {
           if ( iid == IID_IUnknown )
           {
                  *ppv = (INondelegatingUnknown *) this ;
                  ((IUnknown *)(*ppv))->AddRef() ; // 这里其实是调用NonDelegationAddRef()!!!!
           } else if ( iid == IID_SomeInterface )
           {
                  *ppv = (ISomeInterface *) this ;
                  ((ISomeInterface *)(*ppv))->AddRef() ; // 而这里则不然,这里直接调用了AddRef(),
                      // 如果是聚合状态调用外部Compoent的Addref,否则则调用NonDelegationAddRef!!!
           }
           else
           {
                  *ppv = NULL;
                  return E_NOINTERFACE ;
           }
           return S_OK;
    }
    ULONG CA::AddRef ()
    {
           if  ( m_pUnknownOuter != NULL )
                  return m_pUnknownOuter->AddRef();
           else
                  return NondelegatingAddRef();
    }
    ULONG CA::Release ()
    {
           if  ( m_pUnknownOuter != NULL )
                  return m_pUnknownOuter->Release ();
           else
                  return NondelegationRelease();
    }
    HRESULT CA::QueryInterface(const IID& iid, void **ppv)
    {
           if  ( m_pUnknownOuter != NULL )
                  return m_pUnknownOuter->QueryInterface(iid, ppv);
           else
                  return NondelegationQueryInterface(iid, ppv);
    }
    HRESULT CA::SomeFunction()
    {
           printf("This is CA::SomeFunction!/n");
           return S_OK;
    }
    由上面的代码可以看出,被聚合的对象需要实现两个IUnknown接口Delegation Unknown和NonDelegation Unknown接口NonDelegation Unknown是按正常方式实现的IUnknown接口。Delegation Unknown在非Aggregation使用时候直接把所有调用传给NonDelegation Unknown接口;而在Aggregation下,它把调用传给外部对象的接口,而此时外部对象通过NonDelegation接口对内部对象进行控制
    Aggregation下CAFactory的CreateInstance实现:
    HRESULT CAFactory::CreateInstance(IUnknown *pUnknownOuter, const IID& iid, void **ppv)
    {
           HRESULT hr;
           //  iid must be IID_IUnknown for aggregating
           if ( ( pUnknownOuter != NULL ) && ( iid != IID_IUnknown ) )
           {            return CLASS_E_NOAGGREGATION;       }
           *ppv=NULL;
           hr=E_OUTOFMEMORY;
           //Create the object passing function to notify on destruction.
           CA *pObj=new CA (pUnknownOuter);
           if (NULL==pObj)          return hr;  
           //Obtain the first interface pointer (which does an AddRef)
           hr = pObj->NondelegationQueryInterface(iid, ppv);
        if (hr != S_OK) {
                 //Kill the object if initial creation or FInit failed.
                  g_CompANumber --; // Reference count g_CompANumber be added in constructor
                  delete pObj;
           }
           return hr;  
    }
  5. MFC的COM Aggregation实现:COM使用了C++嵌套类来实现COM接口,并且使用接口映射表来简化编程工作,MFC对COM的支持是从类CCmdTarget开始。
    #define DECLARE_INTERFACE_MAP() /
    private: /
         static const AFX_INTERFACEMAP_ENTRY _interfaceEntries[]; /
    protected: /
         static const AFX_INTERFACEMAP interfaceMap; /
         static const AFX_INTERFACEMAP* PASCAL GetThisInterfaceMap(); /
         virtual const AFX_INTERFACEMAP* GetInterfaceMap() const; /
    struct AFX_INTERFACEMAP_ENTRY
    {
         const void* piid;       // the interface id (IID) (NULL for aggregate)
         size_t nOffset;         // offset of the interface vtable from m_unknown
    };
    struct AFX_INTERFACEMAP
    {
    #ifdef _AFXDLL
         const AFX_INTERFACEMAP* (PASCAL* pfnGetBaseMap)(); // NULL is root class
    #else
         const AFX_INTERFACEMAP* pBaseMap;
    #endif
         const AFX_INTERFACEMAP_ENTRY* pEntry; // map for this class
    };
    由此可以很明显看出,MFC继续使用Map表来实现COM接口。查看具体的Map表的增加和删除宏可以更详细的了解架构。
    #define BEGIN_INTERFACE_MAP(theClass, theBase) /
         const AFX_INTERFACEMAP* PASCAL theClass::GetThisInterfaceMap() /
             { return &theClass::interfaceMap; } /
         const AFX_INTERFACEMAP* theClass::GetInterfaceMap() const /
             { return &theClass::interfaceMap; } /
         AFX_COMDAT const AFX_INTERFACEMAP theClass::interfaceMap = /
             { &theBase::GetThisInterfaceMap, &theClass::_interfaceEntries[0], }; /
         AFX_COMDAT const AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = /
         { /
    #define INTERFACE_PART(theClass, iid, localClass) /
    { &iid, offsetof(theClass, m_x##localClass) }, /
    #define INTERFACE_AGGREGATE(theClass, theAggr)
    { NULL, offsetof(theClass, theAggr) }, /
    #define END_INTERFACE_MAP() /
    { NULL, (size_t)-1 } /
    }; /
    其中,offsetof宏可以给出成员变量与分类之间的偏移量,编译器在编译时候计算这个常数。
    而接口部分定义则使用宏BEGIN_INTERFACE_PARTINIT_INTERFACE_PARTEND_INTERFACE_PART进行定义。
    #define BEGIN_INTERFACE_PART(localClass, baseClass) /
         class X##localClass : public baseClass /
         { /
         public: /
             STDMETHOD_(ULONG, AddRef)(); /
             STDMETHOD_(ULONG, Release)(); /
             STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj); /
    #define INIT_INTERFACE_PART(theClass, localClass) /
             size_t m_nOffset; /
             INIT_INTERFACE_PART_DERIVE(theClass, localClass) /
    #define INIT_INTERFACE_PART_DERIVE(theClass, localClass) /
             X##localClass() /
                  { m_nOffset = offsetof(theClass, m_x##localClass); } /
    #define END_INTERFACE_PART(localClass) /
         } m_x##localClass; /
         friend class X##localClass; /
  6. 复习二将重点涉及COM一些高级概念,从MarshalThread Model(Apartment和Free)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值