第七章:类场【代码】

客户程序清单

在本章的示例代码中我们将创建我们的第一个纯COM客户和组件。程序清单7-1给出了客户的代码。此客户同第5章中给出的客户的真正的差别在于客户创建组件时使用的是CoCreateInstance。另外它还使用了Colnitialize 和CoUninitialize 来初始化COM库(请参阅第6章)。

// Client.cpp - client implementation Client. cpp-客户端实现

#include <iostream>
#include <objbase.h>
#include "Iface.h"
using namespace std;

//定义一个 trace 函数,用于打印调试信息,便于跟踪程序执行流程。
void trace(const char* msg)
{
	cout << "Client; \t\t" << msg << endl;
}
// main function 主函数

int main()
{
	// Initialize COM Library 初始化COM库
	CoInitialize(NULL);//调用 CoInitialize(NULL) 初始化 COM 库,使程序能够使用 COM 功能。
	trace("Call CoCreateInstance to create 调用CoCreateInstance创建");
	trace(" component and get interface IX.组件并获取接口IX。");
	IX* pIX = NULL;//定义一个 IX 接口指针 pIX 并初始化为空
	//调用 CoCreateInstance 创建 CLSID_Component1 对象实例,并请求 IX 接口
	HRESULT hr = ::CoCreateInstance(CLSID_Component1, //组件的类 ID
								NULL, //不需要聚合
								CLSCTX_INPROC_SERVER,//指定服务器在本地进程内运行
								IID_IX,//请求的接口 ID
								(void**)&pIx);//接口指针的输出位置
	//检查 CoCreateInstance 是否成功创建了组件并获得 IX 接口。如果成功,打印获取成功的信息
	if (SUCCEEDED(hr))
	{
		trace("Succeeded getting IX.成功获得IX。");
		pIX->Fx();		// Use interface IX. 使用接口IX。
		trace("Ask for interface IY.询问接口IY。");
		IY * pIY = NULL;
		hr = pIX->QueryInterface(IID_IY, (void**)&pIY);//请求由 IX 接口指针 pIX 获取 IY 接口
		if (SUCCEEDED(hr))//如果成功,调用 IY 接口的 Fy 方法,然后释放 IY 接口指针
		{
			trace("Succeeded getting IY.成功得到IY。");
			pIY->Fy();		// Use interface IY.使用接口IY。
			pIY->Release();
			trace("Release IY interface.释放IY接口。");
		}
		else//如果获取 IY 接口失败,则打印无法获得接口的错误信息。
		{
			trace("Could not get interface IY.无法获得接口IY。");
		}
		trace("Ask for interface IZ.询问接口IZ。");
		IZ* pIZ = NULL;
		hr = pIX->QueryInterface(IID_IZ, (void**)&pIZ);//请求 IX 接口指针 pIX 获取 IZ 接口
		if (SUCCEEDED(hr))//如果成功,调用 IZ 接口的 Fz 方法,然后释放 IZ 接口指针。
		{
			trace("Succeeded in getting interface IZ.成功获取接口IZ。");
			pIZ->FzQ;
			pIZ->Release();
			trace("Release IZ interface.发布IZ接口。");
		}
		else//如果获取 IZ 接口失败,则打印错误信息
		{
			trace("Could not get interface IZ.无法获取接口IZ。");
		}
		trace("Release IX interface.发布IX接口。");
		pIX->Release();//释放 IX 接口
	}
	else
	{
		cout << "Client: \t itCould not create component. hr = 客户端:\t它无法创建组件。hr= "
			<< hex << hr << endl;
	}
	// Uninitialize COM Library 取消初始化COM库,释放在初始化期间分配的所有资源,程序结束
	CoUninitialize(:
	return 0
}

组件代码清单

在程序清单7-2中实现了组件即相应的类厂。这个类厂实际上是由C++类CFactory实现的。关于CFactory,需要说明的第一点是,它只不过是另外一个组件而已,例如它也按与其他组件相同的方式实现了IUnknown接口。CFactory和CA的唯一区别在于它们所支持的接口的不同。
在读者阅读此程序清单时,请特别注意CFactory :: Createlnstance和DIlGetClassObject的实现。

//程序清单7-2 组件、类厂及DLL所输出函数的完整代码。
// cmpnt.cpp
#include <iostream>
#include <objbase.h>
#include "Iface.h"		// Interface declarations 接口声明
#include "Regiatry.h"	// Registry helper functions 注册表辅助函数
using namespace std;
// Trace function Trace函数 定义了 trace 函数,用于输出调试信息
void trace(const char* msg)
{
	cout << msg << endl;
}

// Global variables 全局变量
//包括 DLL 模块句柄、当前活动组件的计数和服务器锁的计数
static HMODULE g_hModule = NULL;	// DLL module handle DLL模块句柄
static long g_cComponents = 0;		// Count of active components 有效元件计数
static long g_cservertocks = 0;		// Count of locks 锁的数量
// Friendly name of component 组件的友好名称
const char g_szFriendlyName[] = "Inside COM: Chapter 7 Example.";

// Version independent ProgID 版本无关的ProgID
const char g_szVerIndProgID[] = "InsidCOM.Chap07";

// ProgID 具体的ProgID
const char g_szProgID[] = "InsideCOM.chap07.1";

/
//
// Component
//
class CA : public IX,
           public IY
{
public:
    // IUnknown 实现了 IUnknown 的三个方法 QueryInterface、AddRef 和 Release
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();

	// 实现了接口 IX 和 IY 的方法 Fx 和 Fy,分别输出 "Fx" 和 "Fy"
    // Interface IX
    virtual void __stdcall IX() { cout << "Fx" << endl; } 
    // Interface IY
    virtual void __stdcall IY() { cout << "Fy" << endl; }

    // Constructor
    CA();

    // Destructor
    ~CA();

private:
    // Reference count
    long m_cRef;
}

// Constructor
//构造函数初始化引用计数为 1,并增加全局组件计数。
CA::CA() : m_cRef(1)
{
    InterlockedIncrement(&g_cComponents);
}

// Destructor
//析构函数减少全局组件计数,并打印销毁信息。
CA::~CA()
{
    InterlockedDecrement(&g_cCompoents);
    trace("Component:\t\tDestroy self.组件:\t\t自我销毁");
}

// IUnknown implementaion IUnknown实现
// QueryInterface用于根据iid获取相应的接口指针。
// 如果匹配ID_IUnknown、IID_IX或IID_IY,则返回相应的接口指针并增加引用计数
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);
        trace("Component:\t\tReturn pointer to IX.");
    }
    else if (iid == IID_IY) {
        *ppv = static_cast<IY*>(this);
        trace("Component:\t\tReturn pointer to IY.");
    }
    // 如果接口不匹配,则返回 E_NOINTERFACE
    else 
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef();
    return S_OK;
}

