8跨进程特性.ppt_第1页
8跨进程特性.ppt_第2页
8跨进程特性.ppt_第3页
8跨进程特性.ppt_第4页
8跨进程特性.ppt_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

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

文档简介

1、1,八. COM跨进程特性,进程外组件 进程内COM对象的缺陷 进程外组件的使用 列集 列集的概念 接口指针的列集 标准列集过程 总体结构 存根 代理 接口列集器 ORPC通道 标准列集的实现 自定义列集 IMarshal接口 例子,2,1.进程外组件,1.1 进程内COM对象的缺陷 1.缺乏错误隔离. 对象的运行时错误将直接引起客户程序的崩溃. 2.安全环境共享 对象在客户进程中,使用的是客户进程的安全环境与权限. 这意味着特权客户程序创建的对象可以进行危险的操作; 较低权限的用户创建的对象可能无法访问一些重要的资源,从而无法达到计划的目的. 3. 很难实现分布式计算 进程内的对象使得“多个

2、客户进程共享同一个对象”非常困难. 进程外的COM组件也是实现DCOM的基础.(另外一台机器上的进程.) 无论哪种方式(进程内,进程外,远程)对客户而言,是透明的. 进程外的COM对象具有重要的意义.,3,进程外COM组件的实现以exe的形式存在.可以独立执行. 它 不会引出函数DllRegisterServer 和DllUnregisterServer. 相反,它执行时会检测命令行中是否有参数/ RegServer或/UnregServer, 以决定是否对注册表进行注册(注销). 注册表中它所支持的COM对象项中用LocalServer32键代替InprocServer32键. 进程外组件没

3、有输出DllGetClassObject以让客户程序得到类厂对象,相反当客户调用CoGetClassObject创建类厂对象时: 在CoGetClassObject函数内部,它找到EXE组件的程序位置后,发现是一个进程外组件, 于是启动组件进程,然后等待. 组件进程启动后(使用了/Embedding参数),调用CoInitialize初始化,创建所有的类厂,调用CoRegisterClassObject把类厂注册到COM中. 客户进程得到了组件的类厂信息,创建类厂,然后创建对象. 组件程序没有引出DllCanUnloadNow函数. 但是其判断是否可以卸载的条件与之相类似. 组件进程退出时,使

4、用CoRevokeClassObject函数在COM库中注销掉其所支持的类厂. CoRegisterClassObject与 CoRevokeClassObject要配对使用,以保证COM信息的一致性. 进程外组件与客户进程之间使用RPC进行通讯.如下图所示:,1.2 进程外组件的使用,4,进程外组件与客户进程之间使用RPC进行通讯. 在客户进程与组件对象之间是代理对象和存根对象. 代理和存根直接使用RPC. 这里的RPC是经过了扩展的RPC, 称为ORPC. 在ORPC中, 调用请求和返回结果要经过列集和散集的过程. 其定义如下.,2. 列集,5,列集(marshaling) 和散集(unm

5、arshaling) marshal的字典含义:编组、调度、引导、安排 整顿、配置、汇集、排列、集合 定义:是指客户进程可以透明地调用另一进程中的对象成员函数的一种参数处理机制 在调用过程中如果涉及到数值或指针的传递,则列集过程如下: 数值: 比如一个32位整数, 把四个字节的数据顺序装入到字节流中即可. 地址: 一个进程中的地址对另一个进程没有意义. 因此,列集时是把地址中的数据取出来封装到数据包中,散集时,在客户进程中分配一块内存数据包中的数据拷贝到内存中,然后返回内存地址. 接口指针: 实际上列集更重要的工作在于获取对象的接口指针.客户程序的一个有效接口指针代表客户进程到组件进程的一个连

6、接.列集一个接口指针远比一个一般的指针要复杂. 以下讨论的列集一般都指接口指针的列集.,2.1 列集的概念,6,2.2 接口指针的列集,接口指针列集的结果是把它变为一个可以被传输的字节流,字节流的内容唯一地标识了对象和对象所处的环境. (即套间 Apartment 见后, 现在可以理解为运行环境) 列集过程分为两种:标准列集和自定义列集.由于列集要使用到底层的传输协议,而这些代码往往对所有的对象而言是类似的,所以COM提供了标准列集法, 凡是没有特别指明的,都是使用这种方法. 为了效率等因素,对象可以选择自己控制底层的通讯.这时称为自定义列集法. 标准列集方式下的接口指针列集数据流. 见下图:

7、,7,其中OXID代表了对象的运行环境(套间). 代理需要使用此OXID来解析成网络或者IPC(进程间通讯)的地址,以便与对象的套间进行联系. OXID的解析工作由OXID解析器(OXID Resolver, OR)完成. OR是RPCSS服务的一部分. 接口指针的列集过程是由COM库函数CoMarshalInterface完成的:,8,HRESULT CoMarshalInterface( IStream *pStm, /列集数据的存放位置,是一个流.底层介质可以是磁盘,内存,或自定义的介质. 见结构化存储. REFIID riid, /列集指针的类型 IUnknown *pUnk, /列集

8、指针,当然它应该是riid类型的. DWORD dwDestContext, /目标环境. void *long pvDestContext, /保留. DWORD mshlflags /常规列集还是表格列集(写到一个全局的接口表中,可以被多次散集) ); 散集过程由函数CoUnmarshalInterface完成 HRESULT CoUnmarshalInterface( IStream *pStm, /包含有列集内容的流 REFIID riid, / 散集指针类型 void * * ppvObj /存放散集指针的位置 ); 一般而言,除非在进程内(而且套间类型相吻合),散集的接口不是原来的

9、接口本身,而是一个代理.,9,3 标准列集过程,3.1 总体结构 如果一个对象没有实现IMarshal接口,那么它的引用都是按照标准列集方式进行. 列集所使用的通讯协议: COM使用ORPC (Object Remote Procedure Call)来进行远程的通讯. COM对MS RPC其进行了扩充,以支持面向对象的调用。称为ORPC。 ORPC使用标准的RPC数据包,附加上专用于COM的信息,如接口指针标识符。在ORPC数据包经过列集后的数据按照NDR格式保存(网络数据表示法Network Data Representation)(CORBA使用CDR Common Data Repre

10、sentation,Web服务使用XML)。 标准列集的通讯机制如下图:,10,标准列集的proxy和stub结构,11,当CoMarshalInterface第一次确定对象希望使用标准列集时, 就创建一个特殊的COM对象: “存根管理器”. (Stub Manager). 存根管理器与COM对象一一对应, 被对象标识符OID标识(见接口的列集数据图). 并且拥有一个对COM对象的引用.可以理解为一个进程内的客户. 存根管理器并不知道如何处理ORPC请求.它针对每个COM接口管理一个“接口存根”对象(interface stub).接口存根是用IPID来标识的. 接口存根知道关于这个接口的所有

11、细节,它知道如何把ORPC请求消息中出现的所有in参数都散集出来,并且调用实际对象中的方法,然后把HRESULT结果和所有out参数列集到ORPC相应消息中去. 接口存根也有一个对COM对象的引用.,3.2 存根,12,接口存根实现IRpcStubBuffer接口 class IRpcStubBuffer : public IUnknown HRESULT Connect(IUnknown *pUnkServer) = 0; /把接口存根与目标COM对象联系起来 void Disconnect() = 0; /释放对象 HRESULT Invoke(RPCOLEMESSAGE *pMessag

12、e, IRpcChannelBuffer *pChannel) = 0; /当ORPC请求到达对象一方时,COM库会调用Invoke方法, *pMessage包含所有经过列集的in参数,也要利用RPC通道把处理结果发送回去 IRPCStubBuffer* IsIIDSupported(REFIID iid) = 0; ULONG CountRefs() = 0; HRESULT DebugServerQueryInterface(void *ppv) = 0; void DebugServerRelease(void *pv) = 0; ;,13,当CoUnmarshalInterface把一

13、个标准列集得到的对象引用散集出来的时候,它会创建一个“代理管理器”(proxy manager). 和存根管理器一样,它也不懂COM接口的任何知识,它也要针对每一个接口创建一个“接口代理”对象(Interface proxy),并且把这些对象都聚合在其内部.让客户感觉所有的接口都是从这个代理管理器上实现的. 代理管理器实现了IUnkown的三个函数.并且对AddRef和Release进行了优化处理,使得这些操作非到最后,只是增减本地的一个引用计数.这样以减少网络开销. 接口代理把客户的调用请求转换成为ORPC请求消息(列集in参数).并且把ORPC相应消息中的out消息和HRESULT散集出来

14、,返回给客户进程.,3.3 代理,14,每个接口代理实现IRpcProxyBuffer接口. class IRpcProxyBuffer : public IUnknown HRESULT Connect(IRpcChannelBuffer *pRpcChannelBuffer) = 0; void Disconnect() = 0; ; 接口代理管理器通过这个接口把接口代理与RPC通道连接起来,Connect方法把RPC通道保存起来 接口代理接到方法请求后,通过IRpcChannelBuffer接口的GetBuffer和SendReceive方法处理远程方法调用,15,接口代理和接口存根分别

