窗口子类化如何防止冲突
子类化是用GetWindowLong和SetWindowLong这两个API来对已经创建的窗口的窗口过程地址进行修改,用自己的窗口过程的新地址代替原来的,然后在自己写的新地址里过滤掉自己感兴趣的消息,一般我们是把自己不处理的消息再用原来的窗口函数调用,以实现我们对某一个窗口的特性的小修改要求,一般把子类化用在控件上,但也可以用在任意类型的窗口上.
以VB代码为例:
1、首先在form_load事件中拦截发送到所有form的消息,发送到自编回调函数NewWindowProc的地址。注意不同API函数及常量均要进行申明。
OldWindowProc = SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf NewWindowProc)
RegisterHotKey Me.hwnd, 1, MOD_ALT, vbKeyN '装载时注册热键
2、在自编回调函数NewWindowProc中对感兴趣的消息进行相关处理。
这里建议拦截句柄为hwnd控件的所有消息建议放在一个回调函数中,根据消息编号msg和消息附带的高位参数wparam的不同进行相关处理。
如果放在不同的回调函数中,就有可能会引起冲突。
Public Function NewWindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim mx As Integer
If Msg = TRAY_CALLBACK Then '如果用户点击了托盘中的图标,则进行判断是点击了左键还是右键
If lParam = WM_LBUTTONUP Then '如果点击了托盘左键
TheForm.Visible = Not TheForm.Visible '单击一次就隐藏
ElseIf lParam = WM_RBUTTONUP Then '如果点击了托盘右键
TheForm.PopupMenu TheMenu '则弹出右键菜单
Exit Function
End If
End If
If Msg = WM_HOTKEY Then '如果是热键消息
If wParam = 1 Then
'如果是本程序定义的(系统消息中的wParam参数在热键消息中代表热键标示符,是在RegisterHotKey注册热键的时候定义的一个整数,如果热键是系统定义的,则标示符取值为-1或-2,详见开头
frm_Main.Visible = Not frm_Main.Visible ' 热键对应上了之后就调用指定的过程
'这样,运行之后,反复按Alt + N 就可以实现窗口的隐藏与显示
Exit Function '消息已处理,不需要发回窗口
End If
End If
NewWindowProc = CallWindowProc(OldWindowProc, hwnd, Msg, wParam, lParam) '如果是其他类型的消息则传递给原有默认的窗口函数
End Function
3、Form_Unload事件中释放资源。
SetWindowLong Me.hwnd, GWL_WNDPROC, OldWindowProc '将窗口过程地址还原
UnregisterHotKey Me.hwnd, 1 '释放热键供其它应用程序使用