// AddRef 方法增加引用计数
ULONG __stdcall CA::AddRef()
{
    return InterlockedIncrement(&m_cRef);
}

//Release 方法减少引用计数,当计数为 0 时,删除对象并返回 0
ULONG __stdcall CA::Release()
{
    if (InterlockedDecrement(&m_cRef) == 0) {
        delete this;
        return 0;
    }
    return m_cRef;
}

/
// Class factory
// 定义类工厂 CFactory,实现了 IClassFactory 接口,负责创建组件实例
class CFactory : public IClassFactory
{
public:
    // IUnknown 实现了 IUnknown 的三个方法 QueryInterface、AddRef 和 Release
    virtual HRESULT __stdcall QueryInstance(const IID& iid, void** ppv);
    virtual ULONG   __stdcall AddRef();
    virtual ULONG   __stdcall Release();

    // Interface IClassFactory 接口IClassFactory
    // 实现类工厂接口的 CreateInstance 和 LockServer 方法
    virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
                                             const IID& iid,
                                             void** ppv);
    virtual HRESULT __stdcall LockServer(BOOL bLock);

    // Constructor
    CFactory() : m_cRef(1) {}

    // Destructor
    ~CFactory() { trace("Class factory:\t\tDestroy self."); }

private:
    long m_cRef;    
}

// Class factory IUnknown implementation 类场IUnknown的实现
// QueryInterface 根据 iid 返回相应的接口指针并增加引用计数
HRESULT __stdcall 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 InterlockedIncrement(&m_cRef);
}

ULONG __stdcall CFactory::Release()
{
    if (InterlockedDecrement(&m_cRef) == 0) {
        delete this;
        return 0;
    }
    return m_cRef;
}

