[转载] Read Events 的奥秘
转自:http://www.gz9f.com/bbs/dispbbs.asp?boardID=1&ID=273673&page=2作者:古金楠
我的上一封帖子《小聊致命错误C0000005》,自己主观来判断,至少有80%的网友没有足够的耐心完整地阅读之。这次,我吸取了教训,将本贴的中心思想写在文章的开始:
VFP 3.0 的 Read Events 命令机制,实际上是为 FoxPro2.5/2.6 for Windows 程序员提供一种选择权:
是通过自己的 Do While + Do Case 语句结构 所构成的 基于事件响应的机制来编写应用程序,还是将消息循环与事件响应 通过 Read Events 语句 来交给VFP和Windows 自动去处理。
本贴正文开始……
以下是引用qyqmhh在2005-3-18 17:54:06的发言:
大家都知道,运行vfp表单后,必须紧跟read event语句,否则编译后就是一闪而过, 可是我就是不明白,vfp为什么要这样设计。其他语言都不需要这么做的。 欢迎大家深入讨论!!!
问这个问题的人是真正具备程序员思想境界的人,将来毕竟是位了不起的高人。因此我愿意花时间来详细解释。将来你成为大师了,甭多,送给我辆奔驰,我就知足了:)
这件事说来话长。
我将首先告诉你Read Events命令在C代码中是如何做到的(VFP早期版本是用C语言编写的,后期版本逐渐增加了些C++代码);在本贴的后面,将向你详细解释VFP开发小组为什么要这样设计。
解释VFP中的Read Events命令机制一直以来是个难题,就像数学中证明1+1=2一样。因为多数VFP程序员不了解 C语言、和Windows消息机制。如果很不幸,你恰好就是这样的话,那么看本贴的时候一直要硬着头皮读下去,千万不要中途放弃。
Read Events在底层是通过调用Windows API 函数 GetMessage 和 DispatchMessage来实现的,当你在VFP中写下Read Events命令时,在程序运行期间,这段代码将被解释器中的如下C代码来解释:
While(GetMessage(&MSG,<其它参数>)){
TranslateMessage(&MSG);
DispatchMessage(&MSG);
}
你可以通过从VFPxR.DLL导出Windows API函数的方式看到上面的API函数,它们的宿主库是USER32.DLL。
C for Windows 程序员都知道上面代码的涵义,该While语句用于开始响应Windows消息循环,参数MSG是个结构体(C语言中的结构体实际上就是VFP中的数组),该结构体的第一个成员记录了一个窗口的句柄,Windows操作系统会通过该句柄查找相对应窗口的窗体过程函数。
如果你是个 C 程序员的话,你不妨作个试验:在VC中随便打开一个已存在的工程,除控制台应用程序外,每个有Windows界面的WIN32应用程序都存在上面的C代码(对于MFC程序而言,上面的代码被CWinApp类的成员函数Run()封装了起来),请找到这些代码,然后将其注释掉,重新编译EXE。
再运行后,你将会发现VFP经典的“一闪而过”的问题在VC中重现了!按下组合键Ctrl+Alt+Delete打开Windows任务管理器,你会发现该应用程序实际上仍在运行中,这种症状真的和缺少Read Events命令的VFP应用程序一摸一样!
VFP中的CLEAR EVENTS命令,在底层是调用Windows API函数PostQuitMessage来实现的,用于结束Windows窗口消息循环。
如果上面的解释你看不懂,没有关系,你只需要知道一点就可以了:对于所有需要Windows界面的应用程序而言,都需要有响应Windows消息循环的代码。
接下来该解释为什么VFP3.0开发小组要这样设计了。
的确,对于幸运的VB、Delphi程序员来讲,他们不存在这样的烦恼。因为应用程序底层当遇到窗体对象时,便会自动加上响应消息循环的代码。那么为什么惟独VFP要这样“个色”呢?
如果你了解FoxPro的历史,就不难想象其中的奥秘。
我们知道,当年所诞生的Delphi和VB,就像时下的C#一样,不存在历史代码兼容性的负担。VB和Basic一点也不一样,但VFP就不同了。从面向过程的FoxPro for Dos到面向对象的VFP3.0之间,存在两个过渡的版本FoxPro2.5/2.6 for Windows。
在折中性的版本for WIN2.5/2.6中,如果想将应用程序设计成基于事件响应的模式,你就必须这样设计你的代码:
DEFINE WINDOW ……
ACTIVE WINDOW ……
DO WHILE .T.
DO CASE
CASE 鼠标滑动
则……
CASE 鼠标左键单击
则……
CASE 鼠标左键双击
则……
CASE INKEY(0)
则……
CASE INKEY(27)
则…………
(当然,上述代码在for DOS2.5/2.6版本中同样有效。)
在你打开VFP帮助文件,找到DEFINE WINDOW命令时,你会惊讶地发现该命令甚至比DEFINE CLASS AS FORM 命令还要丰富。
当年FoxPro程序员多如牛毛,其历史遗留下来的代码不计其数。理想总要对现实进行妥协,如果换做我们是微软的决策者,那么我们当年是否也会决定兼容老版本的代码呢?
Read Events机制提供了一种灵活性,使你依旧可以按照传统的基于事件响应的方式编程(即用Do While + Do Case语句来代替Read Events),这就实现了VFP3.0开发小组的诺言:从老版本升级到3.0,您不用修改一行代码。
换句话说:VFP3.0的Read Events命令机制,实际上是为FoxPro2.5/2.6 for Windows程序员提供一种选择权:是通过自己的Do While + Do Case 语句结构所构成的基于事件响应的机制来编写应用程序,还是将消息循环与事件响应通过Read Events语句来交给VFP和Windows自动去处理。
这样一来,Read Events就成了VFP的传统,就像当年3.0需要兼容老版本代码一样,现在的8.0/9.0新版,反而要考虑兼容Read Events机制了 :)