封送处理详细信息

如果使用标准封送,COM 将处理此处介绍的所有详细信息。 但是,程序员很少需要这些详细信息,并且对基础信息感兴趣。 封送是打包和解压缩参数的过程,因此可以进行远程过程调用。

不同的参数类型以不同的方式封送。 例如,封送整数参数只需将值复制到消息缓冲区。 (但即使如此简单,还会存在跨计算机调用时要处理的字节排序等问题。但是,封送数组是一个更复杂的过程。 数组成员按特定顺序复制,以便另一方可以完全重新构造数组。 封送指针时,指针指向的数据将按照处理结构中的嵌套指针的规则和约定进行复制。 可通过唯一函数处理每个参数类型的封送。

使用标准封送时,代理和存根是接口的系统范围资源,它们通过标准协议与通道交互。 标准封送可由标准 COM 定义的接口和自定义接口使用,如下所示:

  • 对于大多数 COM 接口,标准封送的代理和存根是进程内组件对象,这些对象从 COM 在 Ole32.dll 中提供的系统级 DLL 加载。
  • 对于自定义接口,标准封送的代理和存根由接口设计器生成,通常使用 MIDL 生成。 这些代理和存根在注册表中静态配置,因此任何潜在客户端都可以跨进程边界使用自定义接口。 这些代理和存根从通过系统注册表定位的 DLL,使用其封送的自定义接口的接口 ID (IID) 加载。
  • 如果不使用 MIDL 为自定义接口生成代理和存根,可以改为生成类型库,并且系统提供的类型库驱动的封送引擎将封送接口。

作为标准封送的替代方法,接口(标准或自定义)可以使用自定义封送。 通过自定义封送,对象可在运行时动态实现所支持的每个接口的代理。 对于任何给定的接口,对象可以选择 COM 提供的标准封送或自定义封送。 此选择由对象基于接口进行。 为给定接口做出选择后,该接口在对象的生存期内仍有效。 但是,对象上的一个接口可以使用自定义封送,而另一个接口则使用标准封送。

自定义封送与其实现对象本就不同。 它使用由对象实现的代理,并在运行时按需提供给系统。 实现自定义封送的对象必须实现 IMarshal 接口,而支持标准封送的对象则不实现。

如果决定编写自定义接口,则必须提供封送支持。 通常,将为设计的接口提供标准封送 DLL。 可以创建代理/存根代码和代理/存根 DLL,也可以创建 COM 用于执行数据驱动封送的类型库(使用类型库中的数据)。

客户端在另一个进程中调用对象中的接口方法涉及多个组件的合作。 标准代理是一段特定于接口的代码,其驻留在客户端的进程空间中并准备用于传输的接口参数。 以在接收过程中重新创建和理解的方式进行打包或封送。 标准存根(也即一段特定于接口的代码)驻留在服务器的进程空间中并撤销代理工作。 存根解封或拆收发送的参数并将其转发到对象应用程序。 它还将回复信息打包发回客户端。

注意

相比 COM,读者更熟悉 RPC,可用于查看客户端存根和服务器存根术语。 这些术语类似于代理和存根。

 

进程间通信的组件

下图显示了所涉及组件之间的通信流。 在进程边界的客户端,客户端的方法调用通过代理,然后进入 COM 库中的通道。 通道将包含封送参数的缓冲区发送到 RPC 运行时库,随后传输到进程边界。 RPC 运行时库和 COM 库分别位于进程的两端。 通道和 RPC 运行时库之间的区别是此实现的特征,不属于 COM 客户端/服务器对象的编程模型或概念模型。 COM 服务器只能看到代理或存根,并能间接地看到通道。 将来的实现可使用通道下方的不同层或不使用层。

Diagram that shows the Client.exe and Server.exe flows on each side fo the Process Boundary.

渠道

对象间通信

Microsoft RPC

代理

存根