八. COM跨进程特性 进程外组件 列集 标准列集过程 总体结构 存根 代理 接口列集器 ORPC通道 标准列集的实现 自定义列集

Slides:



Advertisements
Similar presentations
全院教职工基础信息 采集工作培训会 2013 年 10 月 15 日.  一、采集工作基本情况  二、 Excel 表格组成  三、 Excel 采集模板操作.
Advertisements

1 中 间 件 技 术中 间 件 技 术. 2 第 1 章 中间件产生背景及分布式计算环境 主要内容 开放系统 互操作性 中间件.
股指期货的风险及防范.
第五章 网络服务组件.
广州宜家选址分析 0连锁 李若谷 陈玉风 黄小飞 蓝柔盈.
南山中學 102學年度 性別平等教育週性別教育 性騷擾防治.
第 12 章 SOAP技術.
第16章 代理模式 Website:
性教育教學模組設計 主題:身體自主權 台中市忠明國小 巫偉鈴.
整体销售方案 中山市美好物业代理有限公司
产学研项目财务管理若干问题 鲁春艳
中国公务员管理 CHINAS CIVIL SERVICE SYSTEM
一百零一年溪口國小 學校日 班級: 三年三班 教師: 張慈麟.
校园信息管理系统 河北科技大学网络中心 2000/4/10.
关注热点 2014年天猫双十一成交总额 571亿 点亮217个国家地区
徵收苗栗市福全段147、1588及文心段10、11地號等4筆土地之
動畫與遊戲設計 遊戲開發工具 程于芳 老師
2016中重卡网络规划 中重卡营销部 2016年6月.
关注品德与生活课的 探究性学习和微课程的发展
讲 义 大家好!根据局领导的指示,在局会计科和各业务科室的安排下,我给各位简要介绍支付中心的工作职能和集中支付的业务流程。这样使我们之间沟通更融洽,便于我们为预算单位提供更优质的服务。 下面我主要从三方面介绍集中支付业务,一是网上支付系统,二是集中支付业务流程及规定等,
高等职业学校建筑设计类与艺术设计类专业骨干教师实践能力国家级培训
建设数字化的卫生监督体系 深 圳 市 卫 生 监 督 所 2006年4月.
中国人民公安大学经费管理办法(试行) 第一章总则 第四条:“一支笔” “一支笔”--仅指单位主要负责人。负责对本 单位的经费进行审核审批。
中国公务员制度 主讲:吴春华 教授 温志强 副教授.
没有请柬该如何办 记者如何选取有利位置 着装 准备工作 提问时的注意事项
主讲:江西财经职业学院傅文清 联系电话: 教学模式与课程教学设计 主讲:江西财经职业学院傅文清 联系电话:
22 第 课 增强自我保护的意识和能力.
在课题探索中成长 东风东路小学 王洁华 全国红领巾示范学校 广东省一级学校
关注女职工劳动保护,维护女职工合法权益 ——《女职工劳动保护特别规定》解读
计算机系统安全 第10章 常用攻击手段.
3.1能源资源的开发 ——以我国山西省为例.
Socket.
《公共事物的治理之道》 Governing the Commons
潘爱民 北京大学计算机科学技术研究所 组件技术——最后一讲 潘爱民 北京大学计算机科学技术研究所
远程教育站点管理 及齐鲁先锋平台的使用 平阴县党员干部现代远程教育中心.
潘爱民 COM开发 潘爱民
第一章 認識Visual C 環境架構 1-1 認識Visual C Visual Studio 概觀
Asp.net 基礎.
第五章 信息与系统集成技术 概述 数据流集成技术 信息流集成技术 信息管理集成技术 流程重组与业务流程集成 企业门户集成 企业集成架构
第9章 GIS新技术与”数字地球”简介 北京建筑工程学院 王文宇.
第1章 .NET与C# 为什么要设计一门新的编程语言? C#在微软的.Net平台中占据什么样的地位?
WalkThrough SharePoint WebPart 入门指南
潘爱民 COM对象的实现(续) 潘爱民
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
在一定程度上 人类的思维产生于 简单个体之间的相互作用 ——Marvin Minsky.
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
十四. 名字对象 概念 IMoniker接口 名字对象的创建 根据显示名创建名字对象 类名字对象的创建 其他名字对象的创建
五 COM对象 接口及其接口方法的实现 注册表 类厂 COM组件与客户程序的交互过程 类厂的由来 类厂的定义与实现 类厂的创建
COM:moniker、UDT、control
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
潘爱民 COM:可连接对象 & 结构化存储 潘爱民
潘爱民 自动化(Automation) 潘爱民
Window Socket 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
劉崇汎 崑山科技大學 電腦與通訊系 DLL的建立與引用 劉崇汎 崑山科技大學 電腦與通訊系
计算机网络概述 计算机网络原理与技术.
_08遍历物理网卡 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
小学生交通安全主题班会课件 安全 security 上派学区中心校校园安全管理办公室.
2.3 平面与回转体表面相交 回转体截切的基本形式 截平面 截平面 截交线 截交线.
四 COM接口 接口的结构与描述 IUnknown 接口 C++, C, Delphi IDL 接口的的标识 方法与结果 数据类型
COM组件及其设计 一、COM组件定义和DNA思想简介 二、COM组件的特点 三、COM组件对象的软件工程方法 四、DNS、MTS
水利绿色发展问题与建议 姜文来 中国农业科学院农业资源与农业区划研究所.
微信商城系统操作说明 色卡会智能门店.
3.5 出入口管理软件设置与设计验证.
中国农业科学院博士后学术论坛 博士后基金申请的经验及体会 中国农业科学院生物技术研究所 秦 华 博士
#include <iostream.h>
本节内容 重定位表 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第十二章 位运算.
客户端-服务器框架 第一部分.
大綱 一.受試者之禮券/禮品所得稅規範 二.範例介紹 三.自主管理 四.財務室提醒.
Android进程间通讯.
Presentation transcript:

