![]() |
|
| | 网站首页 | 电子知识 | 单片机知识 | 电路设计 | 微电子技术 | SCADA系统 | 资源下载 | 给我留言 | 视频教程 | ieee | |
| 热门搜索关键字: 单片机教程 | 三极管 | 微电子 | C语言 | 汇编语言 | SCADA | 元器件 | IEEE | |
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
经过这几天的努力奋战,关于用VB实现全局钩子的学习稍有进展,我见过的国内大多数论坛、网站的技术文章都断定:VB要实现全局钩子的编写,只能用SetWindowsHookEx、CallNextHookEx、UnhookWindowsHookEx三个函数,而且钩子函数必须位于DLL中,而且要用GetModuleHandle和GetProcAddress来调用。其实不然,在我所学习的一本VB书籍中比较详细地介绍了回调和子分类,具体是用一个类似于钩子的例子来进行说明的,这个例子让我感觉似乎还有一种(或许有更多)实现全局钩子的编写方法,以下为书中的源码和我按书中的思路写的全局钩子,英文注释为原文注释,中文注释是我根据书中的讲解在后面加的,如果有误,恳请指正
'----------------------------------------------------------------------------------------------------
'--- 回调部分 ---
'----------------------------------------------------------------------------------------------------
'模块中
'*******************************************************************
'EnumWindows:对当前窗口列表中的窗体
' 进行枚举
'MyCallBackFunc:回调函数,函数要实现
' 的功能由程序员完成,但函数的声
' 明格式必须与本例中一致
'InitiateCallback过程:初始化回调函数
'******************************************************************
Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, _
lParam As Any) As Long
Function MyCallBackFunc(ByVal hwnd As Long, lParam As Form) As Long
Dim sInfo As String
'sGetWindowInfo is a wrapper
'for GetClassName and GetWindowText.
sInfo = sGetWindowInfo(hwnd) ' sGetWindowInfo是GetClassname和GetWindowText的一个封装函数,可以根据自己的需要定义
lParam.Print "hwnd=" & hwnd & vbTab & sInfo
'Returning False causes EnumWindows to stop
'moving through the windows list
MyCallBackFunc = True ' 重要!如果忽略这一句回调函数会停止
End Function
Sub InitiateCallback()
'This code is called from the form's command button
Dim lRetVal As Long
Form1.Cls
lRetVal = EnumWindows(AddressOf MyCallBackFunc, Form1)
End Sub
'Form1中
Private Sub Command1_Click()
InitiateCallback
End Sub
部分运行结果:
hwnd=3316 Class:Volume Contro||| Text:Volume Control
hwnd=3312 Class:SNDVOL32
hwnd=864 Class:CAPTURE|| Text:Collage Capture <ORIGINAL.S>
......
'-------------------------------------------------------------------------------------------------------
'--- 子分类部分 ---
'-------------------------------------------------------------------------------------------------------
'模块中
'***********************************************************
'SetWindowLong:设置指定窗口的信息,本例中
设置指定窗口中处理消息的过程
'CallWindowProc:调用原窗口的过程
'WindowProc:替换原窗口的过程
'Hook:安装钩子的过程
'Unhook:卸载钩子的过程
'***********************************************************
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
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd _
As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Global Const GWL_WNDPROC = (-4)
Public lpPrevWndProc As Long ' 记录窗体
Public gHW As Long
Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, _
Debug.Print "Message: "; hw, uMsg, wParam, lParam
'根据Windows传递给窗体的消息Long值判断消息的类型,如果为512(WM_MOUSEMOVE)则吃掉消息,这样安装了钩子的窗体就收不到mousemove事件
在VB窗体中可以理解为Mouse_Move事件不会发生
If uMsg <> 512 Then WindowProc=CallWindowProc(lpPrevWndProc, hw, uMsg _
wPram, lParam)
'(Decimal 512 is 200 hex which is WM_MOUSEMOVE in the API text file.)
End Function
Sub Hook()
lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, AddressOf WindowProc)
End Sub
Sub Unhook()
Dim temp As Long
temp = SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc)
End Sub
'窗体中
Private Sub cmdHook_Click()
Hook
End Sub
Private Sub cmdUnHook_Click()
Unhook
End Sub
Private Sub Form_Load()
gHW = Me.hWnd
End Sub
运行此例,结果会在“立即”窗口中打印消息的详细信息,而且窗体的mouse_move事件不会发生,欲证实这一点,请在Form1的Mouse_move中编程。
言归正题,既然用SetWindowLong和CallWindowProc可以拦截、吃掉窗体消息中的鼠标消息,理所当然可以拦截其中的键盘消息了,因此我尝试照这个思路拦截键盘消息,而且只要用EmunWindows枚举出所有窗口的句柄,也就可以将所有窗口中处理消息的过程全部替换为自己的处理消息的过程了,也就能实现全局钩子了,但这样有个弊端,即安装了全局钩子以后,如果用户启动了新的窗口,那么钩子对新的窗体无效,因为新的窗体中的过程未被替换,所以在这一点上还要动动脑筋,正在研究之中。
| | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 网站地图 | 名站导航 | 管理登录 | |
|
中国IEEE 中国电气电子工程师网 版权所有 鲁ICP备08006092号 |