肖 巍
(长春师范大学传媒学院,吉林长春 130032)
VCL Framework窗口消息机制研究
肖 巍
(长春师范大学传媒学院,吉林长春 130032)
本文介绍了传统Windows消息机制及处理过程,重点阐述了对VCL Framework消息机制的研究,对VCL Framework窗口消息封装机制、窗口消息分派机制的实现方法和实现技术进行了详细的论述。
VCL Framework;消息机制;消息封装;消息分派
VCL(Visual Component Library) Framework是一种高效的应用程序开发框架,提供了对大多数Windows消息的处理机制。程序开发人员如果想要编写自己的组件或更加灵活地运用现有的组件,使程序的功能更加强大灵活,就必须对VCL Framework的窗口消息机制有深入的理解。封装窗口消息,并且结合VCL的组件模型提供更有效的Windows程序设计风格,正是VCL Framework设计的主要使命之一。
Windows的消息系统由消息队列、消息循环和窗口过程三个部分组成。Windows定义了两种不同的消息队列,分别是系统消息对列和应用程序消息队列。系统消息队列用来储存Windows中系统和硬件触发的事件,应用程序消息队列则用来储存窗口触发的一般事件。程序员一般不需要直接处理Windows消息队列。Windows系统本身会帮助应用程序来管理消息队列,消息队列是以线程(Thread)来分组的,一般情况下每个线程都有自己的消息队列。
消息循环往往是Windows应用程序的核心,因为消息循环使一个应用程序能够响应外部的事件,消息循环的任务就是从应用程序消息队列中检索消息,把消息传递给适当的窗口,然后从消息队列中检索下一条消息,再分派给适当的窗口,依次进行。一般形式如下:
while GetMessage(msg, 0, 0, 0) do
{
TranslateMessage(msg);
DispatchMessage(msg);
}
每个窗口都有一个窗口过程来接收传递来的消息,它的任务就是获取消息然后响应它。窗体过程实际上是一个回调函数。所谓回调函数,就是由Windows操作系统或外部程序调用的函数。回调函数一般都有规定的参数格式,以地址方式传递给调用者。窗口过程中是Windows操作系统调用了,在一个窗口创建的时候,在分配窗体句柄的时候就需要传入回调函数地址。其形式如下:
Function WindowProc(Window:HWnd ; AMsg:UINT; WParam:WPARAM; LParam : LPARAM): LRESULT; stdcall;export;
传统的窗口回调程序设计有诸多缺点:所有的窗口过程结构都非常相似,程序员不断重复撰写类似代码;不能复用,生产效率低下;使用Case逐一判断窗口消息类别的程序代码编译出来后执行效率低下;需要程序员非常了解窗口消息,增加了开发难度,降低了生产力等。
VCL Framework不但实现了窗口消息封装和窗口消息分派,也使用了VCL类来封装窗口控件,让每一个VCL封装类都能够在其中实现处理窗口消息的工作,而不需要像传统Windows程序设计一样在一个冗长繁杂的窗口回调函数中撰写所有的程序代码。
2.1 VCL Framework的窗口消息封装机制
VCL Framework的消息封装和处理流程与窗口消息种类、VCL消息种类、方法调用惯例以及方法种类有着密切的关系。 VCL Framework中处理的消息种类大体可分为窗口消息和VCL内部消息,如表1所示。
表1 VCL Framework中处理消息种类
调用惯例(Calling Convention)影响执行效率、参数的传递方式以及栈清除方式,表2列出了最常使用的调用惯例对于参数和栈的处理方式。
表2 调用惯例对于参数和栈的处理方式
窗口回调函数使用pascal调用惯例,而VCL组件的事件处理函数却使用register调用惯例。因此,当VCL Framework从窗口回调函数在分派消息到VCL组件的消息处理函数时,必须把调用惯例从pascal转换为register调用惯例,才能够让程序正确执行下去。VCL Framework在消息分派时,选择实现的消息处理函数大都偏向使用动态方法,因为可以大幅节省VCL组件使用的空间。在VCL组件实现类中,可以定义类似下面处理特定窗口消息的处理函数,其中以WM开头的方法是直接处理特定窗口消息的函数:
Procedure WMLButtonUp(var Message:TWMLButtonUp);message WM_LBUTTONUP
而以CM开头的方法则是处理VCL Framework定义的特定消息处理函数:
Procedure CMParentFontChanged(var M:TMessage);message CM_PARENTFONTCHANGED
2.2 VCL Framework的窗口消息分派机制
VCL Framework使用虚拟方法来解决分派窗口消息的机制,只要调用一个标准的虚拟方法,然后不同的VCL封装类覆写此虚拟方法,就可以被VCL的分配消息机制调用并传递窗口消息作为此虚拟方法的参数。
TWinControl是所有VCL Framework中封装窗口控制的根类,在TWinControl类中定义了虚拟方法WndProc,WndProc接受代表窗口消息的TMessage数据结构作为参数:
TWinControl=class(TObject)
Procedure WndProc(var Message:TMessage);virtual;
End;
在TWinControl类的派生类中,封装了窗口按钮控件的TButton类可以重载WndProc虚拟方法并且在其中处理发生在按钮控件中的触发事件:
TButton=class(TWinControl)
Procedure WndProc(var Message:TMessage);override;
End;
当VCL Framework找到了相应的目标VCL组件后,就可以正确地分派窗口消息给封装窗口控件的VCL组件了:
Var
aControl:TWinControl;
Begin
GetWindowMessage(Message);
aControl:=GetTargetControl(Message);
aControl.WndProc(Message);
End;
GetWindowMessage可根据Windows系统触发的事件转换为TMessage对象,最后以GetTargetControl取得的TWinControl组件以多态的机制调用到VCL组件覆写的窗口消息处理函数。
在传统的Windows程序设计中,Windows调用一般的回调函数,指C语言的函数类型。在面向对象程序语言中,当调用对象的方法时,除了目标方法接受的参数之外,调用者还需要传递一个额外的隐藏参数,即Object Pascal语言的Self。在传统的Windows回调函数中先找到目的VCL对象,主动把Self压入栈中,再压入对象方法的参数,最后调用对象方法,即可实现调用回调函数改变成调用对象方法。为了提高执行效率,VCL Framework使用Register调用惯例,实际上是把Self压入EAX寄存器中。VCL Framework的回调函数InitWndProc在执行完上述的转换动作后,会调用StdWndProc函数,再由StdWndProc分配消息给对象方法。StdWndProc是VCL Framework中分派消息的枢纽,执行次数非常频繁,需要很高的执行速度,它是完全使用汇编语言编写的,位于InitWndProc和VCL组件之间的提供窗口消息分派和转换的通道。
当VCL Framework把窗口消息分派到VCL组件的消息处理函数WndProc之后,真正让窗口消息和VCL组件的事件处理函数串联起来的枢纽是TObject的消息分派服务虚拟方法Dispatch。该虚拟方法使用两种方式来分派消息,第一种是分派能够被VCL组件事件处理函数处理的消息,对于这种消息Dispatch会在目标VCL组件的动态数据表中搜寻拥有相同消息ID的动态方法,找到后就直接调用相应的VCL事件处理函数来处理触发的消息。第二种是如果Dispatch对于触发的消息不需要分派,那么Dispatch就会调用同属TObject消息分派服务中的DefaultHandler虚拟方法来处理,程序员可以直接使用此方法,也可以覆写此虚拟方法,由程序员自己实现处理Dispatch不分派的消息,使VCL组件具有更好的灵活性和可扩展性。
本文介绍了传统Windows消息机制及处理过程,重点阐述了对VCL Framework消息机制的研究,通过对VCL Framework窗口消息封装机制和分派机制实现方法和实现技术的梳理,以及与传统方式的对比,对VCL Framework在窗口消息处理机制上的先进性和高效性有了更深的了解,对日后应用VCL Framework开发出更加强大、灵活的应用程序具有一定的指导意义。
[1]李维.深入核心——Inside VCL架构剖析[M].北京:电子工业出版社,2003.
[2]刘文韬,徐学洲.Delphi环境下Windows消息机制的应用分析[J].电子科技,2005(9):17-20.
[3]张利兵,陈定方.Windows消息机制及其在Delphi中的应用[J].交通与计算机,2004(3):108-110.
[4]王亚,宋铭利.Windows消息机制研究[J].现代计算机:下半月版,2008(2):70-71.
2014-09-06
肖 巍(1975- ),男,吉林长春人,长春师范大学传媒学院副教授,从事图像处理与模式识别、自动识别技术、嵌入式系统研究。
TP311
A
2095-7602(2014)06-0052-03