八. COM跨进程特性 进程外组件 列集 标准列集过程 总体结构 存根 代理 接口列集器 ORPC通道 标准列集的实现 自定义列集 进程外组件的使用 列集 列集的概念 接口指针的列集 标准列集过程 总体结构 存根 代理 接口列集器 ORPC通道 标准列集的实现 自定义列集 IMarshal接口 例子

1.进程外组件 1.1 进程内COM对象的缺陷 1.缺乏错误隔离. 对象的运行时错误将直接引起客户程序的崩溃. 2.安全环境共享 对象在客户进程中,使用的是客户进程的安全环境与权限. 这意味着特权客户程序创建的对象可以进行危险的操作; 较低权限的用户创建的对象可能无法访问一些重要的资源,从而无法达到计划的目的. 3. 很难实现分布式计算 进程内的对象使得“多个客户进程共享同一个对象”非常困难. 进程外的COM组件也是实现DCOM的基础.(另外一台机器上的进程.) 无论哪种方式(进程内,进程外,远程)对客户而言,是透明的. 进程外的COM对象具有重要的意义.

1.2 进程外组件的使用 进程外COM组件的实现以exe的形式存在.可以独立执行. 它 不会引出函数DllRegisterServer 和DllUnregisterServer. 相反,它执行时会检测命令行中是否有参数/ RegServer或/UnregServer, 以决定是否对注册表进行注册(注销). 注册表中它所支持的COM对象项中用LocalServer32键代替InprocServer32键. 进程外组件没有输出DllGetClassObject以让客户程序得到类厂对象,相反当客户调用CoGetClassObject创建类厂对象时: 在CoGetClassObject函数内部,它找到EXE组件的程序位置后,发现是一个进程外组件, 于是启动组件进程,然后等待... 组件进程启动后(使用了/Embedding参数),调用CoInitialize初始化,创建所有的类厂,调用CoRegisterClassObject把类厂注册到COM中. 客户进程得到了组件的类厂信息,创建类厂,然后创建对象…. 组件程序没有引出DllCanUnloadNow函数. 但是其判断是否可以卸载的条件与之相类似. 组件进程退出时,使用CoRevokeClassObject函数在COM库中注销掉其所支持的类厂. CoRegisterClassObject与 CoRevokeClassObject要配对使用,以保证COM信息的一致性. 进程外组件与客户进程之间使用RPC进行通讯.如下图所示:

2. 列集 客户程序 (客户进程) 代理对象 组件程序 (组件进程) 存根代码 LPC/RPC 组件对象 进程外组件与客户进程之间使用RPC进行通讯. 在客户进程与组件对象之间是代理对象和存根对象. 代理和存根直接使用RPC. 这里的RPC是经过了扩展的RPC, 称为ORPC. 在ORPC中, 调用请求和返回结果要经过列集和散集的过程. 其定义如下.

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

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

接口指针的列集过程是由COM库函数CoMarshalInterface完成的: MEOW FLAGS IID STD FLAGS cPublicRefs OXID (Object Exporter ID) OID (Object ID) IPID (Interface Pointer ID) cch secOffset Host Addresses Security PackageInfo 签名符号 标准/自定义列集方式 被列集的接口IID 与标准列集有关的标志 引用计数 对象引出标识符 对象标识符(存根管理器) 接口指针标识符(接口存根) 字符数 安全信息偏移 其中OXID代表了对象的运行环境(套间). 代理需要使用此OXID来解析成网络或者IPC(进程间通讯)的地址,以便与对象的套间进行联系. OXID的解析工作由OXID解析器(OXID Resolver, OR)完成. OR是RPCSS服务的一部分. 接口指针的列集过程是由COM库函数CoMarshalInterface完成的:

