WIN32汇编语言教程:第11章 动态链接库和钩子 · 11.2 Windows钩子(5)
;#################################################################### ; 数据段 ;#################################################################### .data? hInstance dd ? hWinMain dd ? hHook dd ? szAscii db 32 dup (?) ;#################################################################### ; 代码段 ;#################################################################### .code ;#################################################################### ; 钩子回调函数 ;#################################################################### HookProc proc _dwCode,_wParam,_lParam local @szKeyState[256]:byte invoke CallNextHookEx,hHook,_dwCode,_wParam,_lParam pushad .if _dwCode == HC_ACTION mov ebx,_lParam assume ebx:ptr EVENTMSG .if [ebx].message == WM_KEYDOWN invoke GetKeyboardState,addr @szKeyState invoke GetKeyState,VK_SHIFT mov @szKeyState + VK_SHIFT,al mov ecx,[ebx].paramH shr ecx,16 invoke ToAscii,[ebx].paramL,ecx,\ addr @szKeyState,addr szAscii,0 mov byte ptr szAscii [eax],0 .if szAscii == 0dh mov word ptr szAscii+1,0ah .endif invoke SendDlgItemMessage,hWinMain,IDC_TEXT,\ EM_REPLACESEL,0,addr szAscii .endif assume ebx:nothing .endif popad ret HookProc endp ;#################################################################### _ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam mov eax,wMsg ;******************************************************************** .if eax == WM_CLOSE invoke UnhookWindowsHookEx,hHook invoke EndDialog,hWnd,NULL ;******************************************************************** .elseif eax == WM_INITDIALOG push hWnd pop hWinMain invoke SetWindowsHookEx,WH_JOURNALRECORD,\ addr HookProc,hInstance,NULL .if eax mov hHook,eax .else invoke EndDialog,hWnd,NULL .endif ;******************************************************************** .else mov eax,FALSE ret .endif mov eax,TRUE ret _ProcDlgMain endp ;#################################################################### start: invoke GetModuleHandle,NULL mov hInstance,eax invoke DialogBoxParam,eax,DLG_MAIN,NULL,\ offset _ProcDlgMain,NULL invoke ExitProcess,NULL ;#################################################################### end start
由于不再需要动态链接库了,钩子回调函数HookProc被移到了主程序中,也取消了InstallHook和UninstallHook两个子程序,相应的内容直接放在WM_INITDIALOG和WM_CLOSE消息中完成。在WM_INITDIALOG消息中用下面的语句完成对钩子的安装:
invoke SetWindowsHookEx,WH_JOURNALRECORD,addr HookProc,hInstance,NULL
参数WH_JOURNALRECORD表示安装的钩子是日志记录钩子。
由于钩子回调函数也写在主程序中,所以没有必要再通过自定义的WM_HOOK消息来通信,在回调函数中使用ToAscii函数将监测到的按键扫描码转换成ASCII码字符串以后,程序直接发送EM_REPLACESEL消息将它添加到编辑框中。
程序比较重要的一个不同点在于日志钩子回调函数的参数定义不同,在这里dwCode的参数定义如下:
● HC_ACTION——系统准备从消息队列中移去一条消息,消息的具体信息由lParam参数中指定的EVENTMSG结构定义。
● HC_SYSMODALOFF——某个系统模态对话框准备被关闭。
● HC_SYSMODALON——某个系统模态对话框准备被建立。
我们关心的是HC_ACTION标志,这时lParam参数指向一个EVENTMSG结构,其定义为:
EVENTMSG STRUCT message DWORD ? ;消息队列中将要移去的消息ID paramL DWORD ? ;消息的wParam参数 paramH DWORD ? ;消息的lParam参数 time DWORD ? ;消息发生的事件 hwnd DWORD ? ;消息对应的窗口句柄 EVENTMSG ENDS
由于日志记录钩子可以截获的不仅是键盘消息,也有鼠标等其他消息,所以需要有个地方指定消息类型,通过检测EVENTMSG结构中的消息ID字段就可以得知截获的究竟是什么消息。如果关心的是按键消息的话,那么发现消息ID为WM_KEYDOWN时进行处理就可以了,同理,如果关心的是鼠标消息的话,使用日志记录钩子也可以完成鼠标钩子完成的工作。例子程序中的相关代码如下:
.if _dwCode == HC_ACTION mov ebx,_lParam assume ebx:ptr EVENTMSG .if [ebx].message == WM_KEYDOWN ;处理按键消息 .endif assume ebx:nothing .endif
日志记录钩子回调函数的返回值没有被定义。所以不管返回什么值对消息的传递都没有影响。
上页:第11章 动态链接库和钩子 · 11.2 Windows钩子(4) 下页:第12章 多线程 · 12.1 进程和线程