包容和聚合(COM技术内幕笔记五)
包容和聚合:
包容和聚合实际上是使一个组件使用另外一个组件的一种技术。在包容的情况下,外部组件将包含内部组件。在聚合的情况下,外部组件聚合内部组件。
在此设想一下,外部组件是我们的要实现的组件,而内部组件是其它要重用的组件。
包容是外部组件包含指向内部组件接口的指针.外部组件相对来说是内部组件的一个客户,它将使用内部组件的接口来实现它自己的接口.
聚合是包容的一个特例,当一个外部组件聚合了某个内部组件的一个接口时,它并没有像包容那样重新实现此接口并明确地将调用请求转发给内部组件。相反,外部组件将直接把内部件的接口指针返回给客户。
如何使用包容:
在前一节,建立了一个组件CA,其实现了IX,IY接口。在这一节,暂时把其看作是一内部组件。我们要使用其对IY接口的函数实现
新建一个DLL项目,新建一接口IX,新建一个组件的CLSID。另外,导入CA项目IFACE.h中的IY接口IID和CA组件的CLSID。如下所示:
extern "C"
{
// {3CA3B6D4-799C-4d5d-BF3A-373C4EECE925} 此IX是新建的IID
static const IID IID_IX =
{ 0x3ca3b6d4, 0x799c, 0x4d5d, { 0xbf, 0x3a, 0x37, 0x3c, 0x4e, 0xec, 0xe9, 0x25 } };
// {41A5F090-B33A-4ae8-A1BB-EF2D0B4F8B0E} //此IY是从CA中IID_IY的复制
static const IID IID_IY =
{ 0x41a5f090, 0xb33a, 0x4ae8, { 0xa1, 0xbb, 0xef, 0x2d, 0xb, 0x4f, 0x8b, 0xe } };
}
// {3D29721C-8D93-4c24-A8A5-4CE01FD9FD00} 这是CB组件新建的CLSID
static const CLSID CLSID_CTANINFACE =
{ 0x3d29721c, 0x8d93, 0x4c24, { 0xa8, 0xa5, 0x4c, 0xe0, 0x1f, 0xd9, 0xfd, 0x0 } };
// {282D8F98-BC89-43d5-9225-0B1BB479CBDE} 这是CA组件复制过来的CLSID
static const CLSID CLSID_Component1 =
{ 0x282d8f98, 0xbc89, 0x43d5, { 0x92, 0x25, 0xb, 0x1b, 0xb4, 0x79, 0xcb, 0xde } };
{
// {3CA3B6D4-799C-4d5d-BF3A-373C4EECE925} 此IX是新建的IID
static const IID IID_IX =
{ 0x3ca3b6d4, 0x799c, 0x4d5d, { 0xbf, 0x3a, 0x37, 0x3c, 0x4e, 0xec, 0xe9, 0x25 } };
// {41A5F090-B33A-4ae8-A1BB-EF2D0B4F8B0E} //此IY是从CA中IID_IY的复制
static const IID IID_IY =
{ 0x41a5f090, 0xb33a, 0x4ae8, { 0xa1, 0xbb, 0xef, 0x2d, 0xb, 0x4f, 0x8b, 0xe } };
}
// {3D29721C-8D93-4c24-A8A5-4CE01FD9FD00} 这是CB组件新建的CLSID
static const CLSID CLSID_CTANINFACE =
{ 0x3d29721c, 0x8d93, 0x4c24, { 0xa8, 0xa5, 0x4c, 0xe0, 0x1f, 0xd9, 0xfd, 0x0 } };
// {282D8F98-BC89-43d5-9225-0B1BB479CBDE} 这是CA组件复制过来的CLSID
static const CLSID CLSID_Component1 =
{ 0x282d8f98, 0xbc89, 0x43d5, { 0x92, 0x25, 0xb, 0x1b, 0xb4, 0x79, 0xcb, 0xde } };
在组件CB实现的时候,添加一成员变量:
private:
IY* m_pIY;
对IY接口的Fy函数的实现,与组件CA不同:
Virtual void __stdcall CB::Fy()
{
m_pIY->Fy();
}
对组件CB新增一成员函数 HRESULT Init();
HRESULT CB::Init()
{
trace("Create Contained component.");
//CLISD_Component1为组件CA的CLSID
HRESULT hr = ::CoCreateInstance(CLSID_Component1,
NULL,
CLSCTX_INPROC_SERVER,
IID_IY,(void**)&m_pIY);
if(FAILED(hr))
{
trace("Could not create contained components");
return E_FAIL;
}
else
return S_OK;
}
{
trace("Create Contained component.");
//CLISD_Component1为组件CA的CLSID
HRESULT hr = ::CoCreateInstance(CLSID_Component1,
NULL,
CLSCTX_INPROC_SERVER,
IID_IY,(void**)&m_pIY);
if(FAILED(hr))
{
trace("Could not create contained components");
return E_FAIL;
}
else
return S_OK;
}
至于CB的其它实现和CA相同,暂不累叙,如有不清楚的概念请看前一节。
在组件CB的CFactory::CreateInstance函数中加入对Init函数的调用:
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv)
{
CA* pA = new CA();
if(pA == NULL)
return E_OUTOFMEMORY;
HRESULT hr = pA->Init();
if(FAILED(hr))
{
pA->Release();
return hr;
}
hr = pA->QueryInterface(iid,ppv);
pA->Release();
return hr;
}
{
CA* pA = new CA();
if(pA == NULL)
return E_OUTOFMEMORY;
HRESULT hr = pA->Init();
if(FAILED(hr))
{
pA->Release();
return hr;
}
hr = pA->QueryInterface(iid,ppv);
pA->Release();
return hr;
}
在此,就实现了组件CB对组件CA的包容。CB没有自己去实现基类IY的Fy()函数,而是把这个任务交给了组件CA对于Fy()函数的实现。一切的一切都是通过组件CB中的Init函数。通过CoCreateInstance查询组件CA的IY接口。然后返回IY指针,赋给CB的私有成员m_pIY。
通过对于m_pIY的包容,实现了组件的复用。
至于组件的聚合,下一节再叙。