delphi的消息处理(50分)

  • 主题发起人 主题发起人 teleman2000
  • 开始时间 开始时间
T

teleman2000

Unregistered / Unconfirmed
GUEST, unregistred user!
今天看《delphi精要》(罗小平)的‘VCL消息机制’,其中的一个解释把我搞糊涂了。
“当你的应用程序运行时,程序中的每个有窗口的控件(TWinControl,也就是有句柄的
控件)都会在Windows中注册一个窗口过程,这个过程在VCL中叫作MainWndProc。”

我对Delphi处理消息的机制不是很清晰,但我觉得上面的解释跟我头脑中的印象不一致。
我觉得普通的控件(如,Tbutton,Tedit等)并不会注册回调函数,
它们响应消息,是Form的回调函数发给它们的。

是这样吗?请大家指教。
 
Tbutton 、Tedit 这些也是窗口啊!都是窗口的!
 
它们都有自己的消息处理过程的,
 
它们的处理过程是WndProc,但并不是向Windows 注册,而是在TControl.Perform中调用,
是这样吗?
 
你倒蛮喜欢研究的吗?
处理过程需要向windows注册吗?不会呀
 
所以说
“当你的应用程序运行时,程序中的每个有窗口的控件(TWinControl,
也就是有句柄的控件)都会在Windows中注册一个窗口过程,
这个过程在VCL中叫作MainWndProc。”
是不是不太准确?
 
這個問題要問一下李維﹗
 
windows一定会回调Tform的某个函数,但应该不会回调Tbutton的函数吧。是这样吗?
 
每个有句柄的窗口或者控件都有自己的窗口过程,而且都必须向windows注册,不然user32模块怎么将消息转到你的控件处理!?其实在delphi中TForm和TButton的消息处理过程没有多少不同!delphi产生的程序一般在application中使用getmessage函数产生一个消息循环,然后再translatemessage-->dispatchmessage-->USER32.DLL-->根据句柄和登记的窗口过程发送到这个过程(比如按钮的窗口过程).由于窗口过程是标准的C函数,而MainWndProc是一个对象方法,所以中间的处理过程还是蛮复杂,大概的过程是这样的!
每个控件在建立的时候注册一个初始的标准窗口过程,然后再向一块固定的内存将自己的对象方法写入(这个过程有高度的技巧,过程类似编译器的翻译方式)其中(对象方法指针为8字节,其中前4字节为地址,后4字节为对象的地址),然后在默认的窗口过程中将窗口过程换成刚才写入的地址,通过几个跳转,可以进入到相应的对象方法,并且通过其中的汇编指令CALL和POP指令的配合,可以很容易将进入地址压如栈中然后再在一个固定过程中弹出地址,并加4得到对象地址,由于知道了函数地址和对象地址,然后将对象地址压入eax中后jmp到函数地址,这样就可以符合delphi中关于对象方法的定义了,其他的参数按原来的方式传递!建议找本书好好看看!
 
每一个TControl都有个句柄,由window分配并管理,应用程序在收到消息后分配给相应的FORM,再由Form分配给相应的TControl,每个有句柄的TControl都有相应的消息处理函数用于处理其收到的消息。
我刚才又看了一下Delphi的源码,如它的TCustomCombobox在create时。利用MakeObjectInstance(EditWndProc),它的窗口过程就是editwinproc
定义如下: procedure EditWndProc(var Message: TMessage);
确认我说的内容,请鼓掌,加分~~以兴勇于回答之风~~
 
呵呵,先鼓掌
 
不过,到底是Windows先发给Form然后Form再发给Button;还是,Windows直接发消息给Button呢?我认为是Windows先发给Form然后Form再发给Button,是这样吗?
 
只要研究一下Form的WndProc中能否拦截到Button的消息就知道了。你可以自己测试一下,发一个消息到一个form的button,在Form的WndProc拦截试一试。结论就会明白了
 
哦,这给了我提醒,Form是可以拦截到Button的。但是如何解释Button向Windows 注册窗口函数呢?
 
button会向Windows注册窗口函数吗?如果注册不是为了回调,那么注册有什么用处呢?恳请指教。
 
讨论真热烈,李维有这样的书么?
 
Delphi中的每个VCL组件都有一个内在的消息处理机制,Tbutton,Tedit加入后,同样会注册
一个消息接受的过程MainWndProc,这是每个窗体和组件固有的。Delphi在内部使用这个过程
来接受来自各方面的消息并把他们发送给适当的处理方法。关于MainWndProc它是定义在WinControl类的一种静态的方法,不能被重载。它不直接处理消息,而是交给WndProc方法处理,WndProc可以截获自己想要的消息来进行处理,对于自己不能处理的就调用继承 ,让
它的父类去处理。它调用dispatch方法来进行消息的分配。
 
我是这样认为的:
点击button后产生的消息是由Windows获取后保存到应用程序的消息队列中,然后派发到相应的窗体(Tform),调用Form中的回调函数(MainWndProc->WndProc)处理消息,后来,WndProc调用了Dispatch(Wm_command),Dispatch(Wm_command)找到了TwinControl.Wmcommand,而TWinControl.Wmcommand调用了Tcontrol.perform来将消息分派到了Button.
从这个流程来看,只有Tform的回调函数起到作用了,所以Tform是有必要向Windows注册的,但是button这个窗口控件没有必要向Windows注册回调函数呀,因为它处理消息的函数都被显式的调用了。
因为我对Windows的机理很不清楚,对回调函数也不太清楚,对继承、多态了有些糊涂,基础很差,所以看有些资料,只能看懂十之一二。恳请各位不吝赐教,答疑解惑。
 
你的理解不是很正确哟!呵呵
Form的wndproc的确起到了调度的作用,但也不只是它一个有用!比如按钮(系统的标准控件,而不是Borland写的组件,Borland只是包装了它)是采用所谓超类化技术,替换其中的窗口过程,使得自己有完整的消息处理控制能力,留下足够的余地让delphi自己的消息和用户的消息更好的运转.而其中就使用到了Dispatch,便于delphi中使用消息方法来处理某个消息.
你如果碰到了下面的代码:SendMessage(Button1.handle,WM_LButtonDown,0,0),这个消息是直接发送到Button上的,你的Form中的窗口过程在这里就没有用到了,但在delphi中这个消息发送后按钮是会有反应的哟.
其实在Win32SDK中我们使用的按钮是标准的,依靠另一种回调(CreateWindow参数HMENU)方式在主窗体的窗口过程中来处理按钮发回来的信息,而delphi的封装方式更好,它可以直接接管所有的消息处理,使程序拥有所有的控制权! 所以Borland这种封装方式是有道理的!
 
不一定有窗口处理过程,但一定有类处理过程.
参照相关API:
GetWindowLong
GetClassLong
SetWindowLong
SetClassLong
 
后退
顶部