《COM组件技术积累》由会员分享,可在线阅读,更多相关《COM组件技术积累(43页珍藏版)》请在金锄头文库上搜索。
1、第 1 章 COM 基本概念1.1 什么是 COM所谓 COM(Componet Object Model,组件对象模型) ,是一种说明如何建立可动态互变组件的规范,此规范提供了为保证能够互操作,客户和组件应遵循的一些二进制和网络标准。通过这种标准将可以在任意两个组件之间进行通信而不用考虑其所处的操作环境是否相同、使用的开发者语言是否一致以及是否运行于同一台计算机。COM 规范所描述的即是如何编写组件,遵循 COM 标准的任何一个组件都是可以被用来组合成应用程序的。至于对组件采取的是何种编程语言则是无关紧要的,可以自由选取。作为一个真正意义上的组件,应具备如下特征:1) 实现对开发语言的封装。
2、2) 以二进制形式发布。3) 能够在不妨碍已有用户的情况下被升级。4) 在网络上的位置必须能够被透明的重新分配。在 Windows 操作系统平台上,有一些用 COM 形式提供的组件模块极大地丰富了Windows 的功能,而且也使 Windows 功能扩展更加灵活,例如:1) DiretX 多媒体软件包。它以 COM 接口的形式为 Windows 平台提供了强大的多媒体功能,现广泛用于游戏娱乐软件及其他多媒体软件的开发。2) RDO(remote data objet,远程数据对象)和 DAO(data access object,数据访问对象)数据库访问对象库。它以 COM 自动化对象的形式为
3、数据库应用提供了便捷的操作方法,特别适合于在 BASIC 语言或其他一些高级语言中使用。而数据访问一致接口 OLE DB/ADO(active data object,活动数据对象)更淋漓尽致地发挥了COM 接口的作用。3) Internet Client SDK。它提供了一组 COM 库,为应用系统增加 Internet 特性提供了底层透明的一致操作。其它还有一些组件如 MAPI(messaging API,消息应用编程接口) 、ADSI(active directory service interface,活动目录服务接口)等,它们都提供了一致、高效的服务。从整个Windows 操作系统来
4、看,COM 成了系统的基本软件模型,它带来的是灵活性和高效率,以及应用开发的一致性。1.2 COM 对象与 C+对象比较COM 对象建立在二进制一级的基础上,而 C+对象建立在源代码一级的基础上,但从特性上,可以作一比较。1) 封装性:COM 对象的数据成员的封装以组件模型为最终边界,对于用户是完全透明的、不可见的;而 C+对象的封装特性只是语义上的封装,对于对象用户是可见的。2) 可重用性COM 对象的可重用性表现在 COM 对象的包容和聚合,一个对象可以完全使用另一个另一个对象的所有功能;而 C+对象的可重用表现在 C+类的继承性,派生类可以调用其父类的非私有成员函数。3) 多态性C+对象
5、的多态性体现了 C+语言用类描述事物的高度抽象的特征;COM 对象也具有多态性,但这种多态性需要通过 COM 对象所具有的接口才能体现出来,就像 C+对象的多态性需要通过其虚函数才能体现一样。1.3 COM 对象和接口COM 提供的是面向对象的组件模型,COM 组件提供给客户的是以对象形式封装起来的实体。客户程序和 COM 组件程序进行交互的实体是 COM 对象。COM 对象包括属性(也称为状态)和方法(也称为操作) ,对象的状态反映了对象的存在,也是区别于其他对象的要素;而对象所提供的方法就是对象提供给外界的接口,客户必须通过接口才能获得对象的服务。对于 COM 对象来说,接口是它与外界进行
6、交互的唯一途径,因此,封装特性是 COM 对象的基本特征。1.3.1 COM 对象标识CLSIDCOM 组件的位置对于客户来说是透明的,因为客户并不直接去访问 COM 组件,客户程序通过一个全局标识符进行对象的创建和初始化工作,这个全局标识符就是CLSID。CLSID 结构定义上与 GUID 一致。COM 规范采用了 128 位全局唯一标示符 GUID。这是一个随机数。手工创建 128 位GUID 或者编写程序来产生 GUID 是件很麻烦的事。为此,Microsoft Visual C+提供了两个工具实现这样的目的:UUIDGen.exe 和 GUIDGen.exe,前者是一个命令行程序,后者
7、是一个基于对话框的应用程序。另外,COM 库为我们提供了以下 API 函数可以产生 GUID:HRESULT CoCreateGuid(GUID *pguid)下面为示例工程中.rgs 文件中 CLSID 的定义:Math.Obj.1 = s MyMath ClassCLSID = s 3B28F0D6-D029-484B-80D7-A946EB20E9BD将示例工程的 COM 组件成功注册后,我们可以根据组件的 CLSID 在系统的注册表编辑器中找到组件的注册信息,如图 1。图 1 系统注册表1.3.2 COM 对象的数据类型 HRESULT:一个双字节的值,其最高位(bit )如果是 0
8、表示成功,1 表示错误。常见的 HRESULT 值:HRESULT 值 含义S_OK 0x00000000 成功S_FALSE 0x00000001 函数成功执行完成,但返回时出现错误E_INVALIDARG 0x80070057 参数有错误E_OUTOFMEMORY0x8007000E 内存申请错误E_UNEXPECTED 0x8000FFFF 未知的异常E_NOTIMPL 0x80004001 未实现功能E_FAIL 0x80004005 没有详细说明的错误E_POINTER 0x80004003 无效的指针E_HANDLE 0x80070006 无效的句柄E_ABORT 0x800040
9、04 终止操作E_ACCESSDENIED 0x80070005 访问被拒绝E_NOINTERFACE 0x80004002 不支持接口 UNICODE:IDL 字符串的标准形式,使用 2 个字节表示一个字符(unsigned short int、WCHAR、 _wchar_t、OLECHAR ) ,不会出现乱码,UNICODE 的范围是 0x0000-0xFFFF 共 6 万多个字符。 BSTR:一个 OLECHAR*类型的 Unicode 字符串。由于操作系统提供相应的 API 函数(如SysAllocString)来管理它以及一些默认的调度代码,因此 BSTR 实际上就是一个 COM字符
10、串,自带字符串长度信息。API 函数 函数作用SysAllocString() 申请一个 BSTR 指针,并初始化为一个字符串SysFreeString() 释放 BSTR 内存SysAllocStringLen() 申请一个指定字符长度的 BSTR 指针,并初始化为一个字符串SysAllocStringByteLen()申请一个指定字节长度的 BSTR 指针,并初始化为一个字符串SysReAllocStringLen() 重新申请 BSTR 指针CString 函数 函数作用AllocSysString() 从 CString 得到 BSTRSetSysString() 重新申请 BSTR
11、指针,并复制到 CString 中CComBSTR 函数ATL 的 BSTR 包装类,在 atlbase.h 中定义,具体查看 MSDN_bstr_tC+对 BSTR 的封装,它的构造和析构函数分别调用 SysAllocString 和 SysFreeString 函数,其他操作是借用 BSTR API 函数。 VARIANT:具有跨语言的特性,它可以表示(存储)任意类型的数据,既包括了数据本身,也包含了数据的类型,定义在 oaidl.h 中。struct tagVARIANTVARTYPE vt;Unionshort iVal; /VT_I2long lVal; /VT_I4float fl
12、tVal; /VT_R4 double dblVal; /VT_R8DATE date; /VT_DATEBSTR bstrVal; /VT_BSTR.short* piVal; /VT_BYREF|VT_I2long* plVal; /VT_BYREF|VT_I4float* pfltVal; /VT_BYREF|VT_R4double* pdbVal; /VT_BYREF|VT_R8DATE* pdate; /VT_BYREF|VT_DATEBSTR* pbstrVal; /VT_BYREF|VT_BSTR;typedef tagVARIANT VARIANT;VARIANT 使用示例:
13、VARIANT va;:VariantInit( /初始化Int a = 2012; Va.vt = VT_I4; /指明 long 数据类型Va.IVal = a; /赋值:VariantClear();Windows 定义的 VARIANT 相关函数:VariantInt 将变量初始化为 VT_EMPTY;VariantClear 消除并初始化 VARIANT;VariantChangeType 改变 VARIANT 的类型;VariantCopy 释放与目标 VARIANT 相连的内存并赋值源 VARIANTCOleVariant:对 VARIANT 结构的封装COleVariant v
14、1(“This is a test ”); /直接构造COleVariant v2 = “This is a test”; /结果时 VT_BSTR 类型,值为”This is a test”COleVariant v3(long)2012);COleVariant v4 = (long)2012; /结果时 VT_I4 类型,值为 2012_variant_t: 用于 COM 的 VARIANT 类1.4 描述性语言 IDL 和 MIDL 编译器COM 规范在采用 OSF 的 DCE 规范描述远程调用接口 IDL( interface description language,接口描述语言)
15、的基础上,进行扩展形成了 COM 接口的描述语言。接口描述语言提供了一种不依赖于任何语言的接口描述方法,因此,它可以成为组件程序和客户端程序之间的共同语言。COM 规范使用的 IDL 接口描述语言不仅可用于定义 COM 接口,同时还定义了一些常用的数据类型,也可以描述自定义的数据结构,对于接口成员函数,我们可以指定每个参数的类型、输入输出特性,甚至支持可变长度的数组的描述。IDL 中所有数据、方法、接口、类和库的特性都由属性信息来描述。属性信息中由括号括起来,作为它们描述的对象的前缀。1) in: 输入型参数,从调用者传递到被调用者,被调用者对输入型参数的更改不传回调用者。2) out: 输出型参数,从被调用者返回调用者,而被调用者不关心参数的初始值。3) In,out: 输入输出型参数在调用的时候传到被调用者,同时,被调用者可以对参数进行修改,这个修改在调用返回的时候会被复制回调用者。 (PS:非指针类型一定是输入型参数。输出型参数和输入输出型参数一定是指针类型)4) retval: 返回一个与方法的物理 HRESULT 不相关的逻辑结果,与 out 一起使用,且只能有一个,放在参数的最后