// 
// IClassFactory implementation IClassFactory的实现
// CreateInstance 创建一个新的 CA 组件实例,并调用 QueryInterface 获取请求的接口
// 如果创建失败或接口请求失败,组件会自动删除自己
HRESULT __stdcall CFactory::CreateInstance(IUknown* pUnknownOuter,
                                           const IID& iid,
                                           void** ppv)
{
    trace("Class factory:\t\tCreate component.类厂:\t\t创建组件。");
    
    // Cannot aggregate.
    if (pUnknownOuter != NULL) 
    {
        return CLASS_E_NOAGGREGATION;
    }

    // Create component. 创建元件
    CA* pA = new CA;
    if (pA == NULL) 
    {
        return E_NOINTERFACE;
    }

    // Get the requested interface. 获取所请求的接口
    HRESULT hr = pA->QueryInterface(iid, ppv);

    // Release the IUnknown pointer. 释放IUnknown指针
    // (If QueryInterface failed, component will delete itself.)
    // (如果QueryInterface失败,组件将删除自身。)
    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
//
// 
// Can DLL unload now? 现在可以卸载DLL了吗?
//DllCanUnloadNow 判断 DLL 是否可以卸载,当没有活动组件和服务器锁时返回 S_OK,否则返回 S_FALSE
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)
{
    trace("DllGetClassObject:\t Create class factory. DllGetClassObject:\t 创建类厂。");

    // Can we create this component?我们可以创建这个组件吗?
    // 检查请求的类ID (CLSID) 是否与 CLSID_Component 匹配,如果不匹配,则返回 CLASS_E_CLASSNOTAVAILABLE
    if (clsid != CLSID_Component) {
        return CLASS_E_CLASSNOTAVAILABLE;// 如果请求的CLSID不匹配,则返回CLASS_E_CLASSNOTAVAILABLE,表示无法创建该类。
    }

    // Create class factory. 创建类厂。
    // 创建一个类工厂对象 CFactory。new CFactory 创建一个新的类工厂实例,但并未在构造函数中增加引用计数
    // 如果内存分配失败,返回 E_OUTOFMEMORY 错误
    CFacotry* pFactory = new CFactory;      // No AddRef in constructor 构造函数中没有AddRef
    if (pFactory == NULL) {
        return E_OUTOFMEMORY;// 如果无法创建类工厂(例如内存不足),返回E_OUTOFMEMORY
    }

    // Get requested interface.获取请求的接口
    HRESULT hr = pFactory->QueryInstance(iid, ppv);
    pFactory->Release();

	// 将 QueryInstance 的结果作为函数返回值。如果接口查询成功,则返回 S_OK,否则返回相应的错误代码
    return hr;
}

//
// Server registration 服务器注册
// llRegisterServer 函数用于注册 COM 服务器。在注册过程中,它会将组件的信息写入 Windows 注册表。
// RegisterServer 是一个辅助函数,用于相关信息注册到系统中
STDAPI DllRegisterServer()
{
    return RegisterServer(g_hModule,// DLL模块句柄
                          CLSID_Component1,// CLSID组件
                          g_szFriendlyName,// 友好名称
                          g_szVerIndProgID,// 版本无关的 ProgID
                          g_szProgID);// ProgID
}

// 
// Server unregistration
// DllUnregisterServer 函数用于注销 COM 服务器。它会从 Windows 注册表中删除与该组件相关的所有信息。
// UnregisterServer 是一个辅助函数,用于移除组件的相关信息。
STDAPI DllUnregisterServer()
{
    return UnregisterServer(CLSID.Component1,
                            g_szVerIndProgID,
                            g_szProgID);
}

/
//
// DLL module information DLL模块信息
// DllMain 是 DLL 的入口点函数,每当 DLL 被加载、卸载或线程附加/分离时都会被调用
BOOL APIENTRY DllMain(HANDLE hModule,// DLL 的句柄
                      DWORD dwReason,// 指示调用 DllMain 的原因
                      				 // 如 DLL_PROCESS_ATTACH (进程附加)、DLL_PROCESS_DETACH (进程分离) 等
                      void * lpReserved)// 保留参数,不使用
{
	// 在 DLL_PROCESS_ATTACH 情况下,保存模块句柄 hModule 到全局变量 g_hModule 中,用于后续注册时使用。
	// DllMain 返回 TRUE,表示成功处理加载事件
    if (dwReason == DLL_PROCESS_ATTACH) // 进程附加
    {
        g_hModule = hModule;
    }
    return TRUE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值