HRESULT CoMarshalInterface( IStream *pStm, //列集数据的存放位置,是一个流.底层介质可以是磁盘,内存,或自定义的介质. 见结构化存储. REFIID riid, //列集指针的类型 IUnknown *pUnk, //列集指针,当然它应该是riid类型的. DWORD dwDestContext, //目标环境. void *long pvDestContext, //保留. DWORD mshlflags //常规列集还是表格列集(写到一个全局的接口表中,可以被多次散集) ); 散集过程由函数CoUnmarshalInterface完成 HRESULT CoUnmarshalInterface( IStream *pStm, //包含有列集内容的流 REFIID riid, // 散集指针类型 void * * ppvObj //存放散集指针的位置 一般而言,除非在进程内(而且套间类型相吻合),散集的接口不是原来的接口本身,而是一个代理.

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 Representation,Web服务使用XML)。 标准列集的通讯机制如下图:

标准列集的proxy和stub结构 客户进程 代理对象 组件进程 ITF1 客户程序 ITF2 ITF n 代理 管理器 IRpcChannelBuffer 系统 RPC 组件对象 存根代码 存根 IRpcProxyBuffer IRpcStubBuffer 通道 标准列集的proxy和stub结构

3.2 存根 当CoMarshalInterface第一次确定对象希望使用标准列集时, 就创建一个特殊的COM对象: “存根管理器”. (Stub Manager). 存根管理器与COM对象一一对应, 被对象标识符OID标识(见接口的列集数据图). 并且拥有一个对COM对象的引用.可以理解为一个进程内的客户. 存根管理器并不知道如何处理ORPC请求.它针对每个COM接口管理一个“接口存根”对象(interface stub).接口存根是用IPID来标识的. 接口存根知道关于这个接口的所有细节,它知道如何把ORPC请求消息中出现的所有[in]参数都散集出来,并且调用实际对象中的方法,然后把HRESULT结果和所有[out]参数列集到ORPC相应消息中去. 接口存根也有一个对COM对象的引用.

接口存根实现IRpcStubBuffer接口 class IRpcStubBuffer : public IUnknown { HRESULT Connect(IUnknown *pUnkServer) = 0; //把接口存根与目标COM对象联系起来 void Disconnect() = 0; //释放对象 HRESULT Invoke(RPCOLEMESSAGE *pMessage, 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; };

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

每个接口代理实现IRpcProxyBuffer接口. class IRpcProxyBuffer : public IUnknown {HRESULT Connect(IRpcChannelBuffer *pRpcChannelBuffer) = 0; void Disconnect() = 0; }; 接口代理管理器通过这个接口把接口代理与RPC通道连接起来,Connect方法把RPC通道保存起来 接口代理接到方法请求后,通过IRpcChannelBuffer接口的GetBuffer和SendReceive方法处理远程方法调用

3.4 接口列集器 接口代理和接口存根分别由代理管理器和存根管理器创建.它们共享同一个CLSID. 包含两个分叉实现的实体称为接口列集器(Interface marshaler). 接口列集器的类厂没有实现接口IClassFactory (有一个成员函数CreateInstance,以创建对应的COM对象) ,相反,它实现了接口 IPSFactoryBuffer. [ uuid(D5F569D0-593B-101A-B569-08002B2DBF7A),local,object ] interface IPSFactoryBuffer : IUnknown { HRESULT CreateProxy( [in] IUnknown *pUnkOuter, // 代理管理器指针 [in] REFIID riid, //请求的远程接口指针的IID [out] IRpcProxyBuffer **ppProxy, //输出接口代理指针 [out] void **ppv ); // 远程接口指针 HRESULT CreateStub ( [in] REFIID riid, // 请求的远程接口指针IID [in] IUnknown *pUnkServer, // 实际对象指针 [out] IRpcStubBuffer **ppStub ); }// 输出接口存根指针 接口列集器的CLSID存放在注册表中.

3.5 ORPC 通道 为了使用ORPC通道,COM提供了一个通道(channel)对象, 通道对象封装了ORPC的功能,它实现了接口IRpcChannelBuffer. typedef struct tagRPCOLEMESSAGE { void *reserved1;  unsigned long     dataRepresentation; // endian/ebcdic 编码方式 void *Buffer; // 载荷 ULONG cbBuffer; //载荷长度 ULONG iMethod; // 方法 void *reserved2[5]; ULONG rpcFlags; } RPCOLEMESSAGE; //ORPC消息的表示 class IRpcChannelBuffer : 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 IsConnected() = 0; };

4 标准列集的实现 COM已经提供了缺省的代理对象、存根管理器以及RPC通道 4 标准列集的实现 COM已经提供了缺省的代理对象、存根管理器以及RPC通道 我们只需实现每一个接口的代理/存根组件。参数和返回值的数据类型是关键。 首先使用IDL语言描述接口 编写IDL文件。产生dictionary.idl MIDL.exe是Win32SDK提供的工具。它能编译idl文档以产生以下代码:命令行: midl dictionary.idl 则产生下面的文件: dictionary.h —— 包含接口说明的头文件,可用于C或者C++语言; dictionary_p.c —— 该C文件实现了接口IDictionary的代理和存根; dictionary_i.c —— 该C文件定义了IDL文件中用到的所有全局描述符GUID,包括接口描述符; dlldata.c —— 该C文件包含代理/存根程序的入口函数以及代理类厂所需要的数据结构等。(DllGetClassObject等函数)

准备一个DEF文件 LIBRARY MyLib DESCRIPTION 'IDictionary Interface Proxy/Stub DLL' EXPORTS DllGetClassObject @1 PRIVATE DllCanUnloadNow @2 PRIVATE GetProxyDllInfo @3 PRIVATE DllRegisterServer @4 PRIVATE DllUnregisterServer @5 PRIVATE 创建一个空的 win32 dll工程 加入以上5个文件 project-》settings-》C/C++-》preprocessor definitions-》REGISTER_PROXY_DLL project-》settings-》Link-》object/library modules -》uuid.lib rpcrt4.lib 以上4,5,6 也可以编写一个MAKE文件在编译选项中加入REGISTER_PROXY_DLL连接选项中加入rpcrt4.lib、uuid.lib来完成 编译,注册。(代理与存根都是DLL,不要与进程外对象混淆) 在实际的编程工作中往往并不这样进行处理。因为集成开发环境已经提供了对IDL文件的编译支持。IDE可以启动MIDL对IDL进行编译。不需手工编写makefile。并且可以把代理存根和可执行代码编译在一起。

5. 自定义列集 为了性能的原因,我们有可能使用自定义列集.接口指针经过自定义列集后的数据流结构如下: MEOW FLAGS IID CLSID cb data 签名符号 标准/自定义列集方式 被列集的接口IID 自定义代理的CLSID 自定义列集数据的字节数 自定义列集数据 一个对象如果实现了IMarshal,则表明它希望使用自定义列集法.

5.1 IMarshal接口 IMashal接口是使用自定义列集或标准列集的标志: class IMarshal : public IUnknown { HRESULT GetUnmarshalClass( ...) = 0; //获取自定义代理的CLSID, 由CoMashalInterface调用. HRESULT GetMarshalSizeMax(...) = 0; //获取自定义对象引用的大小 由CoGetMarshalSizeMax调用 HRESULT MarshalInterface( ...) = 0; //对接口进行列集,写入流中 由CoMarshalInterface调用 HRESULT UnmarshalInterface(...) = 0; //从流中散集出接口来 由CoUnmarshalInterface调用 HRESULT DisconnectObject(...) = 0; //关闭连接 由CoDisconnectObject调用 HRESULT ReleaseMarshalData(...) = 0; //释放列集数据 由CoReleaseMarshalData调用. };

列集过程(第一次)发生在对象进程中 首先向对象查询是否实现了IMarshal接口,如果实现了,则调用其GetUnmarshalClass成员函数获取代理对象的CLSID (如果对象没有实现IMarshal接口,则指定使用COM提供的缺省代理对象,其CLSID为CLSID_StdMarshal,这是标准列集的过程 )。 调用GetMarshalSizeMax函数确定列集数据包最大可能的大小值,并分配一定的空间。 调用MarshalInterface成员函数建立列集数据包。 散集过程(第一次)发生在客户进程中 从stream中读出proxy的CLSID 根据CLSID创建一个proxy 获取proxy的IMarshal接口指针 调用IMarshal::UnmarshalInterface,把stream中的数据传给proxy,proxy根据这些数据建立起它与对象之间的连接,并返回客户请求的接口指针

自定义列集的要点 对象必须实现IMarshal接口 代理对象也必须实现IMarshal接口,并且代理对象与进程外对象之间协作 代理对象必须负责所有接口的跨进程操作 典型用途:提高跨进程调用的效率,使用缓存状态等优化技术

5.2 自定义列集例子 假定客户已经建立了它与类厂之间的连接,也就是说它通过CoGetClassObject获得了类厂的接口指针 5.2 自定义列集例子 假定客户已经建立了它与类厂之间的连接,也就是说它通过CoGetClassObject获得了类厂的接口指针 客户要通过类厂创建另一个COM对象,而这个对象使用custom marshaling 客户调用IClassFactory::CreateInstance创建对象,并返回对象的接口指针 注意这里类厂对象使用的标准列集, COM对象使用的自定义列集.

通过类厂建立代理对象和组件对象自定义列集过程