Windows桌面应用程序(1-2-3-4th) 用COM创建一个对象

线程初始化COM库后,线程使用COM接口是安全的。要使用COM接口,程序首先创建一个实现该接口的对象实例。

通常,创建COM对象有两种方法:

  • 实现该对象的模块可能会提供专门用于创建该对象实例的功能。
  • 或者,COM提供一个名为CoCreateInstance的通用创建函数。

例如,从主题“ 什么是COM接口?”中获取假设的Shape对象。在那个例子中,Shape对象实现了一个名为IDrawable的接口。实现Shape对象的图形库可能会导出带有以下签名的函数。

// Not an actual Windows function. 
HRESULT CreateShape(IDrawable **ppShape);

给定这个函数,你可以创建一个新的Shape对象,如下所示。

IDrawable *pShape;
HRESULT hr=CreateShape(&pShape);
if(SUCCEEDED(hr)){
    // Use the Shape object.
}
else{
    // An error occurred.
}

所述ppShape参数的类型为指针到指针到IDrawable的。如果你之前没有看到过这种模式,双重指针可能会令人费解。

考虑CreateShape函数的要求。该函数必须将一个IDrawable指针返回给调用者。但函数的返回值已经用于错误/成功代码。因此,指针必须通过函数的参数返回。调用者将传递一个类型的变量IDrawable*给函数,函数将用一个新的IDrawable指针覆盖这个变量。在C ++中,函数只有两种方法来覆盖参数值:按引用传递或按地址传递。COM使用后者,通过地址。而指针的地址是一个指针指针,所以参数类型必须是IDrawable**。

以下是帮助可视化发生的图表。
这里写图片描述
显示双指针间接的图

所述CreateShape函数使用的地址pShape(&pShape)写入新的指针值到pShape

CoCreateInstance:创建对象的通用方法
CoCreateInstance的功能提供用于创建对象的通用机制。要理解CoCreateInstance,请记住两个COM对象可以实现相同的接口,并且一个对象可以实现两个或更多个接口。因此,创建对象的通用函数需要两条信息。

  • 要创建哪个对象。
  • 从对象中获取哪个接口。

但是当我们调用函数时,我们如何表示这些信息?在COM中,通过为对象或接口分配一个称为全局唯一标识符(GUID)的128位数来标识该对象或接口。GUID的生成方式使其具有独特性。GUID是解决如何在没有中央注册机构的情况下创建唯一标识符的问题的解决方案。GUID有时被称为通用唯一标识符(的UUID)。在COM之前,他们被用于DCE / RPC(分布式计算环境/远程过程调用)。存在几种用于创建新GUID的算法。并非所有这些算法都严格保证唯一性,但意外创建两次相同GUID值的概率非常小 - 实际上为零。GUID可以用来识别任何类型的实体,而不仅仅是对象和接口。但是,这是本模块中唯一涉及我们的用途。

例如,Shapes库可能会声明两个GUID常量:

extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable;

(您可以假设这些常量的实际128位数值是在别处定义的。)常量CLSID_Shape标识Shape对象,而常量IID_IDrawable标识IDrawable接口。前缀“CLSID”代表类标识符,而前缀IID代表接口标识符。这些是COM中的标准命名约定。

给定这些值,您将创建一个新的Shape实例,如下所示:

IDrawable *pShape;
hr=CoCreateInstance(CLSID_Shape,NULL,CLSCTX_INPROC_SERVER,IID_Drawable,reinterpret_cast<void**>(&pShape));
if(SUCCEEDED(hr)){
    // Use the Shape object.
}
else{
    // An error occurred.
}

CoCreateInstance的功能有五个参数。第一个和第四个参数是类标识符和接口标识符。实际上,这些参数告诉函数,“创建Shape对象,并给我一个指向IDrawable接口的指针。”

将第二个参数设置为NULL。(有关此参数含义的更多信息,请参阅COM文档中的聚合主题。)第三个参数采用一组标志,其主要用途是指定对象的执行上下文。执行上下文指定对象是否在与应用程序相同的进程中运行; 在同一台计算机上的不同进程中; 或在远程计算机上。下表显示了此参数的最常用值。

描述
CLSCTX_INPROC_SERVER 同样的过程。
CLSCTX_LOCAL_SERVER 不同的过程,同一台电脑。
CLSCTX_REMOTE_SERVER 不同的电脑。
CLSCTX_ALL 使用对象支持的最有效的选项。(从最有效到最不高效的排名是:进程中,进程外和跨计算机。)

特定组件的文档可能会告诉您该对象支持哪个执行上下文。如果不是,请使用CLSCTX_ALL。如果您请求该对象不支持的执行上下文,则 CoCreateInstance函数将返回错误代码REGDB_E_CLASSNOTREG。此错误代码还可能表示CLSID与用户计算机上注册的任何组件不符。

CoCreateInstance的第五个参数收到一个指向接口的指针。由于CoCreateInstance是一种通用机制,因此无法强制键入此参数。相反,数据类型是void **,调用者必须强制指向void **类型的指针地址。这是前面例子中reinterpret_cast的目的。

检查CoCreateInstance的返回值至关重要。如果该函数返回一个错误代码,则COM接口指针无效,并试图对其进行解引用可能导致程序崩溃。

在内部,CoCreateInstance函数使用各种技术来创建一个对象。在最简单的情况下,它在注册表中查找类标识符。注册表项指向实现该对象的DLL或EXE。CoCreateInstance还可以使用来自COM +目录或并行(SxS)清单的信息。无论如何,细节对于调用者来说都是透明的。有关CoCreateInstance的内部详细信息的更多信息,请参阅COM客户端和服务器

我们一直在使用的Shapes示例有点人为,所以现在我们来看一个实际COM示例:显示打开对话框供用户选择文件。

下一个
例如:打开对话框

猜你喜欢

转载自blog.csdn.net/qq_37422196/article/details/79763907