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!!!wink_smile.gif
           }
           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 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章