8.4 一个完整的例子
下面我们将实现一个聚合了一个接口的组件。在这个例子中,组件1支持两个接口IX和IY。但它只实现了接口XX,而没有实现接口IY,并且也并没有将此接口调用转发给组件2的实现。相反,当客户向组件1查询接口IY时,组件1将返回内部组件即组件2所实现的IY接口的指针。程序清单8-3给出的是外部组件的实现,程序清单8-4则是内部组件的实现。客户基本上没有什么变化,因它并不关心我们使用的是包容还是聚合。
// 程序清单8-3 外部组件(聚合组件)的实现。
//
// Cmpnt1.cpp - Component1
//
//
#include <iostream>
#include "Iface.h"
#include "Registry.h"
using namespace std;
void trace(const char* msg) { cout << "Component 1:\t" << msg << endl; }
///
//
// Global variables
//
// Static variables
static HMODULE g_hModule = NULL; // DLL module handle
static long g_cComponents = 0; // Count of active components
static long g_cServerLocks = 0; // Count of locks
// Friendly name of component
const char g_szFriendlyName[]
= "Inside COM, Chapter 8 Example 2, Component 1";
// Version-independent ProgID
const char g_szVerIndProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1";
// ProgID
const char g_szProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1.1";
///
//
// Component A
//
class CA : public IX
// public IY
{
public:
// IUnknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
// Interface IX
virtual void __stdcall Fx() { cout << "Fx" << endl; }
/* Component aggregates instead of implementation interface IY.
// Interface IY
virtual void __stdcall Fy() { m_pIY->Fy(); }
*/
// Constructor
CA();
// Destructor
~CA();
// Initialization function called by the class factory
// to create contained component
HRESULT __stdcall Init();
private:
// Reference count
long m_cRef;
// Pointer to the aggregated component's IY Interface
// (We do not have to retain an IY pointer. However, we
// can use it in QueryInterface.)
IY* m_pIY;
// Pointer to inner component's IUnknown
IUnknown* m_pUnknownInner;
}
//
// Constructor
//
CA::CA()
: m_cRef(1),
m_pUnknownInner(NULL)
{
InterlockedIncrement(&g_cComponents);
}
//
// Destructor
//
CA::~CA()
{
InterlockedDecrement(&g_cComponents);
trace("Destroy self.");
// Prevent recursive destruction on next AddRef/Release pair.
m_cRef = 1;
// Counter the pUnknownOuter->Release in the Init method.
IUnknown* pUnknownOuter = this;
pUnknownOuter->AddRef();
// Properly release the pointer: there may be per-interface
// reference counts.
m_pIY->Release();
// Release contained component
if (m_pUnknownInnter != NULL) {
m_pUnknownInnter->Release();
}
}
// Initailize the component by creating the contained component.
HRESULT __stdcall CA::Init()
{
// Get the pointer to the outer unknown.
// Since this component is not aggregated. the outer unknown
// is the same as the this pointer.
IUnknown* pUnknownOuter = this;
trace("Create inner component.");
HRESULT hr =
::CoCreateInstance(CLSID_Component2,
pUnknownOuter, // Outer component's IUnknown
CLSCTX_INPROC_SERVER,
IID_IUnknown, // IUnknown when aggregating
(void**)&m_pUnknownInner);
if (FAILED(hr)) {
trace("Could not create contained component.");
return E_FAIL;
}
// This call will increment the reference count on the outer component.
trace("Get the IY interface from the inner component.");
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY);
if (FAILED(hr)) {
trace("Inner component does not support interface IY.");
m_pUnknownInner->Release();
return E_FAIL;
}
// We need to release the reference count added to the
// outer component in the above call. So call Release
// on the pointer you passed to CoCreateInstance.
pUnknownOuter->Release();
return S_OK;
}
//
// IUnknown implementation
//
HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown) {
*ppv = static_cast<IUnknown*>(this);
}
else if (iid == IID_IX) {
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IY) {
trace("Return inner component's IY interface.");
#if 1
// You can query for the interface.
return m_pUnknownInner->QueryInterface(iid, ppv);
#else
// Or you can return a cached pointer.
* ppv = m_pIY;
// Fall through so it will get AddRef'ed
#endif
}
else {
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
ULONG __stdcall CA::AddRef()
{
retrun InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CA::Release()
{
if (InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
///
//
// Class Factory
//
class CFactory : public IClassFactory
{
public:
// IUnknown
virtual HRESULT __stdcall QueryInterface(cosnt IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
// Interface IClassFactory
virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv);
virtual HRESULT __stdcall LockServer(BOOL bLock);
// Constructor
CFactory() : m_cRef(1) {}
// Destructor
~CFactory() {}
private:
long m_cRef;
}
//
// Class factory IUnknown implemenation
//
HRESULT __stdcall CFactory::QueryInstance(REFIID iid, void** ppv)
{
IUnknown* pI;
if ((iid == IID_IUnknown) || (iid == IID_IClassFactory)) {
pI = static_cast<IClassFactory*>(this);
}
else {
*ppv = NULL;
return E_NOINTERFACE;
}
pI->AddRef();
*ppv = pI;
return S_OK;
}
ULONG CFactory::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG CFactory::Release()
{
if (InterlockedDecrement(&m_cRef)) {
delete this;
return 0;
}
return m_cRef;
}
//
// IClassFactory implementation
//
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv)
{
HRESULT hr = E_FAIL;
// Cannot aggregate
if (pUnknownOuter != NULL) {
return CLASS_E_NOAGGREGATION;
}
// Create component.
CA* pA = new CA;
if (pA == NULL) {
return E_OUTOFMEMORY;
}
// Initialize the component.
hr = pA->Init();
if (FAILED(hr)) {
// Initialization failed. Delete component.
pA->Release();
return hr;
}
// Get the requested interface.
hr = pA->QuerInterface(iid, ppv);
pA->Release();
return hr;
}
// LockServer
HRESULT __stdcall CFactory::LockServer(BOOL bLock)
{
if (bLock) {
InterlockedIncrement(&g_cServerLocks);
}
else {
InterlockedDecrement(&g_cServerLocks);
}
return S_OK;
}
///
//
// Exported functions
//
STDAPI DllCanUnloadNow()
{
if (g_cComponents == 0) && (g_cServerLocks == 0)) {
return S_OK;
}
else {
return S_FALSE;
}
}
//
// Get class factory.
//
STDAPI DllGetClassObject(const CLSID& clsid,
const IID& iid,
void** ppv)
{
// Can we create this component?
if (clsid != CLSID_Component1) {
return CLASS_E_CLASSNOTAVAILABLE;
}
// Create class factory.
CFactory* pFactory = new CFactory; // No AddRef in constructor
if (pFactory == NULL) {
return E_OUTOFMEMORY;
}
// Get requested interface.
HRESULT hr = pFactory->QueryInterface(iid, ppv);
pFactory->Release();
return hr;
}
//
// Server registration
//
STDAPI DllRegisterServer()
{
return RegisterServer(g_hModule,
CLSID_Component1,
g_szFriendlyName,
g_szVerIndProgID,
g_szProgID);
}
STDAPI DllUnregisterServer()
{
return UnregisterServer(CLSID_Component1,
g_szVerIndProgID,
g_szProgID);
}
///
//
// DLL module information
//
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
void* lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
g_hModule = hModule;
}
return TRUE;
}
// 程序清单8-4 内部组件(被聚合组件)的实现。
//
// Cmpnt2.cpp - Component 2
// Note the changes in the class factory marked with
//
#include <iostream>
#include <objbase.h>
#include "Iface.h"
#include "Registry.h"
using namespace std;
void trace(const char* msg) { cout << "Component2:\t" << msg << endl; }
///
//
// Global variables
//
// Static variables
static HMODULE g_hModule = NULL; // DLL module handle
static long g_cComponents = 0; // Count of active components
static long g_cServerLocks = 0; // Count of locks
// Friendly name of component
const char g_szFriendlyName[]
= "Inside COM, Chapter 8 Example 2, Component 2";
// Version-independent ProgID
const char g_szVerIndProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt2";
// ProgID
const char g_szProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt2.1";
///
//
// Nondelegating IUnknown interface
//
struct INondelegatingUnknown
{
virtual HRESULT __stdcall
NondelegatingQueryInterface(const IID&, void**) = 0;
virtual ULONG __stdcall NondelegatingAddRef() = 0;
virtual ULONG __stdcall NondelegatingRelease() = 0;
};
///
//
// Component
//
class CB : public IY,
INondelegatingUnknown
{
public:
// Delegating IUnknown
virtual HRESULT __stdcall
QueryInterface(const IID& iid, void** ppv)
{
trace("Delegate QueryInterface.");
return m_pUnknownOuter->QueryInterface(iid, ppv);
}
virtual ULONG __stdcall AddRef()
{
trace("Delegate AddRef.");
return m_pUnknownOuter->AddRef();
}
virtual ULONG __stdcall Release()
{
trace("Delegate Release.");
return m_pUnknownOuter->Release();
}
// Nondelegating IUnknown
virtual HRESULT __stdcall
NondelegatingQueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall NondelegatingAddRef();
virtual ULONG __stdcall NondelegatingRelease();
// Interface IY
virtual void __stdcall Fy() { cout << "Fy" << endl; }
// Constructor
CB(IUnknown* m_pUnknownOuter);
// Destructor
~CB();
private:
long m_cRef;
IUnknown* m_pUnknownOuter;
}
//
// IUnknown implementation
//
HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown) {
// !!! CAST IS VERY IMPORTANT!!!
*ppv = static_cast<INondelegatingUnknown*>(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;
}
ULONG __stdcall CB::NondelegatingAddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CB::NondelegateRelease()
{
if (InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
//
// Constructor
//
CB::CB(IUnknown* pUnknownOuter)
: m_cRef(1)
{
::InterlockedIncrement(&g_cComponents);
if (pUnknownOuter == NULL) {
trace("Not aggregating: delegate to nondelegating IUnknown.");
m_pUnknownOuter = reinterpret_cast<IUnknown*>
(static_cast<INondelegatingUnknown*>
(this));
}
else {
trace("Aggregating: delegate to outer IUnknown.");
m_pUnknownOuter = pUnknownOuter;
}
}
//
// Destructor
//
CB::~CB()
{
InterlockedDecrement(&g_cComponents);
trace("Destroy self.");
}
///
//
// Class factory
//
class CFactory : pubic IClassFactory
{
public:
// 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* pUnknownOuter,
const IID& iid,
void** ppv);
virtual HRESULT __stdcall LockServer(BOOL bLock);
// Constructor
CFactory() : m_cRef(1) {}
// Destructor
~CFactory() {}
private:
long m_cRef;
}
//
// Class factory IUnknown implementation
//
HRESULT CFactory::QueryInstance(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 InterlockedIncremetn(&m_cRef);
}
ULONG __stdcall CFactory::Release()
{
if (InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
//
// IClassFactory implementation
//
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv)
{
// Aggregate only if the requested iid is IID_IUnknown.
if ((pUnknownOuter != NULL) && (iid != IID_IUnknown)) {
return CLASS_E_NOAGGREGATION;
}
// Create component.
CB* pB = new CB(pUnknownOuter);
if (pB == NULL) {
return E_OUTOFMEMORY;
}
// Get the requested interface.
HRESULT hr = pB->NondelegatingQueryInterface(iid, ppv);
pB->NondelegatingRelease();
return hr;
}
// LockServer
HRESULT CFactory::LockServer(BOOL bLock)
{
if (bLock) {
InterlockedIncrement(&g_cServerLocks);
}
else {
InterlockedDecrement(&g_cServerLocks);
}
return S_OK;
}
///
//
// Exported functions
//
STDAPI DllCanUnloadNow()
{
if ((g_cComponents == 0) && (g_cServerLocks == 0)) {
return S_OK;
}
else {
return S_FALSE;
}
}
//
// Get class factory.
//
STDAPI DllGetClassObject(const CLSID& clsid,
const IID& iid,
void** ppv)
{
// Can we create this component?
if (clsid != CLSID_Component2) {
return CLASS_E_CLASSNOTAVAILABLE;
}
// Create class factory.
CFactory* pFactory = new CFactory; // No AddRef in constructor
if (pFactory == NULL) {
return E_OUTOFMEMORY;
}
// Get requested interface.
HRESULT hr = pFactory->QueryInterface(iid, ppv);
pFactory->Release();
return hr;
}
//
// Server registraton
//
STDAPI DllRegisterServer()
{
return RegisterServer(g_hModule,
CLSID_Components2,
g_szFriendlyName,
g_szVerIndProgID,
g_szProgID);
}
STDAPI DllUnregisterServer()
{
return UnregisterServer(CLSID_Components2,
g_szVerIndProgID,
g_szProgID);
}
///
//
// DLL module information
//
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
void* lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
g_hModule = hModule;
}
return TRUE;
}
在第五章的动态链接过后吗,就正式进入了COM组件的学习,因个人原因,并未详对学习过程进行详细记录
COM技术内幕所有学习笔记暂时完结
这是github中有前辈整理的COM技术内幕项目源码