GUID 在 C/C++ 中可以用这样的结构来描述:
typedef struct _GUID
{
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
} GUID;
例:{64BF4372-1007-B0AA-444553540000} 可以如下定义一个 GUID:
extern "C" const GUID CLSID_MYSPELLCHECKER =
{ 0x54BF0093, 0x1048, 0x399D,
{ 0xB0, 0xA3, 0x45, 0x33, 0x43, 0x90, 0x47, 0x47} };
Visual C++ 提供了两个程序生成 GUID: UUIDGen.exe(命令行) 和 GUIDGen.exe(对话框)。COM 库提供了以下 API 函数可以产生 GUID:
HRESULT CoCreateGuid(GUID *pguid);
如果创建 GUID 成功,则函数返回 S_OK,并且 pguid 将指向所得的 GUID 值。
-------------------------------------------------------------------------------
COM 对象
-------------------------------------------------------------------------------
在 COM 规范中,并没有对 COM 对象进行严格的定义,但 COM 提供的是面向对象的组件模型,COM 组件提供给客户的是以对象形式封装起来的实体。客户程序与 COM 程序进行交互的实体是 COM 对象,它并不关心组件模型的名称和位置(即位置透明性),但它必须知道自己在与哪个 COM 对象进行交互。
-------------------------------------------------------------------------------
COM 接口
-------------------------------------------------------------------------------
从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,客户代码可以调用组件对象的功能。接口定义了一组成员函数,这组成员函数是组件对象暴露出来的所有信息,客户程序利用这些函数获得组件对象的服务。
通常我们把接口函数表称为虚函数表(vtable),指向 vtable 的指针为 pVtable。对于一个接口来说,它的虚函数表是确定的,因此接口的成员函数个数是不变的,而且成员函数的先后先后顺序也是不变的;对于每个成员函数来说,其参数和返回值也是确定的。在一个接口的定义中,所有这些信息都必须在二进制一级确定,不管什么语言,只要能支持这样的内存结构描述,就可以使用接口。
接口指针 ----> pVtable ----> 指针函数1 -> |----------|
m_Data1 指针函数2 -> | 对象实现 |
m_Data2 指针函数3 -> |----------|
每一个接口成员函数的第一个参数为指向对象实例的指针(=this),这是因为接口本身并不独立使用,它必须存在于某个 COM 对象上,因此该指针可以提供对象实例的属性信息,在被调用时,接口可以知道是对哪个 COM 对象在进行操作。
在接口成员函数中,字符串变量必须用 Unicode 字符指针,COM 规范要求使用 Unicode 字符,而且 COM 库中提供的 COM API 函数也使用 Unicode 字符。所以如果在组件程序内部使用到了 ANSI 字符的话,则应该进行两种字符表达的转换。当然,在即建立组件程序又建立客户程序的情况下,可以使用自己定义的参数类型,只要它们与 COM 所能识别的参数类型兼容。
Visual C++ 提供两种字符串的转换:
namespace _com_util {
BSTR ConvertStringToBSTR(const char *pSrc) throw(_com_error);
BSTR ConvertBSTRToString(BSTR pSrc) throw(_com_error);
}
BSTR 是双字节宽度字符串,它是最常用的自动化数据类型。
-------------------------------------------------------------------------------
接口描述语言 IDL
-------------------------------------------------------------------------------
COM 规范在采用 OSF 的 DCE 规范描述远程调用接口 IDL (interface description language,接口描述语言)的基础上,进行扩展形成了 COM 接口的描述语言。接口描述语言提供了一种不依赖于任何语言的接口的描述方法,因此,它可以成为组件程序和客户程序之间的共同语言。
COM 规范使用的 IDL 接口描述语言不仅可用于定义 COM 接口,同时还定义了一些常用的数据类型,也可以描述自定义的数据结构,对于接口成员函数,我们可以定义每个参数的类型、输入输出特性,甚至支持可变长度的数组的描述。IDL 支持指针类型,与 C/C++ 很类似。例如:
interface IDictionary
{
HRESULT Initialize()
HRESULT LoadLibrary([in] string);
HRESULT InsertWord([in] string, [in] string);
HRESULT DeleteWord([in] string);
HRESULT LookupWord([in] string, [out] string *);
HRESULT RestoreLibrary([in] string);
HRESULT FreeLibrary();
}
Microsoft Visual C++ 提供了 MIDL 工具,可以把 IDL 接口描述文件编译成 C/C++ 兼容的接口描述头文件(.h)。
-------------------------------------------------------------------------------
IUnknown 接口
-------------------------------------------------------------------------------
IUnknown 的 IDL 定义:
interface IUnknown
{
HRESULT QueryInterface([in] REFIID iid, [out] void **ppv);
ULONG AddRef(void);
ULONG Release(void);
}
IUnkown 的 C++ 定义:
class IUnknown
{
virutal HRESULT _stdcall QueryInterface(const IID& iid, void **ppv) = 0;
virtual ULONG _stdcall AddRef() = 0;
virutal ULONG _stdcall Release() = 0;
}
-------------------------------------------------------------------------------
COM 对象的接口原则
-------------------------------------------------------------------------------
COM 规范对 QueryInterface 函数设置了以下规则:
1. 对于同一个对象的不同接口指针,查询得到的 IUnknown 接口必须完全相同。也就是说,每个对象的 IUnknown 接口指针是唯一的。因此,对两个接口指针,我们可以通过判断其查询到的 IUnknown 接口是否相等来判断它们是否指向同一个对象。
2. 接口自反性。对一个接口查询其自身总应该成功,比如:
pIDictionary->QueryInterface(IID_Dictionary, ...) 应该返回 S_OK。
上一页 1 2 3 4 5 6 下一页 |