深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)

1,回调函数工作机制

回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了。

2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的。

下面还是以具体例子来说明比较好。

在 Windows下,每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息。通常情况下,要把这个消息直接交给 DefWindowProc 函数处理,该函数会返回一个值来告诉 Windows 鼠标按下的是窗口的哪一部分。Windows 利用这个返回值来决定要发送的鼠标消息的类型。例如,如果用鼠标左键单击窗口的标题栏,处理WM_NCHITTEST 消息的 DefWindowProc 函数会返回 HTCAPTION,然后 Windows 会再向该
窗口发送 WM_NCLBUTTONDOWN 消息。如果 DefWindowProc 的返回值是 HTCLIENT,Windows 就将鼠标所在位置的坐标从屏幕坐标转化成为客户区坐标,并且通过WM_LBUTTONDOWN 消息通知用户。

3,既然谈到了截获消息,势必要谈下由“消息产生消息”了,同样以例子来说明:

Windows用WM_NCHITTEST消息产生所有其它鼠标消息,这种由消息引出其它消息的想法在Windows中是很普遍的。举个例子,如果您在一个Windows程序的系统菜单图标上双击一下,那么程序将会终止。双击产生一系列的WM_NCHITTEST消息。由于鼠标定位在系统菜单图标上,因此DefWindowProc将传回HTSYSMENU的值,并且Windows把wParam等于HTSYSMENU的WM_NCLBUTTONDBLCLK消息放在消息队列中,也就是说WM_NCLBUTTONDBLCLK消息的wParam参数是HTSYSMENU,这个是由DefWindowProc返回的。 窗口消息处理程序通常把鼠标消息传递给DefWindowProc,当DefWindowProc接收到wParam参数等于HTSYSMENU的WM_NCLBUTTONDBLCLK消息时,它就把wParam参数等于SC_CLOSE的WM_SYSCOMMAND消息放入消息队列中(这个WM_SYSCOMMAND消息是在使用者从系统菜单中选择「Close」时产生的)。同样地,窗口消息处理程序也把这个消息传给DefWindowProc。DefWindowProc通过给窗口消息处理程序发送WM_CLOSE消息来处理该消息。

下面再以拖动窗口为例来说明:

单击鼠标,系统投递WM_NCHITTEST到消息队列,lParam参数记录了光标的移动目的位置,由DefWindowProc处理,该函数的返回值代表当前鼠标移动到了窗口的哪个部位,如HTCLIENT,HTCAPTION,由DefWindowProc处理WM_NCHITTEST,将控制权返回给系统。DefWindowProc返回HTCAPTION,此时操作系统返回什么消息呢?应该是WM_NCLBUTTON,其wParam参数包含了鼠标在窗口的哪个部位,lParam包含了鼠标的坐标位置。

如果应用程序没有对该消息响应,则由系统默认处理。

系统默认处理又是怎样的呢?系统发现wParam指示了鼠标点击的是标题栏,就会标识当前窗口处于“拖拽状态”(Windows内部记录了每个窗口的状态信息)。由于标识了“拖拽状态”,则从此刻起到鼠标键放开之前,你的鼠标移动状况完全由Windows跟踪。它根据鼠标的移动,使得窗口作“同步”移动。注意,这个过程中,窗口不会收到WM_NCMOUSEMOVE消息,因为窗口和鼠标是“同步”移动的,你的鼠标相对于窗口是静止的。(这些细节你可以自己写个示例来测试并分析得出,事实上我也是这么做的。如果我的观点有错误,欢迎指正)。

当放开鼠标左键时,系统产生WM_NCHITTEST消息,lParam包含当前坐标,该消息由DefWindowProcl处理,处理完成后,由DefWindowProc投递WM_NCLBUTTONUP消息,wParam参数表示当前光标所在窗口的部位,它是由DefWindowProc返回的,lParam代表光标的坐标。当然了这个消息同样由DefWindowProc来处理,处理完毕后,这个函数同时需要发出WM_SYSCOMMAND消息,它的wParam应该是SC_MOVE,代表窗口移动,该消息同样由DefWindowProc处理,处理完后,它在发出WM_MOVE消息,lParam代表了窗口左上角的坐标....先分析到这....

下面对上面的描述进行总结:

当光标移动或者鼠标按下或者释放时,系统产生WM_NCHITTEST消息,其中wParam为空,lParam参数记录了光标的x和y坐标。该消息由DefWindowProc处理,在合适的情况下(多数情况下其实都是这样),DefWindowProc又会向消息队列投递一个WM_SYSCOMMAND消息(注:当用户点击菜单命令时,发出这个消息),其wParam参数反应了用户单击了哪个菜单项命令。回调函数把这个消息给DefWindowProc处理,这个函数再投递一个WM_CLOSE(如果用户选择的是菜单的close命令)给用户程序消息队列。

//下面分析移动鼠标

4,鼠标消息,WM_NCHITTEST,WM_MOUSEMOVE,WM_NCMOUSEMOVE

如果鼠标在窗口移动,系统投递WM_NCHITTEST到消息队列,lParam参数记录了光标的移动目的位置,由DefWindowProc处理,该函数的返回值代表当前鼠标移动到了窗口的哪个部位,如HTCLIENT,HTCAPTION,将控制权返回给系统。

假设光标在标题栏,此时系统会投递一个WM_NCMOUSEMOVE到消息队列,wParam是上面DefWindowProc的返回值,代表了光标移动到了窗口的哪个部位,lParam代表了当前光标所在的坐标。

http://blog.sina.com.cn/s/blog_673ef8130100mw4b.html

上一篇:js中exec、test、match、search、replace、split、indesOf()用法


下一篇:Javascript中substr和substring的区别