COM对象与接口PPT课件_第1页
COM对象与接口PPT课件_第2页
COM对象与接口PPT课件_第3页
COM对象与接口PPT课件_第4页
COM对象与接口PPT课件_第5页
已阅读5页,还剩45页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第二章第二章 COM对象和接口对象和接口第1页/共50页主要内容主要内容 COM对象的概念与特征 接口的定义与标识 接口的内存模型 接口的特点 IUknown接口 引用计数 接口查询 字典组件举例第2页/共50页COM基础基础三个概念三个概念 COM组件 组件:可独立发布的二进制组件 在Windows平台上表现为DLL或者EXE COM对象 通过COM接口提供服务 符合OO中对象的基本概念 COM接口 客户与对象之间的协议,对象实现COM接口,客户使用COM接口从而访问对象第3页/共50页需要思考的一些问题需要思考的一些问题 COM组件 组件的类型:进程内组件(DLL)、进程外组件(EXE)

2、为方便起见,只讨论Windows平台上DLL类型的组件 COM对象 如何标识一个对象?对象以什么形式存在?客户如何创建对象? 对象如何暴露接口?一个或是多个? COM接口 要求:跨编译器、跨语言、跨平台第4页/共50页2.1 COM对象对象 概念 COM对象是客户程序与组件程序进行交互的实体。 COM对象包含属性和方法(或者状态和操作): 属性反映对象的存在,也是区别于其他对象的要素; 方法是对象提供给外界的接口。 能够提供服务(通过COM接口) 对象的实现由组件完全包装起来第5页/共50页2.1.1 COM对象的标识对象的标识CLSID COM组件的位置透明性 客户程序并不直接访问COM对象

3、,而是通过一个唯一的全局标识符进行对象的创建和初始化工作。 可选的标识符方案: 字符串形式:可读性好,名字冲突的可能性大 定长位数的整数:如何保证唯一性?(管理组织 / 大随机数) GUID 是COM规范采取的方案 是一个128位的随机数 不绝对保证唯一性,但发生冲突的可能性非常小 例如: 54BF6567-1007-11D1-B0AA-444553540000 第6页/共50页GUID续续 GUID的C/C+结构描述typedef struct _GUID DWORD Data1; WORD Data2; WORD Data3; BYTE Data48; GUID ; 保证随机性的考虑 空间

4、上:网络中的计算机通常取网卡的地址(唯一的) 时间上:同一机器在不同时候产生的标识符总不相同第7页/共50页GUID (续)续) 产生GUID的工具 Visual C+提供的两个工具: UUIDGen.exe :命令行程序 GUIDGen.exe :基于对话框的程序 COM库提供的API函数 HRESULT CoCreateGuid ( GUID * pguid) ; GUID 与 CLSID CLSID是标识COM对象的GUID 二者在结构上完全一致第8页/共50页2.1.2 COM对象与对象与C+对象的比较对象的比较 层次差异 COM对象建立在二进制级的基础上 C+对象建立在源代码级的基础

5、上 封装特性 COM对象的数据完全封装在对象内部,不能直接访问 C+对象的公有数据成员是可以访问的 可重用性 COM对象的重用表现为包容和聚合 C+对象的重用表现为继承与组合 多态性的表现形式不同 COM对象的多态需要通过接口来表现第9页/共50页2.2 COM接口接口 基本内容 接口定义与标识 用C+定义接口 IDL 接口的内存模型 接口的特点第10页/共50页2.2.2 接口定义和标识接口定义和标识 定义 是一个函数集,以二进制的形式给出了从一方到另一方的调用规范;函数的地址封装在一个数据结构中。 这个数据结构称为“接口函数表” 在C+中称为“虚函数表”,简称vtable 对于一个接口来说

