(savetime 注:下面代码中 ppv 指针的应用,好像应该是 void **)
HRESULT CoCreateInstance(const CLSID& clsid, IUnknown *pUnknownOuter,
DWORD dwClsContext, const IID& iid, void *ppv)
{
IClassFactory *pCF;
HRESULT hr;
hr = CoGetClassObject(clsid, dwClsContext, NULL, IID_IClassFactory,
(void *) pCF);
if (FAILED(hr)) return hr;
hr = pCF->CreateInstance(pUnknownOuter, iid, (void *)ppv);
pFC->Release();
return hr;
}
从这段代码我们可以看出,CoCreateInstance 函数首先利用 CoGetClassObject 函数创建类厂对象,然后用得到的类厂对象的接口指针创建真正的 COM 对象,最后把类厂对象释放掉并返回,这样就把类厂屏蔽起来。
但是,用 CoCreateInstance 并不能创建远程机器上的对象,因为在调用 CoGetClassObject 时,把第三个用于指定服务器信息的参数设置为 NULL。如果要创建远程对象,可以使用 CoCreateInstance 的扩展函数 CoCreateInstanceEx:
HRESULT CoCreateInstanceEx(const CLSID& clsid, IUnknown *pUnknownOuter,
DWORD dwClsContext, COSERVERINFO *pServerInfo, DWORD dwCount,
MULTI_QI *rgMultiQI);
前三个参数与 CoCreateInstance 一样,pServerInfo 与 CoGetClassOjbect 的参数一样,用于指定服务器信息,最后两个参数 dwCount 和 rgMultiQI 指定了一个结构数组,可以用于保存多个对象接口指针,其目的在于一次获得多个接口指针,以便减少客户程序与组件程序之间的频繁交互,这对于网络环境下的远程对象是很有意义的。
-------------------------------------------------------------------------------
COM 库的初始化
-------------------------------------------------------------------------------
调用 COM 库的函数之前,为了使函数有效,必须调用 COM 库的初始化函数:
HRESULT CoInitialize(IMalloc *pMalloc);
pMalloc 用于指定一个内存分配器,可由应用程序指定内存分配原则。一般情况下,我们直接把参数设为 NULL,则 COM 库将使用缺省提供的内存分配器。
返回值:S_OK 表示初始化成功
S_FALSE 表示初始化成功,但这次调用不是本进程中首次调用初始化函数
S_UNEXPECTED 表示初始化过程中发生了错误,应用程序不能使用 COM 库
通常,一个进程对 COM 库只进行一次初始化,而且,在同一个模块单元中对 COM 库进行多次初始化并没有意义。唯一不需要初始化 COM 库的函数是获取 COM 库版本的函数:
DWORD CoBuildVersion();
返回值:高 16 位 主版本号
低 16 位 次版本号
COM 程序在用完 COM 库服务之后,通常是在程序退出之前,一定要调用终止 COM 库服务函数,以便释放 COM 库所维护的资源:
void CoUninitialize(void);
注意:凡是调用 CoInitialize 函数返回 S_OK 的进程或程序模块一定要有对应的 CoUninitialize 函数调用,以保证 COM 库有效地利用资源。
(? 如果在一个模块中调用 CoInitialize 返回 S_OK,那么它调用 CoUnitialize 函数后,其它也在使用 COM 库的模块是否会出错误?还是 COM 库会自动检查有哪些模块在使用?)
-------------------------------------------------------------------------------
COM 库的内存管理
-------------------------------------------------------------------------------
由于 COM 组件程序和客户程序是通过二进制级标准建立连接的,所以在 COM 应用程序中凡是涉及客户、COM 库和组件三者之间内存交互(分配和释放不在同一个模块中)的操作必须使用一致的内存管理器。COM 提供的内存管理标准,实际上是一个 IMalloc 接口:
// IID_IMalloc: {00000002-0000-0000-C000-000000000046}
class IMalloc: public IUnknown
{
void * Alloc(ULONG cb) = 0;
void * Realloc(void *pv, ULONG cb) = 0;
void Free(void *pv) = 0;
ULONG GetSize(void *pv) = 0; // 返回分配的内存大小
int DidAlloc(void *pv) = 0; // 确定内存指针是否由该内存管理器分配
void HeapMinimize() = 0; // 使堆内存尽可能减少,把没用到的内存还给
// 操作系统,用于性能优化
}
获得 IMalloc 接口指针:
HRESULT CoGetMalloc(DWORD dwMemContext, IMalloc **ppMalloc);
CoGetMalloc 函数的第一个参数 dwMemContext 用于指定内存管理器的类型。COM 库中包含两种内存管理器,一种就是在初始化时指定的内存管理器或者其内部缺省的管理器,也称为作业管理器(task allocator),这种管理器在本进程内有效,要获取该管理器,在 dwMemContext 参数中指定为 MEMCTX_TASK;另一种是跨进程的共享分配器,由 OLE 系统提供,要获取这种管理器,dwMemContext 参数中指定为 MEMCTX_SHARED,使用共享管理器的便利是,可以在一个进程内分配内存并传给第二个进程,在第二个进程内使用此内存甚至释放掉此内存。
只要函数的返回值为 S_OK,则 ppMalloc 就指向了 COM 库的内存管理器接口指针,可以使用它进行内存操作,使用完毕后,应该调用 Release 成员函数释放控制权。
COM 库封装了三个 API 函数,可用于内存分配和释放:
void * CoTaskMemAlloc(ULONG cb);
void CoTaskFree(void *pv);
void CoTaskMemRealloc(void *pv, ULONG cb);
这三个函数分配对应于 IMalloc 的三个成员函数:Alloc、Realloc 和 Free。
例:COM 程序如何从 CLSID 值找到相应的 ProgID 值:
WCHAR *pwProgID;
char pszProgID[128];
hResult = ::ProgIDFromCLSID(CLSID_Dictionary, &pwProgID);
if (hResult != S_OK) {
...
}
wcstombs(pszProgID, pwProgID, 128);
CoTaskMemFree(pwProgID); // 注意:必须释放内存
在调用 COM 函数 ProgIDFromCLSID 返回之后,因为 COM 库为输出变量 pwProgID 分配了内存空间,所以应用程序在用完 pwProgID 变量之后,一定要调用 CoTaskMemFree 函数释放内存。该例子说明了在 COM 库中分配内存,而在调用程序中释放内存的一种情况。COM 库中其他一些函数也有类似的特性,尤其是一些包含不定长度输出参数的函数。
上一页 1 2 3 4 5 6 下一页 |