|
|
COM复习(一) : COM复用的中Containment(包容)和Aggregation(聚合)的实现 |
|
|
作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站 |
- 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_PART、INIT_INTERFACE_PART、END_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一些高级概念,从Marshal到Thread Model(Apartment和Free)。

|
|
相关文章:相关软件: |
|