在每一个继承类的 WndProc 中应该只处理维持窗体运作的最基本的消息,其他不处理的消息最终会在 TControl.WndProc 中被传递到 TObject.Diapatch。TObject.Diapatch 在自己和父类的动态方法表中查询相应消息 ID,如果找到了,则调用相应的方法。所有处理消息的类方法都应该以关键字 message 定义,这可以保证其入口地址都是存在动态方法表中,从而也保证需要处理的消息 可以在 TObject.Diapatch 执行过程中被调用。
如果在动态方表中还是无法查询到需要处理的消息,那么 TObject.Diapatch 会继续调用虚方法 DefaultHandler,TObject.DefaultHandler 只是个 PlaceHolder,该方法在 TWinControl 中被重载, TWinControl 继承类中鲜有继续重载该方法的类,可以认为消息最后一次被处理的机会就是发生在 TWinControl.DefaultHandler 中。我们知道在消息循环中不处理的消息最后都应该交给 Windows 的默认回调函数 DefWindowProc API 来处理, TWinControl.DefaultHandler 最主要的工作就是完成这个,除此之外,还完成几个额外的消息处理[2]。
VCL 的消息流程至此为止。
可能你还在为整个消息分派流程犯晕,让我用实例来分析一下吧。
三,VCL 完整的消息分派流程
1. TButton
新建一个 Application,在 Form1 上放一个 Button (缺省名为Button1),在其 OnClick 事件中随便写点代码,加上断点,在调试之前,请打开 DCU 调试开关(Project->Options->Compiler->Use Debug DCUs), 这个开关如果不打开,是没法调试 VCL 的,然后 F9 运行,当停留在断点上时,打开Call Stack 窗口(View->Debug Window->Call Stack)可看到调用顺序如下(从底往上看):
TControl.Click
TButton.Click
TButton.CNCommand((48401, 660, 0, 524948, 0))
TControl.WndProc((48401, 660, 524948, 0, 660, 0, 660, 8, 0, 0))
TWinControl.WndProc((48401, 660, 524948, 0, 660, 0, 660, 8, 0, 0))
TButtonControl.WndProc((48401, 660, 524948, 0, 660, 0, 660, 8, 0, 0))
TControl.Perform(48401,660,524948)
DoControlMsg(524948,(no value))
TWinControl.WMCommand((273, 660, 0, 524948, 0))
TCustomForm.WMCommand((273, 660, 0, 524948, 0))
TControl.WndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))
TWinControl.WndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))
TCustomForm.WndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))
TWinControl.MainWndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))
StdWndProc(918056,273,660,524948)
TWinControl.DefaultHandler((no value))
TControl.WMLButtonUp((514, 0, 48, 13, (48, 13), 0))
TControl.WndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))
TWinControl.WndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))
TButtonControl.WndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))
TWinControl.MainWndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))
StdWndProc(524948,514,0,852016)
TApplication.HandleMessage
TApplication.Run
Project1
一个 Button 被点击,在 TButton 内部会发生两个消息:
2. TForm
新建一个 Application,为 Form1 的 OnMouseDown 事件随便写一点代码,在这个方法上设断点,F9 运行,看看 Call Stack
TControl.MouseDown(mbLeft,[ssLeft],346,212)
TControl.DoMouseDown((513, 1, 346, 212, (346, 212), 0),mbLeft,[])
TControl.WMLButtonDown((513, 1, 346, 212, (346, 212), 0))
TControl.WndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))
TWinControl.WndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))
TCustomForm.WndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))
TWinControl.MainWndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))
StdWndProc(2687598,513,1,13893978)
TApplication.HandleMessage
TApplication.Run
Project1
鼠标在 Form 上点击,产生两个消息
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




