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 进程和线程

第11章 动态链接库和钩子

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号