8.4 一个完整的例子
下面我们将实现一个聚合了一个接口的组件。在这个例子中,组件1支持两个接口IX和IY。但它只实现了接口IX,而没有实现接口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 DLL 模块句柄 用于跟踪模块句柄
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 无关的ProgID
const char g_szVerIndProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1";
// ProgID
const char g_szProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1.1";
///
//
// Component A 组件A
// 定义了 CA 类,继承接口 IX。
// 实现聚合其他组件的功能,通过 QueryInterface 支持接口查询,AddRef 和 Release 处理引用计数。
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 接口IY
virtual void __stdcall Fx() { cout << "Fx" << endl; }
/* Component aggregates instead of implementation interface IY. 组件聚合而不是实现接口IY
// Interface IY 接口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 指向聚合组件的IY接口的指针
// (We do not have to retain an IY pointer. However, we can use it in QueryInterface.)
// (我们不需要保留y指针。但是,我们可以在QueryInterface中使用它。)
IY* m_pIY; // 指向被聚合组件的 IY 接口
// Pointer to inner component's IUnknown
// 指向内部组件IUnknown的指针
IUnknown* m_pUnknownInner; // 指向内部组件的 IUnknown 接口
}
//
// Constructor
//初始化组件 CA,设置初始引用计数为 1,并将指向内部组件的指针设为 NULL,同时增加全局组件计数
CA::CA()
: m_cRef(1),
m_pUnknownInner(NULL)
{
InterlockedIncrement(&g_cComponents); // 增加全局组件计数
}
//
// Destructor
// 析构函数在销毁 CA 时,减少全局组件计数,防止递归销毁,并释放指向内部组件的指针。
CA::~CA()
{
InterlockedDecrement(&g_cComponents); // 减少全局组件计数
trace("Destroy self."); // 输出销毁信息
// Prevent recursive destruction on next AddRef/Release pair.
// 防止下一个AddRef/Release对的递归销毁。
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.
// 通过创建包含的组件来初始化组件。
// Init 函数用于初始化组件 CA,创建内部组件,并获取其 IY 接口。如果组件创建失败或接口不支持,则释放资源并返回错误。
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.
// 因为这个组件没有聚合。外部unknown与this指针相同。
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.
// 所以在你传递给CoCreateInstance的指针上调用Release。
pUnknownOuter->Release(); // 释放外部组件引用计数
return S_OK;
}
//
// IUnknown implementation IUnknown实现
// QueryInterface 用于查询对象支持的接口,并返回相应的接口指针;
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 ... #else ... #endif 是一个预处理指令,用于控制代码的条件编译。
// 在这里,它用于选择两种不同的处理 IID_IY 接口请求的方式。这部分代码允许你灵活地选择查询接口信息或者返回缓存的接口指针
#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;
}
// AddRef 增加引用计数;Release 减少引用计数并在必要时销毁对象。
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 类厂
// 实现 IClassFactory 接口,负责创建组件实例 (CreateInstance) 并管理服务器锁 (LockServer)。
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 接口IClassFactory
virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv);
virtual HRESULT __stdcall LockServer(BOOL bLock);
// Constructor
CFactory() : m_cRef(1) {}// 初始化引用计数为 1
// Destructor
~CFactory() {}
private:
long m_cRef;
}
//
// Class factory IUnknown implemenation
//类工厂:IUnknown的实现
// 用于返回 IClassFactory 或 IUnknown 接口
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;
}
// AddRef 和 Release 用于管理类工厂的引用计数
ULONG CFactory::AddRef()
{
return InterlockedIncrement(&m_cRef); // 增加类工厂的引用计数
}
ULONG CFactory::Release()
{
if (InterlockedDecrement(&m_cRef)) // 减少引用计数,如果为 0 则删除对象
{
delete this;
return 0;
}
return m_cRef;
}
//
// IClassFactory implementation
// IClassFactory实现 用于创建 CA 组件的实例并返回请求的接口
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();// 释放组件(即使 QueryInterface 成功)
return hr;
}
// LockServer控制服务器的锁定状态,影响组件是否可以卸载。
HRESULT __stdcall CFactory::LockServer(BOOL bLock)
{
if (bLock) {
InterlockedIncrement(&g_cServerLocks); // 增加锁计数
}
else {
InterlockedDecrement(&g_cServerLocks); // 减少锁计数
}
return S_OK;
}
///
//
// Exported functions
// 输出功能:用于决定 DLL 是否可以从内存中卸载,当没有活动组件且服务器未被锁定时返回 S_OK,允许卸载
STDAPI DllCanUnloadNow()
{
// 当组件计数和服务器锁都为 0 时,允许卸载 DLL
if (g_cComponents == 0) && (g_cServerLocks == 0)) {
return S_OK;
}
else {
return S_FALSE;
}
}
//
// Get class factory.
//获取类工厂。DllGetClassObject 用于创建类工厂的实例,并返回请求的接口,用于对象的创建过程
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 服务器注册
// DllRegisterServer 和 DllUnregisterServer 用于将组件注册到系统中或者从系统中移除。
STDAPI DllRegisterServer()
{
// 调用 RegisterServer 注册组件
return RegisterServer(g_hModule,
CLSID_Component1,
g_szFriendlyName,
g_szVerIndProgID,
g_szProgID);
}
STDAPI DllUnregisterServer()
{
// 调用 UnregisterServer 反注册组件
return UnregisterServer(CLSID_Component1,
g_szVerIndProgID,
g_szProgID);
}
///
//
// DLL module information
// DLL 主入口点
// DllMain 是 DLL 的主入口点,用于处理 DLL 加载和卸载的事件
// 在 DLL_PROCESS_ATTACH 时保存模块句柄,以供其他函数使用。
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
void* lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
g_hModule = hModule; // 保存模块句柄
}
return TRUE; // 返回 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 // DLL 模块句柄
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 版本无关的 ProgID
const char g_szVerIndProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt2";
// ProgID
const char g_szProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt2.1";
///
//
// Nondelegating IUnknown interface
// INondelegatingUnknown 接口
// 定义了一个非委托的 IUnknown 接口,用于组件的内部接口管理
struct INondelegatingUnknown
{
virtual HRESULT __stdcall NondelegatingQueryInterface(const IID&, void**) = 0;
virtual ULONG __stdcall NondelegatingAddRef() = 0;
virtual ULONG __stdcall NondelegatingRelease() = 0;
};
///
//
// Component
// 组件类 CB
class CB : public IY,INondelegatingUnknown
// CB 类实现了 IY 和 INondelegatingUnknown 接口。
{
{
public:
// CB 类实现了 IY 和 INondelegatingUnknown 接口。
// 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
// NondelegatingQueryInterface、NondelegatingAddRef 和 NondelegatingRelease 是非委托的 IUnknown 实现,用于组件内部接口的管理。
virtual HRESULT __stdcall
NondelegatingQueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall NondelegatingAddRef();
virtual ULONG __stdcall NondelegatingRelease();
// Interface IY
// Fy() 是 IY 接口的方法实现,输出 Fy
virtual void __stdcall Fy() { cout << "Fy" << endl; }
// Constructor
CB(IUnknown* m_pUnknownOuter);
// Destructor
~CB();
private:
long m_cRef;
IUnknown* m_pUnknownOuter;
}
//
// IUnknown implementation
// IUnknown实现
// NondelegatingQueryInterface 实现了内部接口的查询,使用非委托的接口进行强制类型转换
HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown) {
// !!! CAST IS VERY IMPORTANT!!!
// 类型转换 它确保返回的是非委托的 IUnknown 实现,而不是被聚合时返回给外部组件的 IUnknown
// 强制转换确保返回的是内部组件自己的 INondelegatingUnknown 实现,而不是其他接口。
// 这是保证组件能够正确管理自身行为的关键步骤
*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;
}
// NondelegatingAddRef 和 NondelegatingRelease 实现了引用计数管理
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);
// pUnknownOuter 是一个指向外部 IUnknown 的指针,用于支持聚合。如果传入 NULL,说明该组件是非聚合的。
if (pUnknownOuter == NULL)
{
trace("Not aggregating: delegate to nondelegating IUnknown.不聚合:委托给非委托IUnknown。");
// 在组件没有聚合时,将 m_pUnknownOuter 设置为指向当前对象的非委托 IUnknown 实现。
m_pUnknownOuter = reinterpret_cast<IUnknown*>// 将其再转换为 IUnknown* 类型。尽管这两个类型都与 IUnknown 有关,二次转换是为了确保符合 IUnknown 的接口格式
(static_cast<INondelegatingUnknown*> // 将 this 指针(当前对象)转换为 INondelegatingUnknown* 类型,即非委托的 IUnknown。
(this));
}
// 在聚合模式下,组件将把所有的 IUnknown 方法(QueryInterface、AddRef、Release)委托给这个外部指针。
else {
trace("Aggregating: delegate to outer IUnknown.聚合:委托给外部IUnknown。");
m_pUnknownOuter = pUnknownOuter; // 将 m_pUnknownOuter 设置为传入的 pUnknownOuter,即指向外部 IUnknown 的指针。
}
}
//
// Destructor
// 析构函数减少组件计数,并输出销毁信息
CB::~CB()
{
InterlockedDecrement(&g_cComponents);
trace("Destroy self.");
}
///
//
// Class factory
// 类工厂 CFactory
// CFactory 类实现了 IClassFactory 接口,负责创建组件实例
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 接口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
// 实现了 IUnknown 接口,用于管理类工厂的生命周期
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
// IClassFactory 的实现
// CreateInstance 方法用于创建 CB 组件实例,并返回请求的接口。
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv)
{
// Aggregate only if the requested iid is IID_IUnknown.
// 仅当请求的iid为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
// LockServer 方法管理 DLL 的加载和卸载控制
HRESULT CFactory::LockServer(BOOL bLock)
{
if (bLock)
{
InterlockedIncrement(&g_cServerLocks);
}
else {
InterlockedDecrement(&g_cServerLocks);
}
return S_OK;
}
///
//
// Exported functions
// 输出功能
// 用于检查是否可以卸载 DLL。
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
// DLL 的入口点,设置模块句柄,处理 DLL 加载和卸载事件
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
void* lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
g_hModule = hModule;
}
return TRUE;
}
在第五章的动态链接过后吗,就正式进入了COM组件的学习,因个人原因,并未详对学习过程进行详细记录
COM技术内幕所有学习笔记暂时完结
这是github中有前辈整理的COM技术内幕项目源码