第8章
“实现继承”,指的是继承基类代码或实现,“接口继承”,指的是继承基类类型或接口。 COM支持的继承是接口继承,不支持实现继承。实现继承会导致一个对象的实现同另外一个对象实现关联起来,当基类修改后,派生类也就必须被修改,甚至客户端的程序也需要修改,这显然有悖于COM组件编程的基本思想。
在C++中,对类的改造用包容和继承来实现的。在COM中,对组件的改造是使用包容和聚合来实现的,包容和聚合都是在接口级实现的。
包容
包容,是一个组件使用另外一个组件的技术,分别成为外部组件和内部组件。
包容的情况下,外部组件包含指向内部组件接口的指针,外部组件只是内部组件的一个客户。外部组件使用内部组件的接口来实现它自己的接口,并且可以在接口的实现函数加上它对内部组件接口实现的修改。
组件的包容类似c++的包容。
示意图如下
包容的实现
在下面的例子中,组件1(Component1)是一个实现了IX和IY接口的外部组件,它复用了组件2(组件1包容的内部组件)对IY接口的实现。源码与第七章的没多大差别,只是在组建1中加入了一个Init()的函数,用来创建组件2中的IY接口指针。组件2是一个典型的COM组件。当客户向Component1请求IY接口时,Component1将返回其IY接口的一个指针。当客户调用Component1中的IY接口时,Component1通过如下的代码将把这些调用请求转发给Component2。
void __stdcall CA::Fy()
{
m_pIy->Fy();
}
当Component1将自己销毁时,它将调用m_pIy上的Release,以使Component2将自己从内存释放。Component1的类厂所做的修改,只是在类厂创建好Component1之后加上对Component1的Init()的调用,用来创建组件2。
本章代码
组件2部分:cmpnt2.cpp
//
//cmpnt2.cpp
//use: cl /LD cmpnt2.cpp guids.cpp registry.cpp cmpnt2.def uuid.lib ole32.lib advapi32.lib
// regsvr32 /s cmpnt2.dll
// ole32.lib COMLIBRARY advapi32.lib REGISTER
#include <objbase.h>
#include "iface.h"
#include "registry.h"
#include <iostream>
#include <string>
using namespace std;
//global function
//
static HMODULE g_hModule = NULL; //COMPONENT2 MODULE HANDLE
static long g_lComponent = 0; //COMPONENT2 COUNT
static long g_lServerLocks = 0; //CFactory COUNT
//Friendly Name
const char g_szFriendlyName[]
= "Inside COM, Chapter 8 Example 1, Component 2";
//Version-independent ProgID
const char g_szVerIndProgID[] = "InsideCOM.chap08.ex1.cmpnt2";
//ProgID
const char g_szProgID[] = "InsideCOM.chap08.ex1.cmpnt2.1";
//trace function
void trace(string msg)
{
cout<<msg<<endl;
}
////////////////////////////////////////////
//class CB
//
class CB : public IY
{
public:
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual void __stdcall Fy() {cout<<"CB::Fy"<<endl;}
CB();
~CB();
private:
long m_cRef;
};
CB::CB():m_cRef(1)
{
InterlockedIncrement(&g_lComponent);
}
CB::~CB()
{
trace("component2 destroy self");
InterlockedDecrement(&g_lComponent);
}
ULONG __stdcall CB::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CB::Release()
{
if(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT __stdcall CB::QueryInterface(const IID& iid, void **ppv)
{
if(iid == IID_IUnknown)
{
*ppv = static_cast<IY*>(this);
}
else if(iid == IID_IY)
{
*ppv = static_cast<IY*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
/////////////////////////////////////////////
//class factory
//
class CFactory : public IClassFactory
{
public:
//interface iunknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
//interface iclassfactory
virtual HRESULT __stdcall CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv);
virtual HRESULT __stdcall LockServer(BOOL bLock);
CFactory();
~CFactory();
private:
long m_cRef;
};
CFactory::CFactory():m_cRef(1)
{
}
CFactory::~CFactory()
{
trace("component2 cfactory : destroy self");
}
HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void **ppv)
{
if(iid == IID_IUnknown || iid == IID_IClassFactory)
{
*ppv = static_cast<IClassFactory*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
ULONG __stdcall CFactory::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CFactory::Release()
{
if(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
//CreateInstance
HRESULT __stdcall CFactory::CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv)
{
if(pIUnknownOuter != NULL)
{
trace("no aggregation");
return CLASS_E_NOAGGREGATION;
}
//Create Compnent2
CB *pB = new CB();
if(pB == NULL)
{
return E_OUTOFMEMORY;
}
//Get Request interface
HRESULT hr = pB->QueryInterface(iid, ppv);
//Release IUnknown interface
pB->Release();
return hr;
}
HRESULT __stdcall CFactory::LockServer(BOOL bLock)
{
if(bLock == TRUE)
{
InterlockedIncrement(&g_lServerLocks);
}
else
{
InterlockedDecrement(&g_lServerLocks);
}
return S_OK;
}
////////////////////////////////////////
//export functions
//
//Get Interface IClassFactory
STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
if(clsid != CLSID_Component2)
return CLASS_E_CLASSNOTAVAILABLE;
CFactory *pFactory = new CFactory();
if(pFactory == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pFactory->QueryInterface(iid, ppv);
pFactory->Release();
return hr;
}
STDAPI DllCanUnloadNow()
{
if(g_lComponent == 0 && g_lServerLocks == 0)
return S_OK;
else
return S_FALSE;
}
STDAPI DllRegisterServer()
{
return RegisterServer(g_hModule,
CLSID_Component2,
g_szFriendlyName,
g_szVerIndProgID,
g_szProgID);
}
STDAPI DllUnRegisterServer()
{
return UnregisterServer(CLSID_Component2,
g_szVerIndProgID,
g_szProgID);
}
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved)
{
if(dwReason == DLL_PROCESS_ATTACH)
{
g_hModule = hModule;
}
return TRUE;
}
cmpnt2.def
LIBRARY cmpnt2.dll
DESCRIPTION 'Chapter08 Component2'
EXPORTS DllGetClassObject @2 private
DllCanUnloadNow @3 private
DllRegisterServer @4 private
DllUnRegisterServer @5 private
组件1部分:cmpnt1.
//
//cmpnt1.cpp
//use: cl /LD cmpnt1.cpp guids.cpp registry.cpp cmpnt2.def uuid.lib ole32.lib advapi32.lib
// regsvr32 /s cmpnt1.dll
// ole32.lib COMLIBRARY advapi32.lib REGISTER
#include <objbase.h>
#include "iface.h"
#include "registry.h"
#include <iostream>
#include <string>
using namespace std;
//global function
//
static HMODULE g_hModule = NULL; //COMPONENT1 MODULE HANDLE
static long g_lComponent = 0; //COMPONENT1 COUNT
static long g_lServerLocks = 0; //CFactory COUNT
//Friendly Name
const char g_szFriendlyName[]
= "Inside COM, Chapter 8 Example 1, Component 1";
//Version-independent ProgID
const char g_szVerIndProgID[] = "InsideCOM.chap08.ex1.cmpnt1";
//ProgID
const char g_szProgID[] = "InsideCOM.chap08.ex1.cmpnt1.1";
//trace function
void trace(string msg)
{
cout<<msg<<endl;
}
////////////////////////////////////////////
//class CA
//
class CA : public IX, public IY
{
public:
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual void __stdcall Fx() {cout<<"CA::Fx"<<endl;}
virtual void __stdcall Fy();
CA();
~CA();
HRESULT __stdcall Init();
private:
//pointer to the contained components's IY interface
IY *m_pIy;
long m_cRef;
};
CA::CA():m_cRef(1)
{
InterlockedIncrement(&g_lComponent);
m_pIy = NULL;
}
CA::~CA()
{
trace("component1 destroy self");
InterlockedDecrement(&g_lComponent);
if(m_pIy != NULL)
{
m_pIy->Release();
}
}
ULONG __stdcall CA::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CA::Release()
{
if(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT __stdcall CA::QueryInterface(const IID& iid, void **ppv)
{
if(iid == IID_IUnknown)
{
*ppv = static_cast<IX*>(this);
}
else if(iid == IID_IX)
{
*ppv = static_cast<IX*>(this);
}
else if(iid == IID_IY)
{
*ppv = static_cast<IY*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
void __stdcall CA::Fy()
{
m_pIy->Fy();
}
HRESULT __stdcall CA::Init()
{
HRESULT hr = CoCreateInstance(CLSID_Component2,
NULL,
CLSCTX_INPROC_SERVER,
IID_IY,
(void**)&m_pIy);
if(FAILED(hr))
{
trace("couldn't create contained component");
return E_FAIL;
}
else
{
return S_OK;
}
}
/////////////////////////////////////////////
//class factory
//
class CFactory : public IClassFactory
{
public:
//interface iunknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
//interface iclassfactory
virtual HRESULT __stdcall CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv);
virtual HRESULT __stdcall LockServer(BOOL bLock);
CFactory();
~CFactory();
private:
long m_cRef;
};
CFactory::CFactory():m_cRef(1)
{
}
CFactory::~CFactory()
{
trace("component1 cfactory : destroy self");
}
HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void **ppv)
{
if(iid == IID_IUnknown || iid == IID_IClassFactory)
{
*ppv = static_cast<IClassFactory*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
ULONG __stdcall CFactory::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CFactory::Release()
{
if(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
//CreateInstance
HRESULT __stdcall CFactory::CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv)
{
if(pIUnknownOuter != NULL)
{
trace("no aggregation");
return CLASS_E_NOAGGREGATION;
}
//Create Compnent1
CA *pA = new CA();
if(pA == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pA->Init();
if(FAILED(hr))
{
//Initialize failed.Delete Component
pA->Release();
return hr;
}
//Get Request interface
hr = pA->QueryInterface(iid, ppv);
//Release IUnknown interface
pA->Release();
return hr;
}
HRESULT __stdcall CFactory::LockServer(BOOL bLock)
{
if(bLock == TRUE)
{
InterlockedIncrement(&g_lServerLocks);
}
else
{
InterlockedDecrement(&g_lServerLocks);
}
return S_OK;
}
////////////////////////////////////////
//export functions
//
//Get Interface IClassFactory
STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
if(clsid != CLSID_Component1)
return CLASS_E_CLASSNOTAVAILABLE;
CFactory *pFactory = new CFactory();
if(pFactory == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pFactory->QueryInterface(iid, ppv);
pFactory->Release();
return hr;
}
STDAPI DllCanUnloadNow()
{
if(g_lComponent == 0 && g_lServerLocks == 0)
return S_OK;
else
return S_FALSE;
}
STDAPI DllRegisterServer()
{
return RegisterServer(g_hModule,
CLSID_Component1,
g_szFriendlyName,
g_szVerIndProgID,
g_szProgID);
}
STDAPI DllUnRegisterServer()
{
return UnregisterServer(CLSID_Component1,
g_szVerIndProgID,
g_szProgID);
}
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved)
{
if(dwReason == DLL_PROCESS_ATTACH)
{
g_hModule = hModule;
}
return TRUE;
}
cmpnt1.def
LIBRARY cmpnt1.dll
DESCRIPTION 'Chapter08 Component1'
EXPORTS DllGetClassObject @2 private
DllCanUnloadNow @3 private
DllRegisterServer @4 private
DllUnRegisterServer @5 private
组件1和组件2公用的文件
iface.h
#include <objbase.h>
interface IX:IUnknown
{
virtual void __stdcall Fx() = 0;
};
interface IY:IUnknown
{
virtual void __stdcall Fy() = 0;
};
extern const IID IID_IX; //Interface ID for IX
extern const IID IID_IY; //Interface ID for IY
extern const CLSID CLSID_Component1; //CLSID for Cmpnt1
extern const CLSID CLSID_Component2; //CLSID for Cmpnt2
guids.cpp
#include <objbase.h>
// {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IX =
{0x32bb8320, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IY =
{0x32bb8321, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// {0c092c22-882c-11cf-a6bb-0080c7b2d682}
extern const CLSID CLSID_Component1 =
{0x0c092c22, 0x882c, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// {0c092c23-882c-11cf-a6bb-0080c7b2d682}
extern const CLSID CLSID_Component2 =
{0x0c092c23, 0x882c, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
注册表文件registry.h和registry.cpp与chap07相同
运行结果
包容的主要用途
包容的主要用途是通过给已有的接口加上代码以扩展此接口。