版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第二章 COM对象和接口,主要内容,COM对象的概念与特征 接口的定义与标识 接口的内存模型 接口的特点 IUknown接口 引用计数 接口查询 字典组件举例,COM基础三个概念,COM组件 组件:可独立发布的二进制组件 在Windows平台上表现为DLL或者EXE COM对象 通过COM接口提供服务 符合OO中对象的基本概念 COM接口 客户与对象之间的协议,对象实现COM接口,客户使用COM接口从而访问对象,需要思考的一些问题,COM组件 组件的类型:进程内组件(DLL)、进程外组件(EXE) 为方便起见,只讨论Windows平台上DLL类型的组件 COM对象 如何标识一个对象?对象以什么
2、形式存在?客户如何创建对象? 对象如何暴露接口?一个或是多个? COM接口 要求:跨编译器、跨语言、跨平台,2.1 COM对象,概念 COM对象是客户程序与组件程序进行交互的实体。 COM对象包含属性和方法(或者状态和操作): 属性反映对象的存在,也是区别于其他对象的要素; 方法是对象提供给外界的接口。 能够提供服务(通过COM接口) 对象的实现由组件完全包装起来,2.1.1 COM对象的标识CLSID,COM组件的位置透明性 客户程序并不直接访问COM对象,而是通过一个唯一的全局标识符进行对象的创建和初始化工作。 可选的标识符方案: 字符串形式:可读性好,名字冲突的可能性大 定长位数的整数:
3、如何保证唯一性?(管理组织 / 大随机数) GUID 是COM规范采取的方案 是一个128位的随机数 不绝对保证唯一性,但发生冲突的可能性非常小 例如: 54BF6567-1007-11D1-B0AA-444553540000 ,GUID续,GUID的C/C+结构描述 typedef struct _GUID DWORD Data1; WORD Data2; WORD Data3; BYTE Data48; GUID ; 保证随机性的考虑 空间上:网络中的计算机通常取网卡的地址(唯一的) 时间上:同一机器在不同时候产生的标识符总不相同,GUID (续),产生GUID的工具 Visual C+提
4、供的两个工具: UUIDGen.exe :命令行程序 GUIDGen.exe :基于对话框的程序 COM库提供的API函数 HRESULT CoCreateGuid ( GUID * pguid) ; GUID 与 CLSID CLSID是标识COM对象的GUID 二者在结构上完全一致,2.1.2 COM对象与C+对象的比较,层次差异 COM对象建立在二进制级的基础上 C+对象建立在源代码级的基础上 封装特性 COM对象的数据完全封装在对象内部,不能直接访问 C+对象的公有数据成员是可以访问的 可重用性 COM对象的重用表现为包容和聚合 C+对象的重用表现为继承与组合 多态性的表现形式不同 C
5、OM对象的多态需要通过接口来表现,2.2 COM接口,基本内容 接口定义与标识 用C+定义接口 IDL 接口的内存模型 接口的特点,2.2.2 接口定义和标识,定义 是一个函数集,以二进制的形式给出了从一方到另一方的调用规范;函数的地址封装在一个数据结构中。 这个数据结构称为“接口函数表” 在C+中称为“虚函数表”,简称vtable 对于一个接口来说,它的vtable是确定的,即: 接口成员函数的个数是不变的; 其先后顺序也是不变的 客户程序通过一个指向vtable的指针来调用接口成员函数,COM接口结构,COM接口举例(C语言),struct IDictionaryVtble; struct
6、 IDictionary IDictionaryVtble * pVtbl ; ; struct IDictionaryVtble BOOL ( * Initialize) (Idictionary * this); BOOL ( * LoadLibrary) (Idictionary * this, String); void ( * FreeLibrary) (Idictionary * this); ;,COM接口标识-IID,Interface Identifier 是GUID的一种用法 例如: extern “C” const IID IID_Iunkown = 0 x0000000
7、0, 0 x0000, 0 x0000 0 xc0, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x46 ; 如果客户程序要使用一个COM对象的某个接口,必须知道该接口的IID以及它能提供的方法。,2.2.3 用C+语言定义接口,COM接口结构中的vtable与class的vtable完全一致 因此,用class描述COM接口是最方便的手段 举例: class IDictionary virtual BOOL Initialize() = 0; virtual BOOL LoadLibrary(String) = 0; virtual void Fr
8、eeLibrary() = 0; ;,类IDictionary的内存结构,2.2.4 接口描述语言IDL,以OSF 的 IDL为基础 基本数据类型 与C语言非常接近,包括结构、联合、枚举、typedef等 interface coclass library 可以产生类型库,举例,interface IDictionary HRESULT Initialize(); HRESULT LoadLibrary(in string); HRESULT InsertWord(in string, in string); HRESULT DeleteWord(in string); HRESULT Loo
9、kupWord(in string, out string *); HRESULT RestoreLibrary(in string); HRESULT FreeLibrary(); ; VC+的MIDL可以由IDL文件生成C/C+接口描述,IDL的意义,IDL语言无关 跨语言的中间语言 MIDL.exe产生C+头文件定义 相当于C+定义 MIDL.exe产生TLB类型库 COM本身提供了一套基础设施来解释类型库 所有的标准接口都可以在SDK中找到IDL描述,编译IDL文件,2.2.5 接口的内存模型,如果我们用C+实现字典对象,则类定义为: class CDictionary : publi
10、c IDictionary public : CDictionary(); CDictionary(); public : virtual BOOL Initialize(); virtual BOOL LoadLibrary(String); / private : struct DictWord *m_pData; char *m_DictFilename128; / ;,接口和字典对象的内存结构图,多个字典对象与接口的内存结构图,不同方法实现的字典对象与接口关系,2.2.6 接口的特点,二进制特性 接口不变性 继承性(扩展性) 多态性运行过程中的多态性 (lecture over),2.
11、3 IUnkown 接口,所有的COM接口都必须从IUnknown派生,原因在于Iunknown接口提供了两个重要的特性: 生存期控制:通过“引用计数”来控制 接口查询:QueryInterface函数 Iunknown的IDL定义: Interface IUnknown HRESULT QueryInterface( in REFIID iid, out void * ppv ) ; ULONG AddRef( void ) ; ULONG Release( void ) ; ,2.3 IUnkown 接口(续),Iunknown的C+定义: class IUnknown public: v
12、irtual HRESULT _stdcall QueryInterface( const IID,2.3.1 引用计数,目的:是为了控制对象的生命周期 多个客户可以独立地控制对象的生存 引用计数反映了COM对象被客户引用的个数 引用计数是个整数,从0开始 两个操作:增 1 和 减 1 当客户得到一个指向对象的接口指针时,引用计数1; 当客户用完该接口指针时,引用计数1; 当引用计数为0时,表示没有客户在使用对象或者接口删除,2.3.2 实现引用计数,引用计数多实现方案的原因 一个COM组件可以实现多个COM对象 一个COM对象可以实现多个COM接口 组件级实现 ? 对象级实现 ? 接口级实现
13、? 实现方案比较(参见下页的图) 设置一个针对整个组件的全局引用计数 所有对象必须一起释放 计数分辨率太粗 为每个COM对象设置一个引用计数(折中方案) 为每个接口设置一个引用计数 客户不一定会用到对象的所有接口,造成资源浪费 计数分辨率太细,实现引用计数的层次(或粒度),重新定义IDictionary,class IDictionary : public IUnknown virtual BOOL Initialize() = 0; virtual BOOL LoadLibrary(String) = 0; virtual BOOL InsertWord(String, String) =
14、0; virtual void DeleteWord(String) = 0; virtual BOOL LookupWord(String, String *) = 0; virtual BOOL RestoreLibrary(String) = 0; virtual void FreeLibrary() = 0; ;,重新定义CDictionary,class CDictionary : public IDictionary public : CDictionary(); CDictionary(); public : virtual HRESULT QueryInterface(cons
15、t IID,部分实现代码,CDictionary:CDictionary () m_Ref = 0; / . initialize ULONG CDictionary:AddRef () m_Ref +; return (ULONG) m_Ref; ULONG CDictionary:Release () m_Ref -; return (ULONG) m_Ref; ,客户控制引用计数的基本规则,1、客户创建了组件对象并获得了第一个接口指针后,引用计数应该为1( 0+1 1) 2、在客户程序中,当把接口指针赋给其它变量时,应该调用AddRef,使引用计数增1; 3、在客户程序中,当一个接口指针
16、被用完之后,应该调用Release,使引用计数减1;,客户代码举例,IDictionary * pIDictionary = CreateObject(CLSID_Dictionary, IID_Dictionary); if( pIDictionary = NULL ) return; / reference count is 1 / load the dictionary BOOL retValue = pIDictionary-LoadLibrary(eng_ch.dict); if (retValue = FALSE) pIDictionary-Release(); return; .
17、 IDictionary *pIDictionaryForWord = pIDictionary; pIDictionaryForWord -AddRef(); / Insert or delete some word pIDictionaryForWord -InsertWord(.,.); pIDictionaryForWord -DeleteWord(.); pIDictionaryForWord -Release ( ); . / finally, release dictionary object pIDictionary-Release ( );,2.3.3 使用引用计数的规则,1
18、、函数参数中使用接口指针变量 输入参数:一般不用调用AddRef和Release 输出参数或返回一个接口指针变量: 相当于生成了一个新的接口指针接口指针, 因此,需要调用AddRef 输入输出参数 如果参数未被修改,则不用调用AddRef和Release;否则: 在参数被修改前,对传进来的原接口指针调用Release,在参数被修改之后,对新的接口指针调用AddRef。,2.3.3 使用引用计数的规则(续1),2、局部接口指针变量: 指的是用已有的值对局部变量赋值; 可以不调用AddRef和Release。 3、全局接口指针变量: 作为输入参数传给函数之前,调用AddRef 函数返回之后,调用R
19、elease 4、类成员变量 在类的作用域内,成员变量相当于全局变量,因此用R3.,2.3.3 使用引用计数的规则(续2),5、当以上情况都不合适时,采用下面的一般性规则: 在顺序执行过程中,如果要对一个接口指针变量赋值,则对赋值后的接口指针变量调用AddRef,并且,如果赋值前的接口指针变量还没有结束,则赋值前必须对它调用Release以便先结束它的使用。 如果要结束使用一个接口指针变量,以后不再用到它了,则调用Release函数。 尽量养成遵循规则的好习惯,以免出现错误。 在整个生存期内,AddRef与Release一定要配对,否则: 漏掉AddRef,程序出错 漏掉Release,对象永
20、不释放,2.3.3 使用引用计数的规则(续3),频繁调用AddRef和Release会降低程序运行效率 需要灵活运用,明显可以省略时要省略,比如: IDictionary * pIDictionaryForWord = pIDictionary; pIDictionaryForWord -AddRef(); / Insert or delete some word pIDictionaryForWord -InsertWord(.,.); pIDictionaryForWord -DeleteWord(.); pIDictionaryForWord -Release ( ); ,2.3.4 接
21、口查询,问题的提出 一个COM对象可以实现多个接口,客户程序可以在运行时刻对COM对象的接口进行询问,以确定其是否已经实现。但对象的多个接口之间如何联系起来呢? 通过IUnknown接口的QueryInterface函数解决。 QueryInterface函数的形式 HRESULT QueryInterface( in REFIID iid, out void * ppv ); 输入参数iid是欲查询接口的IID 输出参数ppv为查询得到的结果接口指针 如果对象没有实现iid所标识的接口,则ppv为空(NULL) 函数的返回值是一个32位的整数,含义为: S_OK,查到了指定的接口,接口指针放
22、在ppv中; E_NOINTERFACE,没有这个接口,ppv为NULL; E_UNEXPECTED,发生了意外, ppv为NULL。,客户程序如何调用QueryInterface?,假设字典组件除了实现了IUnknown接口外,还实现了IDictionary接口和ISpellCheck接口,则客户程序只要得到其中的一个接口指针,就可以得到另外任何一个接口指针。下面是具体的例子: /create a new dictionary object, and got the first interface pointer IDictionary * pIDictionary = CreateObje
23、ct(CLSID_Dictionary, IID_Dictionary); if( pIDictionary = NULL ) return; / reference count is 1 / load the dictionary retValue = pIDictionary-LoadLibrary(eng_ch.dict); if (retValue = FALSE) pIDictionary-Release(); return; .,调用QueryInterface(续),ISpellCheck *pISpellCheck; HRESULT result = pIDictionary-
24、QueryInterface(IID_SpellCheck, (void *) .,2.3.6 QueryInterface函数的实现,假设字典对象类CDictionary的定义如下: class CDictionary : public IDictionary , public ISpellCheck public : CDictionary(); CDictionary(); public : / IUnknown member function virtual HRESULT QueryInterface(const IID,CDictionary的定义(续),/ IDictionary member function virtual BOOL _stdcall Initialize(); virtu
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 踝泵运动技术规范团体标准试题及答案
- 2025年5G通信市场竞争态势演变可行性分析报告
- 五育并举演讲稿主题
- 2026年秋招:山西云时代技术公司试题及答案
- 劳动实践基地管理制度及措施 (一)
- 2026秋小学人教版数学四年级上册十月份月考练习卷附参考答案
- 支气管知识问答试题及答案
- 2027届四川省南充市高坪区江东初级中学数学七上期末经典试题含解析
- 植保基础复习试题及答案
- 学习内驱力:5个可操作步骤
- 2026中国安宁疗护服务需求增长与供给缺口测算分析报告
- 2026秋小学岭南版美术六年级上册(新教材)教学计划附教学进度表
- 小学一年级语文上册《天地人》单元整体教学教案
- 2026年电梯高级工特种作业考试题库(附含答案)
- 第2课 《中国人首次进入自己的空间站》课件(内嵌视频)2026-2027学年统编版语文八年级上册
- 2026年魁北克驾驶员考试试题及答案
- 初级焊工理论考试题及答案
- 2026年阿里云ACP云计算工程师认证考试真题题库
- S224颍上至赛涧段道路工程K6~K9初步设计
- 物业公司与理发店合同
- 2026年4月自考02323操作系统概论试题及答案含评分参考
评论
0/150
提交评论