6、,它的vtable是确定的,即:接口成员函数的个数是不变的;其先后顺序也是不变的v 客户程序通过一个指向vtable的指针来调用接口成员函数第11页/共50页COM接口结构接口结构接口指针指针指针函数1指针函数2指针函数3。 。 。 。 。 。对象实 现vtablepVtable第12页/共50页COM接口举例(接口举例(C语言)语言)struct IDictionaryVtble;struct IDictionary IDictionaryVtble * pVtbl ;struct IDictionaryVtbleBOOL ( * Initialize) (Idictionary * thi

7、s);BOOL ( * LoadLibrary) (Idictionary * this, String);void ( * FreeLibrary) (Idictionary * this);第13页/共50页COM接口标识接口标识-IID Interface Identifier 是GUID的一种用法 例如:extern “C” const IID IID_Iunkown = 0 x00000000, 0 x0000, 0 x0000 0 xc0, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x46 ; 如果客户程序要使用一个COM对象的某个接口

8、,必须知道该接口的IID以及它能提供的方法。第14页/共50页2.2.3 用用C+语言定义接口语言定义接口 COM接口结构中的vtable与class的vtable完全一致 因此,用class描述COM接口是最方便的手段 举例:class IDictionaryvirtual BOOL Initialize() = 0;virtual BOOL LoadLibrary(String) = 0;virtual void FreeLibrary() = 0;第15页/共50页类类IDictionary的内存结构的内存结构第16页/共50页2.2.4 接口描述语言接口描述语言IDL 以OSF 的 I

9、DL为基础 基本数据类型 与C语言非常接近,包括结构、联合、枚举、typedef等 interface coclass library 可以产生类型库第17页/共50页举例举例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(

10、in string);HRESULT FreeLibrary(); VC+的MIDL可以由IDL文件生成C/C+接口描述第18页/共50页IDL的意义的意义 IDL语言无关 跨语言的中间语言 产生C+头文件定义 相当于C+定义 产生TLB类型库 COM本身提供了一套基础设施来解释类型库 所有的标准接口都可以在SDK中找到IDL描述第19页/共50页编译编译IDL文件文件xxx.IDL文件文件MIDL.exexxx.h C+头文件头文件xxx_i.c GUIDxxx_p.c P/Sdlldata.cxxx.tlb用于客户用于客户/服务器服务器proxy/stub用于其他编程语用于其他编程语言,如

11、言,如Java、VB第20页/共50页2.2.5 接口的内存模型接口的内存模型 如果我们用C+实现字典对象,则类定义为:class CDictionary : public IDictionarypublic :CDictionary();CDictionary();public :virtual BOOL Initialize();virtual BOOL LoadLibrary(String);/ private :struct DictWord *m_pData;char *m_DictFilename128;/ ;第21页/共50页接口和字典对象的内存结构图接口和字典对象的内存结构图第

12、22页/共50页多个字典对象与接口的内存结构图多个字典对象与接口的内存结构图第23页/共50页不同方法实现的字典对象与接口关系不同方法实现的字典对象与接口关系第24页/共50页2.2.6 接口的特点接口的特点 二进制特性 接口不变性 继承性(扩展性) 多态性运行过程中的多态性(lecture over)第25页/共50页2.3 IUnkown 接口接口 所有的COM接口都必须从IUnknown派生,原因在于Iunknown接口提供了两个重要的特性: 生存期控制:通过“引用计数”来控制 接口查询:QueryInterface函数 Iunknown的IDL定义:Interface IUnknown

13、HRESULT QueryInterface( in REFIID iid, out void * ppv ) ;ULONG AddRef( void ) ;ULONG Release( void ) ;第26页/共50页2.3 IUnkown 接口(续)接口(续) Iunknown的C+定义:class IUnknown public:virtual HRESULT _stdcall QueryInterface(const IID& iid, void *ppv) = 0 ;virtual ULONG_stdcall AddRef( ) = 0; virtual ULONG_std

14、call Release( ) = 0;第27页/共50页2.3.1 引用计数引用计数 目的:是为了控制对象的生命周期 多个客户可以独立地控制对象的生存 引用计数反映了COM对象被客户引用的个数 引用计数是个整数,从0开始 两个操作:增 1 和 减 1 当客户得到一个指向对象的接口指针时,引用计数1; 当客户用完该接口指针时,引用计数1; 当引用计数为0时,表示没有客户在使用对象或者接口删除第28页/共50页2.3.2 实现引用计数实现引用计数 引用计数多实现方案的原因 一个COM组件可以实现多个COM对象 一个COM对象可以实现多个COM接口 组件级实现 ? 对象级实现 ? 接口级实现? 实

15、现方案比较(参见下页的图) 设置一个针对整个组件的全局引用计数 所有对象必须一起释放 计数分辨率太粗 为每个COM对象设置一个引用计数(折中方案) 为每个接口设置一个引用计数 客户不一定会用到对象的所有接口,造成资源浪费 计数分辨率太细第29页/共50页实现引用计数的层次(或粒度)实现引用计数的层次(或粒度)组件模块对象 1IUnknownISomeIntface组件引用计数对象引用计数接口引用计数对象 2IUnknownIOtherIntface。 。 。对象引用计数接口引用计数接口引用计数接口引用计数第30页/共50页重新定义重新定义IDictionaryclass IDictionary

16、 : public IUnknown virtual BOOL Initialize() = 0;virtual BOOL LoadLibrary(String) = 0;virtual BOOL InsertWord(String, String) = 0;virtual void DeleteWord(String) = 0;virtual BOOL LookupWord(String, String *) = 0;virtual BOOL RestoreLibrary(String) = 0;virtual void FreeLibrary() = 0;第31页/共50页重新定义重新定义

17、CDictionaryclass CDictionary : public IDictionarypublic :CDictionary();CDictionary();public :virtual HRESULT QueryInterface(const IID& iid, void *ppv) ;virtual ULONG AddRef() ; virtual ULONG Release() ; virtual BOOL Initialize();virtual BOOL LoadLibrary(String);/ private :struct DictWord *m_pDat

18、a;char *m_DictFilename128;int m_Ref ;第32页/共50页部分实现代码部分实现代码CDictionary:CDictionary ()m_Ref = 0;/ . initialize ULONG CDictionary:AddRef ()m_Ref +;return (ULONG) m_Ref; ULONG CDictionary:Release ()m_Ref -;return (ULONG) m_Ref;第33页/共50页客户控制引用计数的基本规则客户控制引用计数的基本规则 1、客户创建了组件对象并获得了第一个接口指针后,引用计数应该为1( 0+1 1)

19、2、在客户程序中,当把接口指针赋给其它变量时,应该调用AddRef,使引用计数增1; 3、在客户程序中,当一个接口指针被用完之后,应该调用Release,使引用计数减1;第34页/共50页客户代码举例客户代码举例IDictionary * pIDictionary = CreateObject(CLSID_Dictionary, IID_Dictionary);if( pIDictionary = NULL ) return; / reference count is 1/ load the dictionaryBOOL retValue = pIDictionary-LoadLibrary(

20、eng_ch.dict);if (retValue = FALSE) pIDictionary-Release();return;.IDictionary *pIDictionaryForWord = pIDictionary;pIDictionaryForWord -AddRef(); / Insert or delete some wordpIDictionaryForWord -InsertWord(.,.);pIDictionaryForWord -DeleteWord(.);pIDictionaryForWord -Release ( );./ finally, release di

21、ctionary objectpIDictionary-Release ( );第35页/共50页2.3.3 使用引用计数的规则使用引用计数的规则 1、函数参数中使用接口指针变量 输入参数:一般不用调用AddRef和Release 输出参数或返回一个接口指针变量: 相当于生成了一个新的接口指针接口指针, 因此,需要调用AddRef 输入输出参数 如果参数未被修改,则不用调用AddRef和Release;否则: 在参数被修改前,对传进来的原接口指针调用Release,在参数被修改之后,对新的接口指针调用AddRef。第36页/共50页2.3.3 使用引用计数的规则(续使用引用计数的规则(续1)

22、2、局部接口指针变量: 指的是用已有的值对局部变量赋值; 可以不调用AddRef和Release。 3、全局接口指针变量: 作为输入参数传给函数之前,调用AddRef 函数返回之后,调用Release 4、类成员变量 在类的作用域内,成员变量相当于全局变量,因此用R3.第37页/共50页2.3.3 使用引用计数的规则(续使用引用计数的规则(续2) 5、当以上情况都不合适时,采用下面的一般性规则: 在顺序执行过程中,如果要对一个接口指针变量赋值,则对赋值后的接口指针变量调用AddRef,并且,如果赋值前的接口指针变量还没有结束,则赋值前必须对它调用Release以便先结束它的使用。 如果要结束使

23、用一个接口指针变量,以后不再用到它了,则调用Release函数。 尽量养成遵循规则的好习惯,以免出现错误。 在整个生存期内,AddRef与Release一定要配对,否则: 漏掉AddRef,程序出错 漏掉Release,对象永不释放第38页/共50页2.3.3 使用引用计数的规则(续使用引用计数的规则(续3)v 频繁调用AddRef和Release会降低程序运行效率v 需要灵活运用,明显可以省略时要省略,比如: IDictionary * pIDictionaryForWord = pIDictionary; pIDictionaryForWord -AddRef(); / Insert or

24、 delete some word pIDictionaryForWord -InsertWord(.,.); pIDictionaryForWord -DeleteWord(.); pIDictionaryForWord -Release ( );第39页/共50页2.3.4 接口查询接口查询 问题的提出 一个COM对象可以实现多个接口,客户程序可以在运行时刻对COM对象的接口进行询问,以确定其是否已经实现。但对象的多个接口之间如何联系起来呢? 通过IUnknown接口的QueryInterface函数解决。 QueryInterface函数的形式 HRESULT QueryInterfac

25、e( in REFIID iid, out void * ppv ); 输入参数iid是欲查询接口的IID 输出参数ppv为查询得到的结果接口指针 如果对象没有实现iid所标识的接口,则ppv为空(NULL) 函数的返回值是一个32位的整数,含义为: S_OK,查到了指定的接口,接口指针放在ppv中; E_NOINTERFACE,没有这个接口,ppv为NULL; E_UNEXPECTED,发生了意外, ppv为NULL。第40页/共50页客户程序如何调用客户程序如何调用QueryInterface? 假设字典组件除了实现了IUnknown接口外,还实现了IDictionary接口和ISpell

26、Check接口,则客户程序只要得到其中的一个接口指针,就可以得到另外任何一个接口指针。下面是具体的例子:/create a new dictionary object, and got the first interface pointerIDictionary * pIDictionary = CreateObject(CLSID_Dictionary, IID_Dictionary);if( pIDictionary = NULL ) return; / reference count is 1/ load the dictionaryretValue = pIDictionary-Loa

27、dLibrary(eng_ch.dict);if (retValue = FALSE)pIDictionary-Release(); return; .第41页/共50页调用调用QueryInterface(续续)ISpellCheck *pISpellCheck;HRESULT result = pIDictionary-QueryInterface(IID_SpellCheck, (void *)&pISpellCheck);if (result != S_OK) pIDictionary-Release(); return; / . use interface pISpellCh

28、eck/ finally, release dictionary objectpIDictionary - Release( );pISpellCheck - Release ( );.第42页/共50页2.3.6 QueryInterface函数的实现函数的实现 假设字典对象类CDictionary的定义如下:class CDictionary : public IDictionary , public ISpellCheckpublic :CDictionary();CDictionary();public :/ IUnknown member functionvirtual HRESUL

29、T QueryInterface(const IID& iid, void *ppv) ;virtual ULONG AddRef() ; virtual ULONG Release() ;第43页/共50页CDictionary的定义的定义(续续)/ IDictionary member functionvirtual BOOL _stdcall Initialize();virtual BOOL _stdcall LoadLibrary(String);virtual void _stdcall FreeLibrary();virtual BOOL _stdcall LookupWord(String, String *);/ ISpellCheck member functionvirtual BOOL _stdcall CheckWord (String word, String *);private :structDictWord *m_Data;char*m_DictFilename128;intm_Ref ;intm_nWordNumber, m_nStructNumber;第44页/共50页类类CDictionary的内存结构的内存结构IDictionary

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论