资源描述
middleware technology and application,#,#,#,1,第五章 COM 相关技术,COM 技术的发展,COM技术的体系结构,COM技术中的接口,COM类工厂机制,1第五章 COM 相关技术COM 技术的发展,2,COM技术的发展,COM技术经历了,DLL,OLE(建立在DDE的基础上的),1993 年正式 引入COM 规范(,1993中旬COM首次出现。微软推出 OLE2.0,开始用COM代替DDE作为底层通讯协议。这也是COM第一个重要的用途。,),DCOM 发表于1996,COM+ 发表于1999,.NET发表于2000年7月,2COM技术的发展COM技术经历了,3,COM的出现,1996年,大多数开发人员开始编写32位的WIN95应用程序。他们发现,OLE使用COM的方式是一种非常好的设计软件的方法。开发人员开始使用类似的方法编写自己的对象和界面。另外,操作系统也开始要求使用COM技术编程,如编写WIN95用户界面。COM组件的设计是实现一个保罗万象的,二进制通用代码复用技术,,和今时今日的面向服务复用技术不同,当年的技术更崇尚与方法复用,COM技术提供了跨计算机的二进制通讯规范(也就是说是大家都要遵守的合同)。用于软件组件间跨进程,跨机器,和操作系统进行交互操作。COM是透明位置的。它可以在EXE,DLL或者远程机器上使用。,3COM的出现 1996年,大多数开发人,4,2009年1月份第3届中国IT技术精英大会上对外发布,WCF是微软用于开发面向服务的Windows应用程序的统一平台。,42009年1月份第3届中国IT技术精英大会上对外发布 WC,5,COM /DCOM,COM/DCOM(Component Object Model,构件对象模型/Distrubuted Component Object Model) 是Microsoft提出的一个(分布的)二进制兼容构件的规范。只要遵守这种规范,不管用什么编程语言和工具开发的COM构件,也不管是否运行在同一台机器上,还是运行在不同的机器上,都可以被使用。,5COM /DCOM COM/DCOM(Compone,Middleware,6,C+的类和对象,一、类和对象假设你在C+中创建了一个称为xxx的简单类。它有几个成员函数,称为MethodA, MethodB和MethodC。每个成员函数可接收参数,并返回一个结果。该类的定义如下所示:,class xxx public:int MethodA(int a);int MethodB(float b);float MethodC(float c);,Middleware 6C+的类和对象一、类和对象,Middleware,7,C+类,对象的使用,xxx *px; / 指向xxx类的指针px = new xxx; / 创建对象px-MethodA(1); / 调用方法delete px; / 释放对象,Middleware 7C+类,对象的使用,8,COM对象模型,COM使用相同的面向对象模型。COM拥有与C+对象一样的类、成员函数和实例。通过指针来访问COM对象,在完成处理后,必须释放它们。,ixx *pi / 指向to xxx COM接口的指针CoCreateInstance( / 释放接口,8COM对象模型COM使用相同的面向对象模型。COM拥有与C,9,C+对象与COM对象的不同,C+对象通常都运行在同一进程空间中。COM对象可跨进程和跨计算机运行。,COM方法可通过网络调用 。,在一个进程空间中,C+方法的名字必须是唯一的,而COM对象的名字在整个世界中都是唯一的。,COM服务器可以使用多种不同的语言和在不同的操作系统上编写,而C+对象通常都使用C+编写,9C+对象与COM对象的不同C+对象通常都运行在同一进程,10,C+与COM的比较,概念,传统的C+/OOP,COM,客户端,一个从某个服务器请求服务的程序,一个调用COM方法的程序,服务器,一个为其它程序服务的程序,一个让某个COM客户得到COM对象的程序,接口,没有,通过COM调用的一组函数的一个指示器,类,一个数据类型,定义了一组一起使用的方法和数据 一个对象的定义,用来实现一个或者多个COM接口,“coclass”也是,对象,一个类的实例化,一个coclass的实例化,Marshalling,没有,在客户和服务器端之间移动数据,10C+与COM的比较概念传统的C+/OOPCOM客户端,11,接口的概念,COM接口是一个全新的概念,在C+中是没有的。一个接口没有一个有形的存在。它类似一个抽象类,但不完全一样。简单地说,,接口是函数的集合,。,在C+,一个类仅允许有一个接口。这个接口的成员函数都是该类所有的公有成员函数。接口是类的公共可见部分。在C+中一个接口和一个类几乎没有任何的区别,以下就是C+类的一个例子:类的public子集是外部的“接口”。接口将类的内部和使用者隔离开来。,class yyy public: int DoThis(); private: void Helper1(); int count; int x,y,z; ;,11接口的概念COM接口是一个全新的概念,在C+中是没有的,12,COM中的接口,COM允许一个coclass(COM类)拥有多个接口,每个接口拥有自己的名字和函数集。这样做便可得到更为复杂和功能更强的对象。这个概念与C+是完全不同的。,一个COM对象可支持一个接口的集合,每个接口都拥有自己的名字。对于你自己创建的COM对象,你可以只使用单一COM接口。也可支持多个COM接口。COM接口的名字是唯一的。,隔离,接口和实现,对于COM是至关紧要的。通过将它的实现和接口隔离开,我们可以建立组件。组件可被替换和重用。两者均可简化和增加对象的可用性。,12COM中的接口COM允许一个coclass(COM类)拥,13,COM构件模型,*建立在二进制层次上的标准,-编程语言和开发工具无关,*COM规范,-平台无关,-定义了大量的标准接口(如IUnknown、,IClassFactory、,IDispatch等等)用于各种用途,*COM实现,-平台相关,-Windows实现了规范及许多辅助功能,13COM构件模型*建立在二进制层次上的标准,14,COM 组件的使用和开发特点:,COM 组件力图做到以一致的方式使用组件和开发组件.从体系结构上保证所开发的组件的,无时间差异性;(允许用户透明地使用组件的不同版本),无功能差异;(按相同的方式处理变化的组件),位置透明性; (不表现出对组件所处位置的信赖),语言无关性;,运行环境无关性;,14COM 组件的使用和开发特点:COM 组件力图做到以一致,15,COM对象,COM接口,COM组件,COM基础结构,15COM对象COM接口COM组件COM基础结构,16,几个基本概念,COM接口, 客户与对象之间的协议,客户使用COM接口调用COM对象的服务,COM对象, 实现COM接口, 通过COM接口提供服务, 可包含多个接口,COM构件(组件), COM对象的载体,可包含多个COM对象, 可独立发布的二进制组件, 在Windows平台上为DLL或者EXE,COM库,提供 了用户和组件可调用的基本函数,16几个基本概念COM接口,17,进程内构件,COM库,客户应用,程序,服务器,对象,1.客户调用,CoCreatinstance,(CLSID_X,IDD_A),2.COM定位并实例化服务器,CLSID_X C:svr1.DLL,CLSID_Y C:svr2.EXE,3.COM库将界面A,的指针返回,4.客户调用,界面A的方法,17进程内构件客户应用对象1.客户调用2.COM定位并实例化,18,进程外构件,18进程外构件,19,远程外构件,19远程外构件,20,注册表,-发布构件信息、对象信息、接口信息等,构件发布,20注册表构件发布,21,COM功能,*基本功能,- IUnknown (queryinterface,Addref,Release),- IDispatch,*扩展功能,-自动化,-连接点,-结构化存储,-名字服务,21COM功能*基本功能,22,COM体系结构,22COM体系结构,23,COM应用,*OLE,*ActiveX Control,*ASP,*OLE DB,.,23COM应用*OLE,24,COM接口和对象,24COM接口和对象,25,COM接口,接口标识IID,IUnknown,COM接口二进制结构,25COM接口 接口标识IID,26,COM接口的标识,IID,是GUID的一种用法,GUID是一个128位的长整数,具有全球唯一性,前48位是组件位置信息,后80位是组件的时间信息。,例子:54BF6567-1007-11D1-B0AA-444553540000,C语言结构和定义:,typedef struct _GUID DWORD Data1; WORD Data2;,WORD Data3; BYTE Data48; GUID;,extern C const GUID IID_IString =, 0x54bf6567, 0x1007, 0x11d1, 0xb0, 0xaa, 0x44, 0x45, 0x53,0x54, 0x00, 0x00, ;,26COM接口的标识IID 是GUID的一种用法,GUI,27,IUnknown接口,所有的COM接口都从IUnknown派生,C+定义:,class IUnknown,public:,virtual HRESULT_stdcall QueryInterface(,const IID,virtual ULONG _stdcall AddRef() = 0;,virtual ULONG _stdcall Release() = 0;,;,27IUnknown接口 所有的COM接口都从IUnknow,28,IUnknown接口,C定义:,typedef struct IUnknownVtbl,HRESULT ( STDMETHODCALLTYPE _RPC_FAR *QueryInterface )(,IUnknown _RPC_FAR * This, /* in */ REFIID riid,/* iid_isout */ void _RPC_FAR *_RPC_FAR *ppvObject);,ULONG ( STDMETHODCALLTYPE _RPC_FAR *AddRef )(,IUnknown _RPC_FAR * This);,ULONG ( STDMETHODCALLTYPE _RPC_FAR *Release )(,IUnknown _RPC_FAR * This);, IUnknownVtbl;,interface IUnknown,CONST_VTBL struct IUnknownVtbl _RPC_FAR *lpVtbl;,;,28IUnknown接口C定义:,29,COM,接口二进制结构,接口指针,指针,pVtable,指针函数,1,指针函数,2,指针函数,3,vtable,对象实现,29COM接口二进制结构接口指针指针pVtable指针函数1,30,COM接口的内存模型,30COM接口的内存模型,31,接口查询,目的:按照COM规范,一个COM对象可以实现多个接口。从一个接口到另一个接口的访问途径,函数QueryInterface(iid, ppv),用法:, 初始得到了一个接口指针之后, 调用它,QueryInterface函数,获得另一个接口指针,QueryInterface在返回接口之前,必须调用新接口的AddRef函数,返回值说明了对象对接口的支持情况,S_OK、E_NOINTERFACE、E_UNEXPECTED,31接口查询 目的:按照COM规范,一个COM对象可以实现多,32,引用计数,目的:是为了控制对象的生命周期,用法:,-客户要引用接口时 调用AddRef()增一,-客户用完接口时 调用Release()减一,-当对象的引用计数为0时,释放,32引用计数目的:是为了控制对象的生命周期,33,引用计数问题,在整个生存期内,AddRef与Release一定要配对,否则:,漏掉AddRef,程序出错,漏掉Release,对象永不释放,33引用计数问题在整个生存期内,AddRef与Release,34,COM,对象,1.客户的交互实体,2.包括属性和方法,或者状态和操作,3.能够提供服务通过COM接口,34COM对象1.客户的交互实体,35,COM,对象的标识,CLSID,1.是GUID的一种用法,2.创建对象的时候必须要提供CLSID,3.COM对象的身份, 身份是否一致的可判断性,35COM对象的标识CLSID1.是GUID的一种用法,36,COM,对象和接口图示,字典对象,IUnknown,IDictionary,ISpellCheck,36COM对象和接口图示字典对象IUnknownIDicti,37,COM,对象与,C+,对象的比较,C+,对象,设计=多态性+(某些)迟绑定+(某些)封装性 +(实现/接口)继承,COM,对象,设计=多态性+(完全)迟绑定+(完全)封装性 +接口继承+二进制重用性,37COM对象与C+对象的比较C+对象设计=多态性+(某,38,IDL简介,数据类型,包括基本数据类型、结构、联合、枚举、typedef等,interface,coclass,library,可以产生类型库,38IDL简介数据类型,39,IUnknown,接口的,IDL,描述, local, object,uuid(00000000-0000-0000-C000-000000000046),pointer_default(unique),interface IUnknown,typedef unique IUnknown *LPUNKNOWN;,HRESULT QueryInterface( in REFIID riid,out, iid_is(riid) void *ppvObject);,ULONG AddRef();,ULONG Release();,39IUnknown接口的IDL描述 local, obj,40,IDictionary接口的,IDL,描述, local, object,uuid(E13EF4E4-D2F2-11d0-9816-00C04FD91972),pointer_default(unique),interface IDictionary : IUnknown,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();,;,40 IDictionary接口的IDL描述 local,41,IDL,中类的描述,uuid(1e196b20-1f3c-1069-996b-00dd010fe676),version(1.0),helpstring( MyDictionary class),helpcontext(2481), appobject,coclass MyDictionary,interface IDictionary : IUnknown;,;,41IDL中类的描述,42,IDL,中库的描述,uuid(12345678-1234-1234-1234-123456789ABC),helpstring( MyDictionary 2.0 Type Library),lcid(0x0409),version(2.0),library MyDictionaryLib,interface IDictionary : IUnknown;,;,42IDL中库的描述,43,编译IDL,xxx.IDL文件,MIDL.exe,xxx.h C+头文件,xxx_i.c GUID,xxx_p.c P/S,dlldata.c,xxx.tlb,用于客户/服务器,proxy/stub,用于其他编程语,言,如Java、VB,.h 接口说明的头文件;,_p.c 实现了接口的代理和存根;,_i.c 定义了IDL文件中用到的所有全局描述符GUID;,dlldata.c 包含代理/存根程序的入口函数以及代理类厂所需要的数据结构等。,43编译IDLxxx.IDL文件MIDL.exexxx.h,44,COM,实现,44,45,实现形式,进程内组件, in process component,进程外组件, out of process component,45实现形式,46,进程内组件,组件:做成DLL,引出对象创建函数,客户:用到的API函数,LoadLibrary、,GetProcAddress、FreeLibrary,46进程内组件组件:做成DLL,引出对象创建函数,47,进程外组件,实现形式:EXE,IPC:DDE、消息机制、共享内存、RPC/LPC等等,47进程外组件实现形式:EXE,48,进程外组件,48进程外组件,49,回顾:客户与对象之间的连接,客户通过vtable与对象进行通信,客户如何获得第一个接口指针?,CreateString引出函数,49回顾:客户与对象之间的连接客户通过vtable与对象进行,50,创建函数,方案1: 直接引出创建函数。,方案2: 把创建函数封装到一个对象中。,优点:灵活,客户以一致的方式调用创建函数。,50创建函数方案1: 直接引出创建函数。,51,创建函数所在的对象,该对象被称为类对象,也称为类厂,现在问题是:如何创建类厂对象?, 通过引出一个固定的函数: DllGetClassObject,客户-引出函数-类厂对象-用户对象,增加了一层间接性,带来灵活性,51创建函数所在的对象该对象被称为类对象,也称为类厂,52,类厂对象,实例对象,创建类厂对象,创建对象结构示意图,客户,创建实例对象,DllGetClassObject,52类厂对象实例对象创建类厂对象创建对象结构示意图客户创建实,53,类厂,(Class Factory),类厂:用于创建COM对象的COM对象,目标:完成COM对象的创建过程,更好地把客户与对象隔离开来。,特殊性:, 实现一个或多个创建接口,缺省的接口为IClassFactory, 类厂本身没有CLSID,53类厂(Class Factory)类厂:用于创建COM对,54,类厂(续),类厂与COM对象有一一对应关系,54类厂(续)类厂与COM对象有一一对应关系,55,创建类厂对象,DllGetClassObject创建类厂对象,创建类厂对象需要哪些信息?,DllGetClassObject原型:,HRESULT DllGetClassObject(,const CLSID& clsid,const IID& iid,(void *)ppv,);,55创建类厂对象DllGetClassObject创建类厂对,56,创建函数需要哪些信息,clsid,与类厂绑在一起,iid,客户提供,/IID_IClassFactory,结果接口指针,类型取决于iid,56创建函数需要哪些信息clsid,57,IClassFactory接口,class IClassFactory : public IUnknown,virtual HRESULT _stdcall CreateInstance(,IUnknown *pUnknownOuter,const IID& iid,void *ppv) = 0;,virtual HRESULT _stdcall LockServer(BOOL bLock) = 0;,;,57IClassFactory接口class IClassF,58,小结:客户创建对象过程,客户提供信息, 组件位置、clsid、iid、结果接口指针地址ppv,过程:, 根据组件位置,LoadLibrary, GetProcAddress,获取DllGetClassObject, 用clsid和IID_IClassFactory获得类厂对象接口指针pFactory, 用iid、ppv调用pFactory-CreateInstance,58小结:客户创建对象过程客户提供信息,59,创建过程的位置透明性,位置透明性可以极大地方便客户程序,如何做到位置透明性?, 在当前环境下,每个clsid必定与某个组件相联系, 如何从clsid映射到组件位置?,解决方案:, 维护clsid与组件位置的映射关系, 在客户与组件之间插入中介,59创建过程的位置透明性位置透明性可以极大地方便客户程序,60,COM方案,在Windows平台上,使用系统注册表保存映射关系,所以,从clsid可以找到对应组件的位置,在客户与组件之间插入COM库,由COM库完成创建的细节工作,60COM方案在Windows平台上,使用系统注册表保存映射,61,Windows系统注册表,树状结构, 根是“My Computer”, 预定义的5个子节点, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_CONFIG,61Windows系统注册表树状结构,62,通过注册表管理,COM,对象,HKEY_CLASSES_ROOTCLSID,62通过注册表管理COM对象HKEY_CLASSES_ROO,63,TreeView,组件的注册信息,Microsoft TreeView Control,C:WINDOWSSYSTEMCOMCTL32.OCX,COMCTL.TreeCtrl.,6B7E6392-850A-101B-AFC0-4210102A8DA7.,63TreeView组件的注册信息Microsoft Tre,64,回顾:,COM,对象的标识,CLSID,两种形式, 128位整数,随机数,不需要运算功能,但是需要比较和查找功能, 字符串形式,例如: 72d3edc2-a4c4-11d0-8533-00c04fd8d503,ProgID:友好名,字符串形式, 有可能重名,用一种约定来避免重名, 例如:Word.Document, 包含版本:Word.Document.8,64回顾: COM对象的标识CLSID,两种形式,65,注册表其他事项,系统全局的注册信息、公共信息仓库,工具,RegEdit.exe,、,RegSvr32.exe,、,OLEView,程序访问途径:,Win32 API,65注册表其他事项系统全局的注册信息、公共信息仓库,
展开阅读全文