Chinaunix首页 | 论坛 | 博客
  • 博客访问: 379940
  • 博文数量: 35
  • 博客积分: 2500
  • 博客等级: 少校
  • 技术积分: 797
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-02 08:51
文章分类

全部博文(35)

文章存档

2011年(1)

2010年(3)

2009年(3)

2008年(28)

我的朋友

分类: WINDOWS

2008-05-06 10:06:12

  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;
阅读(1262) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~