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

类别:软件工程 点击:0 评论:0 推荐:
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做任何改动。 Containment的例子实现略(潘爱民《COM原理与应用》第四章) Aggregation则比较复杂,Component A必须能够适应被Aggregation下的特殊处理。其核心在于QueryInterface函数。Aggregation涉及到聚合对象和被聚合对象双方的协作,体现了真正意义上的COM复用,而Containment只是客户程序和Component的嵌套这是Containment和Aggregation的本质区别。 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() ;
       } else if ( iid == IID_SomeInterface )
       {
              *ppv = (ISomeInterface *) this ;
              ((ISomeInterface *)(*ppv))->AddRef() ;
       }
       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;  
} 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; \ 复习二将重点涉及COM一些高级概念,从MarshalThread Model(Apartment和Free)。

本文地址:http://com.8s8s.com/it/it33071.htm