现在的位置: 首页 > 综合 > 正文

深入 BCB理解 VCL的消息机制

2013年04月23日 ⁄ 综合 ⁄ 共 2943字 ⁄ 字号 评论关闭

深入 BCB理解 VCL的消息机制
Tommy <nag_amigo@yahoo.com.cn>

TApplication、TScreen和TForm 构成了所有BCB风格的 Win32 GUI程序的脊梁,他们控制
着您程序的行为。TApplication类提供的属性和方法封装了标准Windows程序的行为。
TApplication表现了在Windows操作系统中创建、运行、支持和销毁应用程序的基本原
理。因此,TApplication大大简化了开发者和Windows环境之间的接口。这正是 BCB的
RAD特性。

TApplication封装的标准Windows行为大致包括如下几部分:
1> Windows 消息处理
2> 上下文关联的在线帮助
3> 菜单的快捷键和键盘事件处理
4> 异常处理
5> 管理由操作系统定义的程序基础部分,如:MainWindow 主窗口、 WindowClass 窗
口类 等。

一般情况下,BCB会为每个程序自动生成一个TApplication类的实例。这部分源码可以
在yourproject.cpp文件中见到(这里假定您的工程名称就叫yourproject.bpr)。
 
当然TApplication是不可见的,他总是在您的Form背后默默的控制着您的程序的行为。
但也不是找不到蛛丝马迹。如果您新建一个程序(New Application),然后不作任何改
动,编译运行的话,你会发现程序窗体的Caption是Form1,但在Windows的状态条上的
Caption确写着project1的字样。这就是 TApplication存在的证据。当然,这只是一种
臆测,实战的方法应该打开 BCB附带的WinSight来查看系统的进程。您可以清楚的看到
TApplication类的存在,他的大小是0(隐藏的嘛),然后才是 TForm1类。
 
好了,既然 TApplication封装了消息处理的内容。我们就研究一下 TApplication的实际
动作吧。实际上消息到达BCB程序时,最先得到它们的就是TApplication对象。经由
TApplication之后,才传递给Form的。以前的方法都是重载TForm的方法,显然要比本
文所提到的方法要晚一些收到消息。对您来说,是不是希望在第一时间收到消息并处理
它们呢?
 
要清楚的知道TApplication的处理机制还是深入 VCL源码。首先看一看最最普通的一段
代码吧。
#include
#pragma hdrstop
USEFORM("Unit1.cpp", Form1);
//--------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
// 初始化Application
Application->Initialize();
// 创建主窗口,并显示
Application->CreateForm(__classid(TForm1), &Form1);
// 进入消息循环,直到程序退出
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
 
短短的几行代码就可以让您的BCB程序自如运行。因为一切都已经被VCL在后台封装好
了。Application->Run()方法进入程序的消息循环,直到程序退出。一起跟进 VCL源码
看个究竟吧。

消息由 TApplication->Run()---->TApplication->HandleMessage------->TApplication->ProcessMessage
                                                          |
                                      如果没有什么要处理的|------->TApplication->Idle 

ProcessMessage采用了一套标准的Windows API 函数
PeekMessage .... TranslateMessage;DispatchMessage。
有人说:Application->OnMessage = MyOnMessage; //不能响应 SendMessage的消息,
但是可以响应PostMessage发送的消息,也就是消息队列里的消息 
SendMessage和PostMessage最主要的区别在于发送的消息有没有通过消息队列。
原因就在这里。ProcessMessage使用了PeekMessage(Msg, 0, 0, 0, PM_REMOVE) 从消
息队列中提取消息。然后先检查是不是退出消息。不是的话,检查是否存在OnMessage
方法。如果存在就转入OnMessage处理消息。最后才将消息分发出去。
现在可以简短的总结一下VCL的消息机制了。
标准的BCB程序使用Application->Run()进入消息循环,在 Application的
ProcessMessage方法中,使用PeekMessage方法从消息队列中提取消息,并将此消息从
消息队列中移除。然后ProcessMessage 方法检查是否存在 Application->OnMessage方
法。存在则转入此方法处理消息。之后再将处理过的消息分发给程序中的各个对象。至
此,WndProc方法收到消息,并进行处理。如果有无法处理的交给重载的Dispatch方法
来处理。要是还不能处理的话,再交给父类的 Dispatch方法处理。最后 Dispatch方法实
际上将消息转入DefaultHandler方法来处理。
 
嘿嘿,实际上,你一样可以重载DefaultHandler方法来处理消息。但是太晚了一点。我
想没有人愿意最后一个处理消息吧...:-)
 
写到这里似乎可以结束了。但如果您看过上一篇的话,一定会注意到

Application->HookMainWindow方法。这又是怎么一回事呢?
 
如果您打算使用Application->OnMessage来捕获所有发送至您的应用程序的消息的话,
您大概要失望了。原因已经讲过,它无法捕获使用SendMessage直接发送给窗口的消
息,因为这不通过消息队列。您也许会说我可以直接重载 TApplication的WndProc方
法。呵呵,不可以。因为TApplication的 WndProc方法被Borland申明为静态的,从而无
法重载。显而易见,这么做的原因很可能是Borland担心其所带来的副作用。那该如何
是好呢?

WndProc方法一开始先调用HookMainWindow挂钩的自定义消息处理方法,然后再调用缺
省过程处理消息。这样使用 HookMainWindow就可以在WndProc中间接加入自己的消息处
理方法。使用这个方法响应 SendMessage发送来的消息很管用。最后提醒一下,使用
HookMainWindow挂钩之后一定要对应的调用 UnhookMainWindow卸载钩子程序
                 

抱歉!评论已关闭.