15、由代理管理器和存根管理器创建.它们共享同一个CLSID. 包含两个分叉实现的实体称为接口列集器(Interface marshaler). 接口列集器的类厂没有实现接口IClassFactory (有一个成员函数CreateInstance,以创建对应的COM对象) ,相反,它实现了接口 IPSFactoryBuffer. uuid(D5F569D0-593B-101A-B569-08002B2DBF7A),local,object interface IPSFactoryBuffer : IUnknown HRESULT CreateProxy( in IUnknown *pUnkOuter

16、, / 代理管理器指针 in REFIID riid, /请求的远程接口指针的IID out IRpcProxyBuffer *ppProxy, /输出接口代理指针 out void *ppv ); / 远程接口指针 HRESULT CreateStub ( in REFIID riid, / 请求的远程接口指针IID in IUnknown *pUnkServer, / 实际对象指针 out IRpcStubBuffer *ppStub ); / 输出接口存根指针 接口列集器的CLSID存放在注册表中.,3.4 接口列集器,16,3.5 ORPC 通道,为了使用ORPC通道,COM提供了一个

17、通道(channel)对象, 通道对象封装了ORPC的功能,它实现了接口IRpcChannelBuffer. typedef struct tagRPCOLEMESSAGE void *reserved1; unsigned long dataRepresentation; / endian/ebcdic 编码方式 void *Buffer; / 载荷 ULONG cbBuffer; /载荷长度 ULONG iMethod; / 方法 void *reserved25; ULONG rpcFlags; RPCOLEMESSAGE; /ORPC消息的表示 class IRpcChannelBuf

18、fer : public IUnknown /ORPC通道 HRESULT GetBuffer(RPCOLEMESSAGE *pMessage, REFIID riid) = 0; /分配缓冲区 HRESULT SendReceive(RPCOLEMESSAGE pMessage,ULONG *pStatus) = 0; /发送ORPC请求并接收相应 HRESULT FreeBuffer(RPCOLEMESSAGE pMessage) = 0; /释放缓冲 HRESULT GetDestCtx(DWORD *pdwDestCtx, void *ppvDestCtx) = 0; HRESULT

19、IsConnected() = 0; ;,17,4 标准列集的实现,COM已经提供了缺省的代理对象、存根管理器以及RPC通道 我们只需实现每一个接口的代理/存根组件。参数和返回值的数据类型是关键。 首先使用IDL语言描述接口 编写IDL文件。产生dictionary.idl MIDL.exe是Win32SDK提供的工具。它能编译idl文档以产生以下代码:命令行: midl dictionary.idl 则产生下面的文件: dictionary.h 包含接口说明的头文件,可用于C或者C+语言; dictionary_p.c 该C文件实现了接口IDictionary的代理和存根; dictiona

20、ry_i.c 该C文件定义了IDL文件中用到的所有全局描述符GUID,包括接口描述符; dlldata.c 该C文件包含代理/存根程序的入口函数以及代理类厂所需要的数据结构等。(DllGetClassObject等函数),18,准备一个DEF文件 LIBRARYMyLib DESCRIPTIONIDictionary Interface Proxy/Stub DLL EXPORTS DllGetClassObject1 PRIVATE DllCanUnloadNow2 PRIVATE GetProxyDllInfo 3 PRIVATE DllRegisterServer 4 PRIVATE D

21、llUnregisterServer5 PRIVATE 创建一个空的 win32 dll工程 加入以上5个文件 projectsettingsC/C+preprocessor definitionsREGISTER_PROXY_DLL projectsettingsLinkobject/library modules uuid.lib rpcrt4.lib 以上4,5,6 也可以编写一个MAKE文件在编译选项中加入REGISTER_PROXY_DLL连接选项中加入rpcrt4.lib、uuid.lib来完成 编译,注册。(代理与存根都是DLL,不要与进程外对象混淆) 在实际的编程工作中往往并不

22、这样进行处理。因为集成开发环境已经提供了对IDL文件的编译支持。IDE可以启动MIDL对IDL进行编译。不需手工编写makefile。并且可以把代理存根和可执行代码编译在一起。,19,5. 自定义列集,为了性能的原因,我们有可能使用自定义列集.接口指针经过自定义列集后的数据流结构如下:,一个对象如果实现了IMarshal,则表明它希望使用自定义列集法.,20,5.1 IMarshal接口,IMashal接口是使用自定义列集或标准列集的标志: class IMarshal : public IUnknown HRESULT GetUnmarshalClass( .) = 0; /获取自定义代理的

23、CLSID, 由CoMashalInterface调用. HRESULT GetMarshalSizeMax(.) = 0; /获取自定义对象引用的大小 由CoGetMarshalSizeMax调用 HRESULT MarshalInterface( .) = 0; /对接口进行列集,写入流中 由CoMarshalInterface调用 HRESULT UnmarshalInterface(.) = 0; /从流中散集出接口来 由CoUnmarshalInterface调用 HRESULT DisconnectObject(.) = 0; /关闭连接 由CoDisconnectObject调用 HRESULT ReleaseMarshalData(.) = 0;

温馨提示

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

评论

0/150

提交评论