- 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() ; // 這裏其實是調用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;
} - 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)。
COM複用的中Containment(包容)和Aggregation(聚合)的實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.