聚合在com中的作用非常大,它是代码重用中最有效的模型。但是聚合也是比较麻烦的,因为跟包含一样,com对象B要屏蔽掉com对象A,即用户根本不知道com对象A的存在。但是用户却直接使用了com对象A的接口,通过接口的queryinterface函数是可以查找到com对象实现的所有接口,因为用户只知道com对象B的存在,对于用户来说,通过接口的queryinterface查询的结果应该都是com对象B支持的所有接口,而不应该查到com对象A的接口。因此内部要有很多的细节来处理这个。这里主要是com对象A需要处理,它需要多继承一个接口类,原来的那个接口类用来聚合用,而另外一个接口则是用于原本的功能。在下面的例子中会提到。例子用到了com对象A,com对象B以及调用程序,com对象A实现了接口ISomeInterface,com对象B实现了接口IOtherInterface,聚合了com对象A的接口ISomeInterface。
例子:
com对象A
代码:
接口:ISomeInterface.h
#ifndef __ISomeInterface_H__
#define __ISomeInterface_H__
#include "Unknwn.h"
extern "C" const GUID IID_SomeInterface;
class ISomeInterface : public IUnknown
{
public:
virtual int __stdcall Somefunction() = 0;
};
#endif
对象:4_A.h
#ifndef __4_A_H__
#define __4_A_H__
#ifndef __ISomeInterface_H__
#include "ISomeInterface.h"
#endif
class INondelegatingUnknown
{
public:
virtual HRESULT __stdcall NondelegatingQueryInterface(const IID& iid, void** ppv) = 0;
virtual ULONG __stdcall NondelegatingAddRef() = 0;
virtual ULONG __stdcall NondelegatingRelease() = 0;
};
class CA : public ISomeInterface, public INondelegatingUnknown
{
protected:
ULONG m_Ref;
public:
CA(IUnknown* pUnknownOuter);
~CA();
public:
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual HRESULT __stdcall NondelegatingQueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall NondelegatingAddRef();
virtual ULONG __stdcall NondelegatingRelease();
virtual BOOL __stdcall Somefunction();
private:
IUnknown* m_pUnknownOuter;
};
#endif
4_A.cpp
#include "stdafx.h"
#include <comutil.h>
#include <stdio.h>
#include "objbase.h"
#include "olectl.h"
#include "4_A.h"
#include "Factory.h"
#include "Registry.h"
ULONG g_LockNumber = 0;
ULONG g_4_ANumber = 0;
HANDLE g_hModule;
// {753E2E9D-7ACF-423F-AE87-710D88EEFD42}
extern "C" const GUID CLSID_4_A =
{ 0x753e2e9d, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
extern "C" const GUID IID_SomeInterface =
{ 0x753e2e9e, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
g_hModule = hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
if (clsid == CLSID_4_A) {
CAFactory *pFactory = new CAFactory;
if (pFactory == NULL)
{
return E_OUTOFMEMORY ;
}
HRESULT result = pFactory->QueryInterface(iid, ppv);
return result;
}
else return CLASS_E_CLASSNOTAVAILABLE;
}
extern "C" HRESULT __stdcall DllCanUnloadNow(void)
{
if ((g_4_ANumber == 0) && (g_LockNumber == 0)) return S_OK;
else return S_FALSE;
}
extern "C" HRESULT __stdcall DllRegisterServer()
{
char szModule[1024];
DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, szModule, 1024);
if (dwResult == 0) return SELFREG_E_CLASS;
return RegisterServer(CLSID_4_A, szModule, "4_A.Object", "4_A Component", NULL);
}
extern "C" HRESULT __stdcall DllUnregisterServer()
{
return UnregisterServer(CLSID_4_A, "4_A.Object", NULL);
}
CA::CA(IUnknown* pUnknownOuter)
{
m_Ref = 0;
g_4_ANumber++;
m_pUnknownOuter = pUnknownOuter;
}
CA::~CA()
{
}
ULONG CA::NondelegatingAddRef()
{
m_Ref++;
return (ULONG) m_Ref;
}
ULONG CA::NondelegatingRelease()
{
m_Ref--;
if(m_Ref == 0)
{
g_4_ANumber--;
delete this;
return 0;
}
return (ULONG) m_Ref;
}
HRESULT CA::NondelegatingQueryInterface(const IID& iid, void** ppv)
{
if(iid == IID_IUnknown)
{
*ppv = (INondelegatingUnknown*) this;
//((INondelegatingUnknown*)(*ppv))->NondelegatingAddRef();
((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 NondelegatingRelease();
}
HRESULT CA::QueryInterface(const IID& iid, void** ppv)
{
if(m_pUnknownOuter != NULL) return m_pUnknownOuter->QueryInterface(iid, ppv);
else return NondelegatingQueryInterface(iid, ppv);
}
int CA::Somefunction()
{
printf("调用com对象A的接口!\n");
return 1;
}
类厂:Factory.h
#ifndef __Factory_H__
#define __Factory_H__
#include "Unknwn.h"
class CAFactory : public IClassFactory
{
protected:
ULONG m_Ref;
public:
CAFactory();
~CAFactory();
HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall CreateInstance(IUnknown*, const IID& iid, void** ppv);
HRESULT __stdcall LockServer(BOOL);
};
#endif
Factory.cpp
#include "stdafx.h"
#include "Factory.h"
#include "4_A.h"
extern ULONG g_LockNumber;
extern ULONG g_4_ANumber;
CAFactory::CAFactory()
{
m_Ref = 0;
}
CAFactory::~CAFactory()
{
}
HRESULT CAFactory::QueryInterface(const IID& iid, void** ppv)
{
if(iid == IID_IUnknown)
{
*ppv = (IUnknown*) this;
((IUnknown*)(*ppv))->AddRef();
}
else if(iid == IID_IClassFactory)
{
*ppv = (IClassFactory*) this;
((IClassFactory*)(*ppv))->AddRef();
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
ULONG CAFactory::AddRef()
{
m_Ref++;
return (ULONG) m_Ref;
}
ULONG CAFactory::Release()
{
m_Ref--;
if(m_Ref == 0)
{
delete this;
return 0;
}
return (ULONG) m_Ref;
}
HRESULT CAFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv)
{
HRESULT hr;
if((pUnknownOuter != NULL) && (iid != IID_IUnknown))
{
return CLASS_E_NOAGGREGATION;
}
*ppv = NULL;
hr = E_OUTOFMEMORY;
CA* pObj = new CA(pUnknownOuter);
if(pObj == NULL) return hr;
hr = pObj->NondelegatingQueryInterface(iid, ppv);
if(hr != S_OK)
{
g_4_ANumber--;
delete pObj;
}
return hr;
}
HRESULT CAFactory::LockServer(BOOL bLock)
{
if(bLock) g_LockNumber++;
else g_LockNumber--;
return NOERROR;
}
解释:这里定义了一个接口INondelegatingUnknown,这个接口和IUnknown接口是一级的,只是这里的分工不同,这里IUnknown接口用来聚合用,而INondelegatingUnknown则是接口本身应有的功能。IUnknown作为聚合用就是它的功能是调用了com对象B的接口基本功能。
com对象B
代码:
接口:ISomeInterface.h
#ifndef __SomeInterface_H__
#define __SomeInterface_H__
#include "Unknwn.h"
extern "C" const GUID IID_SomeInterface;
class ISomeInterface : public IUnknown
{
public:
virtual int __stdcall Somefunction() = 0;
};
#endif
IOtherInterface.h
#ifndef __IOtherInterface_H__
#define __IOtherInterface_H__
#include "Unknwn.h"
extern "C" const GUID IID_OtherInterface;
class IOtherInterface : public IUnknown
{
public:
virtual BOOL __stdcall Otherfunction() = 0;
};
#endif
对象:4_B.h
#ifndef __4_B_H__
#define __4_B_H__
#ifndef __SomeInterface_H__
#include "SomeInterface.h"
#endif
#ifndef __OtherInterface_H__
#include "OtherInterface.h"
#endif
class CB : public IOtherInterface
{
protected:
ULONG m_Ref;
public:
CB();
~CB();
HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
BOOL __stdcall Otherfunction();
HRESULT Init();
private:
IUnknown* m_pUnknownInner;
ISomeInterface* m_pSomeInterface;
};
#endif
4_B.cpp
#include "stdafx.h"
#include <comutil.h>
#include <stdio.h>
#include "objbase.h"
#include "olectl.h"
#include "4_B.h"
#include "Factory.h"
#include "Registry.h"
ULONG g_LockNumber = 0;
ULONG g_4_BNumber = 0;
HANDLE g_hModule;
extern "C" const GUID CLSID_4_A =
{ 0x753e2e9d, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
extern "C" const GUID IID_SomeInterface =
{ 0x753e2e9e, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
extern "C" const GUID CLSID_4_B =
{ 0x763e2e9d, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
extern "C" const GUID IID_OtherInterface =
{ 0x763e2e9e, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
g_hModule = hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
if (clsid == CLSID_4_B)
{
CBFactory *pFactory = new CBFactory;
if (pFactory == NULL) return E_OUTOFMEMORY ;
HRESULT result = pFactory->QueryInterface(iid, ppv);
return result;
}
else return CLASS_E_CLASSNOTAVAILABLE;
}
extern "C" HRESULT __stdcall DllCanUnloadNow(void)
{
if ((g_4_BNumber == 0) && (g_LockNumber == 0)) return S_OK;
else return S_FALSE;
}
extern "C" HRESULT __stdcall DllRegisterServer()
{
char szModule[1024];
DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, szModule, 1024);
if (dwResult == 0) return SELFREG_E_CLASS;
return RegisterServer(CLSID_4_B, szModule, "4_B.Object", "4_B Component", NULL);
}
extern "C" HRESULT __stdcall DllUnregisterServer()
{
return UnregisterServer(CLSID_4_B, "4_B.Object", NULL);
}
CB::CB()
{
m_Ref = 0;
g_4_BNumber++;
m_pUnknownInner = NULL;
}
CB::~CB()
{
m_Ref = 1;
IUnknown* pUnknownOuter = this;
pUnknownOuter->AddRef();
if(m_pSomeInterface != NULL) m_pSomeInterface->Release();
if(m_pUnknownInner != NULL) m_pUnknownInner->Release();
}
HRESULT CB::Init()
{
IUnknown* pUnknownOuter = (IUnknown*) this;
HRESULT result = ::CoCreateInstance(CLSID_4_A, pUnknownOuter, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**) &m_pUnknownInner);
if(FAILED(result)) return E_FAIL;
result = m_pUnknownInner->QueryInterface(IID_SomeInterface, (void**) &m_pSomeInterface);
if(FAILED(result))
{
m_pUnknownInner->Release();
return E_FAIL;
}
pUnknownOuter->Release();
return S_OK;
}
ULONG CB::AddRef()
{
m_Ref++;
return (ULONG) m_Ref;
}
ULONG CB::Release()
{
m_Ref--;
if(m_Ref == 0)
{
g_4_BNumber--;
delete this;
return 0;
}
return (ULONG) m_Ref;
}
HRESULT CB::QueryInterface(const IID& iid, void** ppv)
{
if(iid == IID_IUnknown)
{
*ppv = (IUnknown*) this;
((IUnknown*)(*ppv))->AddRef();
}
else if(iid == IID_OtherInterface)
{
*ppv = (IOtherInterface*) this;
((IOtherInterface*)(*ppv))->AddRef();
}
else if(iid == IID_SomeInterface)
{
return m_pUnknownInner->QueryInterface(iid, ppv);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
BOOL CB::Otherfunction()
{
printf("调用com对象B的接口\n");
return true;
}
类厂:Factory.h
#ifndef __Factory_H__
#define __Factory_H__
#include "Unknwn.h"
class CBFactory : public IClassFactory
{
protected:
ULONG m_Ref;
public:
CBFactory();
~CBFactory();
HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall CreateInstance(IUnknown*, const IID& iid, void** ppv);
HRESULT __stdcall LockServer(BOOL);
};
#endif
Factory.cpp
#include "stdafx.h"
#include "Factory.h"
#include "4_B.h"
extern ULONG g_LockNumber;
extern ULONG g_4_BNumber;
CBFactory::CBFactory()
{
m_Ref = 0;
}
CBFactory::~CBFactory()
{
}
HRESULT CBFactory::QueryInterface(const IID& iid, void** ppv)
{
if(iid == IID_IUnknown)
{
*ppv = (IUnknown*) this;
((IUnknown*)(*ppv))->AddRef();
}
else if(iid == IID_IClassFactory)
{
*ppv = (IClassFactory*) this;
((IClassFactory*)(*ppv))->AddRef();
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
ULONG CBFactory::AddRef()
{
m_Ref++;
return (ULONG) m_Ref;
}
ULONG CBFactory::Release()
{
m_Ref--;
if(m_Ref == 0)
{
delete this;
return 0;
}
return (ULONG) m_Ref;
}
HRESULT CBFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv)
{
CB* pObj;
HRESULT hr;
*ppv = NULL;
hr = E_OUTOFMEMORY;
if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
pObj = new CB();
if(pObj == NULL) return hr;
pObj->AddRef();
hr = pObj->Init();
if(FAILED(hr))
{
g_4_BNumber--;
delete pObj;
return E_FAIL;
}
hr = pObj->QueryInterface(iid, ppv);
pObj->Release();
return hr;
}
HRESULT CBFactory::LockServer(BOOL bLock)
{
if(bLock) g_LockNumber++;
else g_LockNumber--;
return NOERROR;
}
解释:这里有个函数Init(),这个函数的作用就是调用对象A,获得A对象的接口指针,为后面调用做准备。
调用程序:
代码:
call.cpp
#include "windows.h"
#include <stdio.h>
#include <comutil.h>
#include <conio.h>
#include "SomeInterface.h"
#include "OtherInterface.h"
extern "C" const GUID IID_SomeInterface =
{ 0x753e2e9e, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
extern "C" const GUID IID_OtherInterface =
{ 0x763e2e9e, 0x7acf, 0x423f,
{ 0xae, 0x87, 0x71, 0xd, 0x88, 0xee, 0xfd, 0x42 } };
void main()
{
IUnknown* pUnknown;
ISomeInterface* pSomeInterface;
IOtherInterface* pOtherInterface;
HRESULT hResult;
GUID objectCLSID;
if(CoInitialize(NULL) != S_OK)
{
printf("Initialize COM library failed!\n");
return;
}
hResult = ::CLSIDFromProgID(L"4_B.Object", &objectCLSID);
if(FAILED(hResult))
{
printf("Can't find the 4_B CLSID!\n");
CoUninitialize();
return;
}
hResult = CoCreateInstance(objectCLSID, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**) &pUnknown);
if(FAILED(hResult))
{
printf("Create object failed!\n");
CoUninitialize();
return;
}
hResult = pUnknown->QueryInterface(IID_SomeInterface, (void**) &pSomeInterface);
pUnknown->Release();
if(FAILED(hResult))
{
printf("QueryInterface ISomeInterface failed!\n");
CoUninitialize();
return;
}
pSomeInterface->Somefunction();
hResult = pSomeInterface->QueryInterface(IID_OtherInterface, (void**) &pOtherInterface);
pSomeInterface->Release();
if(FAILED(hResult))
{
printf("QueryInterface IOtherInterface failed!\n");
CoUninitialize();
return;
}
pOtherInterface->Otherfunction();
pOtherInterface->Release();
CoUninitialize();
getch();
return;
}
运行结果: