(精品)4COM接口.ppt

上传人:hyn****60 文档编号:70946000 上传时间:2023-01-29 格式:PPT 页数:31 大小:197KB
返回 下载 相关 举报
(精品)4COM接口.ppt_第1页
第1页 / 共31页
(精品)4COM接口.ppt_第2页
第2页 / 共31页
点击查看更多>>
资源描述

《(精品)4COM接口.ppt》由会员分享,可在线阅读,更多相关《(精品)4COM接口.ppt(31页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、四 COM接口1.接口的结构与描述1.C+,C,Delphi2.IDL3.接口的的标识4.方法与结果5.数据类型6.MIDL 编译器.2.IUnknown 接口1.IUnkown接口定义2.引用计数规则3.接口查询规则11 接口的结构与描述nCOM把接口与实现分离开的动机:1.升级.把对象内部的工作细节对客户隐藏起来。使得实现类内部的数据成员的数量、类型以及内部的方法都可以发生变化,而客户程序无需重新编译。客户在运行时询问对象,以便发现对象的扩展功能。(是否实现了其他的接口?)2.编译器独立性。nCOM规范规定:接口是包含了一组函数的数据结构,通过这组数据结构,客户可以调用组件对象的功能。接口

2、的结构如下所示:2接口指针pVtable指针函数指针1函数指针2函数指针3对象实现vtablen客户程序使用一个指向接口数据结构的指针来调用接口成员函数。接口指针实际上指向第二个指针,这第二个指针指向一组函数指针(称为接口函数表,通常也成为虚函数表vtable,指向vtable的指针也成为虚表指针pvtable)虚表中每一项为一个4字节的函数指针,指向函数的实现。31.1 使用使用C+,C,Delphi描述接口描述接口n前一章已经模拟了COM的设计过程中最关键的过程。本章通过演示一个真正的COM(提供字典功能和拼写检查功能),来讲述COM接口与对象的关系,为了实现COM所涉及到的其他细节。n假

3、设我们要做一个字典,它要提供一些功能,这些功能用函数表示如下:n BOOL _stdcall Initialize();BOOL _stdcall LoadLibrary(String);BOOL _stdcall InsertWord(String,String);void _stdcall DeleteWord(String);BOOL _stdcall LookupWord(String,String*);BOOL _stdcall RestoreLibrary(String);void _stdcall FreeLibrary();n其具体意义略。4n使用C的类来描述接口的结构:(见原

4、理p29)nclass IDictionary public:virtual BOOL _stdcall Initialize()=0;virtual BOOL _stdcall LoadLibrary(String)=0;virtual BOOL _stdcall InsertWord(String,String)=0;virtual void _stdcall DeleteWord(String)=0;virtual BOOL _stdcall LookupWord(String,String*)=0;virtual BOOL _stdcall RestoreLibrary(String)

5、=0;virtual void _stdcall FreeLibrary()=0;n类IDictionary的内存结构与COM接口规范要求的完全一致。见下图:5thispVtableBOOL Initialize(this*);BOOL LoadLibrary(this*,String);BOOL InsertWord(this*,String,String);void DeleteWord(this*,String);BOOL LookupWord(this*,String,String*);BOOL RestoreLibrary(this*,String);void FreeLibrary

6、(this*);6n使用C语言描述接口的例子(简化自dictionary.h,见原理p27)struct Idictionary /接口包含一个指针,指针指向一个虚表结构 struct IDictionaryVtbl*pVtbl;struct IDictionaryVtbl /虚表由函数指针构成 HRESULT(STDMETHODCALLTYPE*Initialize)(IDictionary*This);/每个函数有一个指向接口本身的指针 HRESULT(STDMETHODCALLTYPE*LoadLibrary)(IDictionary*This,/*stringin*/WCHAR*pFi

7、lename);/以下函数省略7n实际上其他的语言,只要能描述虚表和虚表指针的结构就能够描述COM接口。比如Delphi语言对以上接口的描述如下:IDictionary=interface function Initialize:HResult;stdcall;function LoadLibrary(const fName:WideString):HResult;stdcall;./其他函数省略 end;Delphi对COM接口的描述非常简练。81.2 IDLnCOM最终的目标是建立二进制级的组件模型。COM规范只定义了接口的特征,它没有规定编译器,也没有约束语言的使用。我们不仅需要需要编译

8、器编译器独立性,还需要语言的独立性语言的独立性。n语言映射语言映射:nC其他语言。n类似于为了解决链接器兼容性问题时为每一种可能的链接器都提供一个模块定义文件的方式一样,也可以把C定义的接口翻译到其他的编程语言中。因为COM接口的二进制本质上就是一组vptr/vtbl虚表指针和虚表,所以,很多语言都可以做到。n但如果为所有已知的语言对所有的接口都产生映射版本,1.工作量巨大。2.由于C语言非常复杂,并且很容易产生歧义,它所描述的接口不一定能映射到所有可能的语言上。9nCOM提供了这样一种语言,它只用到基本的C语法。同时加入了一些能消除歧义的特征,用来描述接口。称为接口定义语言IDL(Inter

9、face Definition Language)nCOM IDL以OSF(OpenSoftware Foundation)开放软件基金会的DCE RPC(Distributed Computing Environment RPC)IDL为基础。DCE IDL使得我们可以以语言无关的方式来描述远程调用,IDL编译器也能够产生相应的网络代码。COM IDL在DCE IDL的基础上加入了一些与COM相关的扩展,比如继承性、多态性等。n它的意义在于以语言中性的方式准确地描述接口的类型.并且在IDL与其他语言之间建立映射.从而作为客户端与服务器端的接口描述标准.使得各方在遵循IDL标准的基础上,自由地

10、选择编程语言.n关于COM IDL的完整的参考见msdn组件开发MIDL定义语言。这里只讲解几个涉及到的内容。n下面是一个IDL文档的例子,它定义了我们将要完成的字典对象的接口。10import“unknwn.idl”;/类似于include,引入其他的idl文档#define MaxWordLength 32 object,/表明该接口是一个COM接口而不是一个RPC接口 uuid(54BF6568-1007-11D1-B0AA-444553540000),/全球唯一标志符 /表示属性interface IDictionary:Iunknown /Interface 关键字表明接口定义的开始

11、 HRESULT Initialize();HRESULT LoadLibrary(in,string WCHAR*pFilename);HRESULT InsertWord(in,string WCHAR*pWord,in,string WCHAR*pWordUsingOtherLang);HRESULT DeleteWord(in,string WCHAR*pWord);HRESULT LookupWord(in,string WCHAR*pWord,out WCHAR pWordOutMaxWordLength);HRESULT RestoreLibrary(in,string WCHA

12、R*pFilename);HRESULT FreeLibrary();/以上几个概念,如唯一标识符,数据类型HRESULT等,IUnknown接口等见后.111.3 接口的标识n逻辑名称与实质名称。两个开发人员可能选择同一个接口名字IDictionary,然而有不同的成员函数,更有不同的实现方法。除了名字相同以外,两个接口是不兼容的。两个COM组件和各自的客户程序有可能在同一台机器上。冲突的可能性时刻存在冲突的可能性时刻存在。为了消除名字冲突,所有的接口在设计时分配一个二进制的名字,也就是实质名字,它使用GUID(Global Unique Identifier)来标识接口。GUID是一个12

13、8位长的数。能在概率意义上保证不重复。nCOM GUID以DCE RPC中用到的UUID为基础。当GUID用来命名接口时,它被称为接口ID(Interface Identifier,IID),COM的实现也使用GUID来标识,这时它被称为类ID(Class Identifier,CLSID)用文本来表示,往往是以下的格式:CEBB3FBA-17F5-44c4-987C-631FAE5B80AC 32个16进制的数字。GUID的产生方法:1.GUIDGEN.exe 2.HRESULT CoCreateGuid(GUID*pguid)12n1.因为很少编译器支持128位整数,COM定义了一个结构来

14、表示GUID的128位值:typedef struct _GUID DWORD Data1;WORD Data2;WORD Data3;BYTE Data48;GUID;n2 Typedef GUID IID;typedef GUID CLSID;/为接口和实现类ID提供了别称。n3 为GUID类型定义了常量引用别称,以使得传送GUID类型参数更高效:#define REFIID const IID&#define REFCLSID const CLSID&n4 COM提供了等价性的测试函数 IsEqualGUID 并为GUID引用类型重载了和!操作符。n由于实质接口的名字是GUID而不是字符

15、串,因此上一章的Dynamic_Cast方法要修改,实际上整个IExtensibleObject接口都需要更新。131.4 方法与结果n几乎每个COM方法的返回值都是HRESULT。它是一个32位的整数,可以向调用者的运行环境提供关于发生了什么类型的错误的信息。比如网络错误、服务器失败等等。nHRESULT分为3部分,严重程度位、操作码、信息码。n比如:S_OK 成功S_FALSE 成功返回,但有逻辑错误E_FAIL 失败E_NOTIMPL 方法没有实现nCOM提供了宏来进行操作SUCCEEDED和FAIL.141.5 数据类型n为了支持语言独立性和平台独立性,COM IDL提供了一组内置的数

16、据类型,从这些数据类型到C、C、Java、VisualBasic之间可以建立一个映射。n不使用int数据类型,而使用short或者long类型。因为int类型与平台相关。nCOM使用双字节字符(UniCode编码)。使用OLECHAR(wchar_t)来表示。ASCII字符 单字节。0255 ANSI字符 单字节或多字节 UNICODE 双字节或宽字节 WIN32API 提供了MultiByteToWideChar WideCharToMultiByte.COM 提供了AnsiToUnicode UnicodeToAnsin为了编写在Visual Basic或ASP中使用的COM对象,应使用B

17、STR格式的字符串。BSTR是带有长度前缀的UniCode编码字符串。COM提供了一组函数用于BSTR的操作。SysAllocString SysFreeString等等。15nIDL支持结构类型,并以结构类型作为参数。nCOM与IDL支持联合类型(union)。COM定义了一个通用的联合的类型VARIANT.并且提供了一组函数操作VARIANT。VariantInit VariantClear VariantCopy VariantChangeType 等等。nIDL支持指针类型,并使用C指针语法n函数的每一个参数必须指明是输入、输出或输入输出。以便编译器在生成的代码中进行列集和散集处理。1

18、61.6 MIDL编译器nMIDL.exe是Win32SDK提供的工具。实现从IDL到到C/C+的映射的映射.它能编译idl文档以产生以下代码:(以刚才的Dictionary.idl为例)dictionary.h 接口说明的头文件(C/C+)dictionary_p.c 实现了接口的代理和存根 dictionary_i.c 定义了IDL中的GUID、IID dlldata.c 代理存根的入口函数以及其他数据结构 (DllGetClassObject等函数)dictionary.tlb 类型库文件.可以供VB Java等编译器使用.关于代理与存根及其它引出函数见后文。n开发工具提供了可视化编写I

19、DL的工具,比如CBuilder的TypeLibEditor。17xxx.IDL文件MIDL.exexxx.h C+头文件xxx_i.c GUIDxxx_p.c P/Sdlldata.cxxx.tlb用于客户/服务器proxy/stub用于其他编程语言,如Java、VB182 IUnknown 接口n2.1 IUnkown接口定义接口定义n在仿真程序中我们定义了一个一般性接口:nClass IExtensibleObjectPublic:virtual void*Dynamic_cast(const char*pszType)=0;virtual void DuplicatePointer(v

20、oid)=0;virtual void DestroyPointer(void)=0;用来完成接口的通用的任务:nDynamic_cast用于RTTI,它与C中的dynamic_cast操作符的功能类似。但是是编译器无关的。n DuplicatePointer用于通知对象一个接口指针已经被复制了,DestroyPointer用于通知对象一个接口指针被销毁了,它所拥有的资源可以被释放了。n其他的具体功能性的接口,如IFastString,IPersistObject等等都从此接口派生.19nCOM规范引入IUnkown接口来完成IExtensibleObject的功能。以下是其定义:nclass

21、 IUnknown public:virtual HRESULT _stdcall QueryInterface(REFIID riid,void*ppv)=0;virtual ULONG _stdcall AddRef(void)=0;virtual ULONG _stdcall Release(void)=0;/IUnknown 接口的名字来源于Tony Williams.1988./DonBox 有一张个性车牌:IUNKNOWNnIUnkown接口包括三个成员函数,分别对应于IExtensible的三个成员函数,其中QueryInterface用于对查询COM对象的其他接口,AddRef

22、,Release.用于引用计数。n它是唯一不从其他COM接口派生的接口。是所有COM接口的根源,所有其他COM接口都必须直接或间接地从IUnkown接口派生。nclass IDictionary:public IUnknown public:20IUnknown接口的IDL定义:(见SDK的include目录下的unknwn.idl)local,object,uuid(00000000-0000-0000-C000-000000000046)/UUID号 interface IUnknownHRESULT QueryInterface(in REFIID riid,out,iid_is(rii

23、d)void*ppvObject);ULONG AddRef();ULONG Release();我们可以使用IDL语言表示一个接口从另一个接口派生,正如我们已经看到的例子:21import“unknwn.idl”;/类似于include,引入其他的idl文档 object,/表明该接口是一个COM接口而不是一个RPC接口 uuid(54BF6568-1007-11D1-B0AA-444553540000)/全球唯一标志符 /表示属性interface IDictionary:Iunknown /Interface关键字表明接口 HRESULT LookupWord(in,string WCH

24、AR*pWord,out WCHAR pWordOutMaxWordLength);n使用MIDL编译器把以上IDL映射到映射到C+:#include“unknwn.h”nclass IDictionary:public IUnknown public:virtual BOOL _stdcall Initialize()=0;virtual BOOL _stdcall LoadLibrary(String)=0;virtual BOOL _stdcall InsertWord(String,String)=0;virtual void _stdcall DeleteWord(String)=0

25、;virtual BOOL _stdcall LookupWord(String,String*)=0;virtual BOOL _stdcall RestoreLibrary(String)=0;virtual void _stdcall FreeLibrary()=0;22n接口的继承接口的继承,使得子类接口具有基类接口的功能.特别地,所有的接口都从IUnkown接口派生而来,它们都具有接口的转换,和引用计数的功能.nCOM规定,接口不能使用多重继承。多重继承。n但是,这并不妨碍一个对象支持多个接口对象支持多个接口,(例子见前章).class FastString:public IFast

26、String ,public IPersistentObjectn可以使用一个图来表示COM对象和它所支持的接口:FastStirngIUnknownIPersistObjectIFastString232.2 引用计数规则引用计数规则nCOM对象可能实现了多个接口,对每个接口客户可能拥有多个指针。COM提供了一种机制管理资源,使得客户可以以直观的方式使用接口指针。COM对象通过引用计数来决定是否继续生存下去。每个COM对象都记录了一个“引用计数”的数值,该数值的含义为有多少个有效指针在引用该COM对象。当客户得到了一个指向该对象的接口指针时,引用计数增1;当客户用完了该指针后,引用计数减1。

27、当计数减到0时,COM对象就把自己从内存中清除掉。IUnkown的AddRef和Release成员函数分别进行引用计数的增1和减1操作。当COM对象支持多接口时,客户对每个接口有多个指针时,以上引用计数的工作方式可以顺利进行。往往使用COM对象类的成员变量就可以实现引用计数n引用计数规则可以精简为以下几条公理:24n客户控制规则:1.一个非空的接口指针从一个内存位置被拷贝到另一个内存位置时,应该调用AddRef.以通知对象又有一个指针指向了它.使用新指针或旧指针本质上是一样的,因为它们都指向同一个对象,但是为了理解的直观性,统一使用新指针,表示新指针的指向生效。2.说对于已经包含了非空指针的内

28、存位置来说,在重写该位置之前,(包括释放掉和赋予新的内容两种情况),必须使用此指针调用Release.以通知对象“这个引用已经被销毁了”注意:接口指针变量指向的COM对象是在堆(heap)上的,指针使用完后,无需使用delete删除,只需按照引用计数规则使用即可。引用计数能保证内存的正确管理。3.如果我们对多个内存之间的关系有特殊的理解.当然可能省略省略掉多余的掉多余的AddRef和Release.但是,这往往会带来理解上的和维护上的困难.弊大于利.252.3 接口查询规则n按照COM规范,COM对象可以支持多接口,这是COM对象的升级、更新,体现COM生命力的地方。n客户程序在运行时对COM

29、对象的接口进行询问,如果它实现了该接口,则客户可以调用它的服务。在上章的模拟例子中Dynamic_Cast函数起到了RTTI的作用。n在COM规范中,使用IUnkown的成员函数QueryInterface实现的。HRESULT CDictionary:QueryInterface(const IID&iid,void*ppv);QueryInterface使用接口的GUID而不是字符串逻辑名称来区分接口。n当客户创建了COM对象之后,创建函数会给客户返回一个接口指针,由于所有的接口都派生自Iunkown,它们都有QueryInterface成员函数,客户可以使用它来查询对象支持的其他接口。查

30、询时,客户指定接口的IID号iid,查询函数把查询结果保存在接口指针*ppv中。nQueryInterface的实现要求:26n接口查询原则:1。从同一对象的不同接口出发查询到的IUnknown接口完全相同。也即得到相同的IUnknown子对象.这并不是总是成立的.因为比如多重继承的关系,可能有多个IUnknown子对象.而保持唯一性的目的是调用唯一的接口查询和引用计数.使得无论何时通过IUnknown接口开始的接口查询总是得到唯一的结果.而从不同的路径查询到的其他接口不必完全相同。这可以允许有的接口是动态地生成的,比如tearoff接口等.272 对称性:AB成功,则BA成功n意味着客户不必

31、关心先获得哪个接口指针。两种不同类型的接口指针可以以任意的次序获得。FastStirngIUnknownIPersistObjectIFastString283 传递性:AB,BC,则ACn意味着客户不必以任何特定的顺序来获得某个接口。如果任何两个接口之间不能直接转换,那么也不能通过第三方来完成。或者说,我们总是能够简单地从一个接口出发一步到位地到达其他的接口。FastStirngIUnknownIPersistObjectIFastStringIOther294 自反性:AA总是成功的。n这实际是传递性的一个特例,对应于起点和终点相同的情形。FastStirngIUnknownIFastString30以上几条意味者所有的接口处于平等的地位(IUnknown除外).一个对象的所有接口构成一个双向连接图:IUnknownIForthIpersistObjectIFastStringIThird31

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 生活常识

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com