玩技术,Geeker
一个原创技术文章分享网站

COM编程——EXE中的服务器

前言

我们之前总结的很多东西,甚至是提供的DEMO程序都是基于进程中服务器的,也就是生成的COM组件的形式为DLL。但是,有的时候,我们可能需要使组件是以EXE的形式发布。这样就会出现另一个问题,不同EXE中的组件和客户将在不同的进程中运行,这是因为每一个EXE都有其自己的进程空间。这样一来客户和组件之间的交互就会跨越进程边界了。

不同的进程

由于每一个EXE文件都将在不同的进程中运行,而每一个进程都有其自己的进程空间。一个进程空间中的逻辑地址0x00002525所对应的物理地址将不同于另外一个进程中同一逻辑地址所对应的物理地址。因此若一个进程将地址0x00002525传给另外一个进程,后者用此地址所访问到的内存单元将不是前一进程所希望的。

同每一个EXE都有其自己的进程不同,DLL将被映射到链接它们的EXE文件的进程空间中。由于这个原因,DLL也被称作是进程中服务器,而EXE则被称作是进程外服务器。在某些情况下,EXE也被称作是本地服务器以同另外一种类型的进程外服务器“远程服务器”相区别。远程服务器指的是运行于另外一个不同的机器上的进程外服务器。

对于进程外服务器,跨越进程边界的接口,我们需要考虑如下一些条件:

  1. 一个进程需要能够调用另外一个进程中的函数;
  2. 一个进程需要能够将数据传递给另外一个进程;
  3. 客户无需关心它所访问的服务器是进程内服务器还是进程外服务器。

本地过程调用

对于进程间的通信有几种不同的方法,如动态数据交换,命名管道以及共享内存等。COM所用的方法则为本地过程调用(LPC)。LPC是同一机器上不同进程间通信的一种方法,它是基于远程过程调用(RPC)的用于单机上进程间通信的专利技术。LPC是由操作系统实现的,由于操作系统知道同一个进程逻辑地址空间相对应的物理地址,因此操作系统可以调用任意进程中的任意函数。

调整

调用EXE中的函数只是第一步。另外我们还需要一种方法将函数调用的参数从一个进程的地址空间中传到另外一个进程的地址空间中。这种方法被称为“调整”。

若两个进程都在同一台机器上,则调整过程将是相当直接的:只需要将参数数据从一个进程的地址空间复制到另外一个进程的地址空间就可以了。若参与参数传递的两个进程在不同的地址空间中,那么考虑到不同机器在数据表示方面的不同,如整数的字节顺序可能会不同,必须将参数数据转换成标准的格式。

为对组件进行调整,可以实现一个名为IMarshal的接口。在COM创建组件的过程中,它将查询组件的IMarshal接口。然后它将调用IMarshal的成员函数以在调用函数的前后调整或反调整有关的参数。COM库中实现了一个可以供大多数接口使用的IMarshal的标准版本。在需要对性能进程优化时,可以对IMarshal进行定制。

代理/残根DLL

上面也说了,客户不会去关心的组件是进程中的还是进程外的;最终实现时,客户应该可以按照相同的方式与进程中、本地及远程组件进行通信。显然,若客户必须自己处理LPC的问题,这一目标将无法实现。为达到这一目的,COM使用了一个非常简单的方法。

在实际编程时,我们在使用Win32函数时,它们都用到了LPC。当调用Win32函数时,系统实现上将调用一个DLL中的函数,而此函数将通过LPC调用Windows中的实际代码。这种结构可以将用户进程同Windows代码隔离开。由于不同的进程具有不同的地址空间,因此用户程序不可能对操作系统造成破坏。

COM使用的结构与这个类似。客户将同一个模仿组件的DLL进行通信。这个DLL可以为客户完成参数的调整及LPC调用。在COM中,此DLL(也是一个组件)被称作是一个代理。

用COM的术语来说,一个代理就是同另外一个组件行为相同的组件。代理必须是DLL形式的,因为它们需要访问客户进程的地址空间以便对传给接口函数的数据进行调整。对数据的调整只完成了任务的一半,组件还需要一个被称作是残根的DLL,以对从客户传来的数据进行反调整。残根也将对传回给客户的数据进行调整。

说了这么多,感觉很复杂,我们要去实现代理DLL,残根DLL;但是在实际编程中,这一切都不用我们去实现的。之后的文章会告诉你是谁帮助了我们去完成了这些复杂的动作。

总结

这里说了这么多理论的东西,我一直都认为,理论是实践的基础;任何实践都实践都是建立在理论之上的。理解这里的理论,对后面的学习将会有很大的帮助的。

2014年2月17日 于大连,东软。

打赏

未经允许不得转载:果冻想 » COM编程——EXE中的服务器

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

在这里玩技术,享受技术带来的疯狂

捐赠名单关于果冻