第 20 页
SWT: 深入内幕之消息机制探秘
作者:Treenode
于 2006-6-3
前言
作为一个专注于 C/S 方面开发的程序员,我一直对“面向对象的编程框架如何与 Windows 操作系统
的消息机制打交道”这个问题有着相当大的兴趣。读者想必知道,象 MFC、VCL 和 SWT 这样的类
库在实现界面处理的时候,有几个主要问题是不得不考虑的。首先是如何为窗口和控件这样的界面
组件以面向对象方式进行包装。这一方面可以说没多少技术上的难题;从一般意义上讲,不过是把
HWND 作为第一个参数的函数分类整理一下而已。当 然 ,具体作起来还是有不少东西需要认真考虑,
只是这些问题多半是在设计的层面,考虑包装是否完善、维护和扩展起来是否方便等等;实现上基
本上就没多少需要克服的技术障碍了。而另一方面——即如何处理系统消息机制,则是一个颇费脑
筋的问题了。其中最大的难点之一,就是 Windows 的消息系统依赖于窗口过程(术语叫做 Window
Procedure),而这个窗口过程却是一个非面向对象的、普通的全局函数,它完全不理解对象是什么;
可是而为了让整个程序 OO 起来,你还非得让它去操纵对象不可。因此,如何将窗口过程用面向对
象的方法完美的封装起来,就成为各种类库面临的最大挑战之一。当然,这也理所当然的成为各个
开发小组展示自身功力的绝好舞台。
据我所知,在此一问题上,不同的类库使用了不同的解决方案。较早的 MFC 使用了窗口查找表的
技术,即为每个窗口和对应的窗口过程建立一个映射;需要处理消息的时候,则是映射表中找到窗
口所对应的过程,并调用之。这样会带来几个问题。首先是每次进行查表势必浪费时间,为 此 MFC
不惜在关键处使用 Cache 映射和内联汇编的方法以提高效率。第二个问题:映射表是和线程相关联
的,如 果 你将窗口传递给另外一个线程,MFC 无法在该线程中找到窗口的映射项,也就不知该如何
是好,于是只好出错。我已经在很多地方看到有人问跨线程传递窗口指针的疑问,多半都是因为不
理解 MFC 的消息处理机制。正因为如此,MFC 的使用者必须强制遵守一些调用方面的约定,否则
会出现很多莫名其妙的错误,这无疑是框架不够友好的表现。而稍晚出现的 VCL 和 ATL 则使用了
一种比较巧妙的 Thunk 技术,利用函数调用过程中使用堆栈的原理,巧妙的将对象指针“暗度陈仓”
地偷偷传递进去,并通过一些内存中的“小动作”越过了通常的处理机制。这样做的好处是节省了
额外维护映射表的开销,速度相当快,同时也不存在线程传递的问题。当然,这个过程因为大量使
用汇编,而且需要对函数调用的底层机制有深刻的理解,所以很难为一般程序员所理解和运用。(相
应的维护起来也难度也比较高——还记得 Anders 离开 Borland 以后相当长时间没有人敢改动 Delphi
底层代码的往事吗?)
在众多框架中,SWT 算是比较年轻的一个,也是颇为独特的一个。之所以说它特殊,因为它是用
Java 编写的。我们知道,和 Windows 平台上的本地开发工具不同,Java 程序是生活在自己的虚拟机
中的,除非通过 JNI 这个后门,否则它对底下的操作系统基本上一无所知。这显然为设计者提出了
更高的挑战。那么,SWT 又是如何实现这一点的呢?非常幸运,SWT 是完全开放源代码的(当然,
MFC 和 VCL 也是开放的,不过这种开放就稍显小家子气——许多时候你必须购买昂贵的企业版才
能看到这些宝贵的源码,D 版且不论)。开放源代码为我们研究其实现扫清了障碍。
PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn