|
3#
楼主 |
发表于 2005-8-24 19:24:00
|
只看该作者
窗口程序
Windows并不知道事件,这些是VB特有的隐藏Windows获取你的窗口发生事件的真正方法的一种方式。VB很像是一个将Windows语言翻译成VB语言的解释器。
但是事实并非如此,你很快就会遇到。设想你想知道用户何时加亮了菜单选项(不是点击,只是加亮即选择了)VB并不提供这种事件,但你可能见到其他的程序,但你浏览它的菜单时状态栏会出现相应的文字。如果他们能,你为何不能?
OK,这里是大致的真实情况。每个窗口都有一个特殊的程序叫做窗口程序。它实际上是一个回调函数。该函数将在你的窗口发生事件的任何时间发送消息。这样当用户加亮一个菜单项时就会发送一条消息(WM_COMMAND)。
那为什么我看不到这条消息呢?这是因为是VB创建窗口程序而不是你。当Windows发送消息时,该程序将为之分派特定的事件,并将其参数转换为比较容易用的事件的参数。但是在有些情况下,它会忽略有些消息而不能收到真实的输入。如果你真的想得到这些消息,你必须对你的窗体进行子类处理,我们将在另外一个主题中谈到。
这里是一个回调窗口程序的声明:
Function WindowProc(ByVal Hwnd As Long, ByVal wMsg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long
第一个参数指定窗口的句柄,第二个参数是消息的标识符(如WM_COMMAND或WM_MOUSEMOVE),wParam和lParam时两个32位的数值,它们的意义依赖于消息的类型。
子类处理
当你一最大限度利用了VB所给你的并且还想知道更多的东西,或只是想更多地了解你自己的窗口,你将会发现子类处理的优势。
子类处理是指用一个新的窗口函数来取代当前活动窗口函数。这个用户自定义函数能处理任何需要的消息,并能调用原来的窗口函数,它将在原来的窗口函数之前收到各种消息。但原来的那个窗口处理函数依然存在,并没有消失。如果你不想处理某条消息,你应该让原来的窗口函数去处理它。
子类处理是通过调用SetWindowLong函数实现的,该函数将改变指定窗口的特殊属性。下面是它的声明:
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"(ByVal hwnd As Long, ByVal nIndex As Long,ByVal dwNewLong As Long) As Long
第一个参数代表要进行子类处理的窗口,第二个参数应该是GWL_WNDPROC(-4),第三个参数是新的窗口函数的地址。参见回调和窗口函数一节:
此函数将在窗口取得焦点,发生事件,或其他情况下(如其他进程改变了系统的某些参数)被随时调用:
如果发生错误SetWindowLong函数将返回0,否则将返回原来的窗口函数的地址。这个地址特别重要,你应该把它保存在一个变量中或其他地方。当你不处理某些消息时(实际上,你可能只处理不到1%的消息,其他的都将由原窗口函数处理),调用原来的窗口函数就需要该地址。
调用原窗口函数将由CallWindowProc来完成。这里是它的声明:
Declare Function CallWindowProc Lib "user32" Alias"CallWindowProcA"(ByVal lpPrevWndFunc As Long,ByVal hWnd As Long,ByVal Msg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long
第一个参数是原窗口函数的地址,其他的同你接收到的四个参数一样。你可以改变其中的值来控制对消息的处理。例如:当你收到了一条WM_MOUSEMOVE消息时,你从lParam中得到鼠标所在位置的坐标并将其改成了其他的坐标。那么原窗口函数就会认为鼠标位于其他的位置从而做出一些有趣的事如显示其他控件的Tooltip.。
你指定的返回值也是有意义的,它依赖于发送的消息。
在结束你的程序时将控制权交回给原窗口函数是很重要的,通常在Form_Unload中完成如下:
Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProcAddress)
如果你在VB中启动程序时忘掉了这一行,结果将是VB崩溃并会丢失尚未保存的数据,千万要小心。
这里是子类处理的一个简单示例:
Dim oldWndProc As Long
Private Sub Form_Load()
oldWndProc = SetWindowLong(Me.Hwnd, GWL_WNDPROC, AddressOf MyWndProc)
End Sub
Private Sub Form_Unload()
Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProc)
End Sub
Function MyWndProc(ByVal Hwnd As Long,ByVal wMsg as Long,ByVal wParam As Long,ByVal lParam As Long)
Debug.Print wMsg & " " & wParam & " " & lParam
Ret& = CallWindowProc(oldWndProc, Hwnd, wMsg, wParam, lParam)
End Function
处理参数
有时函数并不以你所需的方式返回信息。一个典型的例子是将 |
|