分享
 
 
 

深入VCL 理解BCB的消息机制(三)

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

New Page 1

深入VCL 理解BCB的消息机制

方法3

Written

by

CKER

方法3。RH指出的来自TApplication的方法

不用我多废话,大家都知道TApplication在BCB中的重要性。在BCB的帮助中指出: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 <vcl.h>

#pragma hdrstop

USERES("Project1.res");

USEFORM("Unit1.cpp", Form1);

//--------------------------------------------------------------

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

try

{

// 初始化Application

Application->Initialize();

// 创建主窗口,并显示[url=file:///][/url]Application->CreateForm(__classid(TForm1), &Form1);

// 进入消息循环,直到程序退出

Application->Run();

}

catch (Exception &exception)

{

Application->ShowException(&exception);

}

return 0;

}

//--------------------------------------------------------------

短短的几行代码就可以让您的BCB程序自如运行。因为一切都已经被VCL在后台封装好了。Application->Run()方法进入程序的消息循环,直到

程序退出。一起跟进VCL源码看个究竟吧。

TApplication的定义在forms.pas中。

procedure TApplication.Run;

begin

FRunning := True;

try

AddExitProc(DoneApplication);

if FMainForm <> nil then

begin

// 设置主窗口的显示属性

case CmdShow of

SW_SHOWMINNOACTIVE: FMainForm.FWindowState := wsMinimized;

SW_SHOWMAXIMIZED: MainForm.WindowState := wsMaximized;

end;

if FShowMainForm then

if FMainForm.FWindowState = wsMinimized then

Minimize else

FMainForm.Visible := True;

// 看见了吧,这里有个循环,直到Terminated属性为真退出。Terminated什么意思,就是取消,结束

repeat

HandleMessage

until Terminated;

end;

finally

FRunning := False;

end;

end;

消息处理的具体实现不在Run方法中,很显然关键在HandleMessage方法,看看这函数名字-消息处理。只有跟进HandleMessage瞧瞧喽。

procedure TApplication.HandleMessage;

var

Msg: TMsg;

begin

if not ProcessMessage(Msg) then Idle(Msg);

end;

咳,这里也不是案发现场。程序先将消息交给ProcessMessage方法处理。如果没什么要处理的,就转入Application.Idle方法『程序在空闲时调用的方法』。

呼呼,再跟进ProcessMessage方法吧。

function TApplication.ProcessMessage(var Msg: TMsg): Boolean;

var

Handled: Boolean;

begin

Result := False;

if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then

begin

Result := True;

if Msg.Message <> WM_QUIT then

begin

Handled := False;

if Assigned(FOnMessage) then FOnMessage(Msg, Handled);

if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and

not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then

begin

TranslateMessage(Msg);

DispatchMessage(Msg);

end;

end

else

FTerminate := True;

end;

end;

哎呀呀,终于有眉目了。ProcessMessage采用了一套标准的Windows API 函数 PeekMessage .... TranslateMessage;DispatchMessage。前一篇帖子RH

跟了几贴说

Application->OnMessage = MyOnMessage; //不能响应sendmessage的消息,但是可以响应postmessage发送的消息,也就是消息队列里的消息

SendMessage和PostMessage最主要的区别在于发送的消息有没有通过消息队列。

原因就在这里。ProcessMessage使用了PeekMessage(Msg, 0, 0, 0, PM_REMOVE) 从消息队列中提取消息。然后先检查是不是退出消息。不是的话,检查

是否存在OnMessage方法。如果存在就转入OnMessage处理消息。最后才将消息分发出去。

这样重载Application的OnMessage方法要比前两种方法更早得到消息,可以说是最快速的方法了吧。举个例子:

void __fastcall TForm1::MyOnMessage(tagMSG &Msg, bool &Handled)

{

TMessage Message;

switch (Msg.message)

{

case WM_KEYDOWN:

Message.Msg = Msg.message;

Message.WParam = Msg.wParam;

Message.LParam = Msg.lParam;

MessageDlg("You Pressed Key!", mtWarning, TMsgDlgButtons() << mbOK, 0);

Handled = true;

break;

}

}

void __fastcall TForm1::FormCreate(TObject *Sender)

{

Application->OnMessage = MyOnMessage;

}

现在可以简短的总结一下VCL的消息机制了。

标准的BCB程序使用Application->Run()进入消息循环,在Application的ProcessMessage方法中,使用PeekMessage方法

从消息队列中提取消息,并将此消息从消息队列中移除。然后ProcessMessage方法检查是否存在Application->OnMessage方法。存在则转入此方法

处理消息。之后再将处理过的消息分发给程序中的各个对象。至此,WndProc方法收到消息,并进行处理。如果有无法处理的交给重载的Dispatch方

法来处理。要是还不能处理的话,再交给父类的Dispatch方法处理。最后Dispatch方法实际上将消息转入DefaultHandler方法来处理。

『嘿嘿,实际上,你一样可以重载DefaultHandler方法来处理消息。但是太晚了

一点。我想没有人愿意最后一个处理消息吧...:-)』

写到这里似乎可以结束了。但如果您看过上一篇的话,一定会注意到RH的提到的Application->HookMainWindow方法。这又是怎么一回事呢?

如果您打算使用Application->OnMessage来捕获所有发送至您的应用程序的消息的话,您大概要失望了。原因已经讲过,它无法捕获使用

SendMessage直接发送给窗口的消息,因为这不通过消息队列。您也许会说我可以直接重载TApplication的WndProc方法。呵呵,不可以。因为

TApplication的WndProc方法被Borland申明为静态的,从而无法重载。显而易见,这么做的原因很可能是Borland担心其所带来的副作用。那该

如何是好呢?

查看TApplication的WndProc的pascal源码可以看到:

procedure TApplication.WndProc(var Message: TMessage);

... // 节约篇幅,此处与主题无关代码略去

begin

try

Message.Result := 0;

for I := 0 to FWindowHooks.Count - 1 do

if TWindowHook(FWindowHooks[I]^)(Message) then Exit;

... // 节约篇幅,此处与主题无关代码略去

WndProc方法一开始先调用HookMainWindow挂钩的自定义消息处理方法,然后再调用缺省过程处理消息。这样使用HookMainWindow就可以在

WndProc中间接加入自己的消息处理方法。使用这个方法响应SendMessage发送来的消息很管用。

最后提醒一下,使用HookMainWindow挂钩之后一定要对应的调用UnhookMainWindow卸载钩子程序。给个例子:

void __fastcall TForm1::FormCreate(TObject *Sender)

{

Application->HookMainWindow(AppHookFunc);

}

//---------------------------------------------------------------------------

bool __fastcall TForm1::AppHookFunc(TMessage &Message)

{

bool Handled ;

switch (Message.Msg)

{

case WM_CLOSE:

mrYes==MessageDlg("Really Close??", mtWarning, TMsgDlgButtons() << mbYes <<mbNo, 0)?

Handled = false : Handled = true ;

break;

}

return Handled;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)

{

Application->UnhookMainWindow(AppHookFunc);

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

SendMessage(Application->Handle,WM_CLOSE,0,0);

}

//---------------------------------------------------------------------------

这样将本文中的两种方法相结合,您就可以自如的处理到达您的应用程序的各种消息了。

版权说明:

您可以随意复制、分发、下载此文档。但未经本人同意,您不可以截取、改动本文片断,或用本文谋取任何形式的利益。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有