WIN32汇编语言教程:第11章 动态链接库和钩子 · 11.2 Windows钩子(3)

如果钩子安装成功,函数返回钩子句柄,否则返回NULL。钩子句柄必须被保存下来,因为在回调函数和卸载钩子的时候还要用到这个句柄。

动态链接库导出的另一个函数是UninstallHook,用来供主程序卸载钩子。程序在这里使用UnhookWidowHookEx函数卸载钩子,这个函数的输入参数只有一个,就是安装钩子时候得到的钩子句柄。

现在来看主程序。Main.rc文件的内容如下:

//##################################################################
#include                 <resource.h>
//##################################################################
#define    ICO_MAIN       1000
#define    DLG_MAIN       1000
#define    IDC_TEXT       1001
//##################################################################
ICO_MAIN       ICON                "Main.ico"
//##################################################################
DLG_MAIN DIALOG 208, 130, 234, 167
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "键盘钩子"
FONT 9, "宋体"
{
 EDITTEXT IDC_TEXT, 5, 5, 224, 158, ES_MULTILINE | ES_AUTOVSCROLL
       | WS_BORDER | WS_VSCROLL | WS_TABSTOP | ES_READONLY
}
//##################################################################

资源脚本文件中的定义很简单,仅定义了一个对话框,对话框中有个多行的编辑控件,用来显示“钩住”的按键。Main.asm的内容如下:

                 .386
                  .model flat, stdcall
                 option casemap :none
;####################################################################
; Include 文件定义
;####################################################################
include        windows.inc
include        user32.inc
includelib     user32.lib
include        kernel32.inc
includelib     kernel32.lib
include        Hookdll.inc
includelib     Hookdll.lib
;####################################################################
; Equ 等值定义
;####################################################################
ICO_MAIN          equ    1000
DLG_MAIN         equ    1000
IDC_TEXT         equ    1001
WM_HOOK        equ    WM_USER + 100h
;####################################################################
; 代码段
;####################################################################
                  .code
;####################################################################
_ProcDlgMain      proc       uses ebx edi esi hWnd,wMsg,wParam,lParam
                 local  @dwTemp
 
               mov    eax,wMsg
;********************************************************************
                 .if    eax == WM_CLOSE
                         invoke UninstallHook
                         invoke EndDialog,hWnd,NULL
;********************************************************************
                 .elseif eax == WM_INITDIALOG
                         invoke InstallHook,hWnd,WM_HOOK
                        .if    ! eax
                                 invoke EndDialog,hWnd,NULL
                          .endif
;********************************************************************
                 .elseif eax == WM_HOOK
                         mov    eax,wParam
                         .if    al == 0dh
                                 mov    eax,0a0dh
                         .endif
                         mov    @dwTemp,eax
                         invoke SendDlgItemMessage,hWnd,IDC_TEXT,\
                                 EM_REPLACESEL,0,addr @dwTemp
                  .else
                         mov    eax,FALSE
                          ret
                 .endif
                 mov eax,TRUE
                 ret
 
_ProcDlgMain      endp
;####################################################################
start:
                 invoke GetModuleHandle,NULL
                 invoke DialogBoxParam,eax,DLG_MAIN,NULL,\
                         offset _ProcDlgMain,NULL
                 invoke ExitProcess,NULL
;####################################################################
                 end start

为了使用动态链接库中的导出函数InstallHook和UninstallHook,在程序的开头需要用include语句和includelib语句将动态链接库的函数声明和导入库包含进来。

在对话框初始化的消息WM_INITDIALOG 中,程序调用InstallHook函数安装钩子,输入的参数是主窗口句柄和自定义的消息ID:WM_HOOK(Windows系统中ID值在WM_USER以后的值都可以由用户使用,在这里将WM_HOOK定义为WM_USER+100h),这样每当钩子回调函数得到按键消息的时候,就可以通过这个消息ID通知主窗口。接下来程序对返回值进行检查,如果返回值表示失败则直接退出程序。在关闭对话框的WM_CLOSE消息中,程序调用UninstallHook函数卸载钩子。

在平时,主程序等待自定义消息WM_HOOK,并将传递过来的按键字符串通过发送EM_REPLACESEL消息添加到编辑框中,在添加之前先检测按键是否为回车键,如果是,再人为插入一个换行符(0ah),以便将编辑框中的内容换行显示。

2. 钩子回调函数

现在回过头来看HookDll.asm程序中的钩子回调函数,回调函数的写法一般如下:

HookProc           proc       dwCode,wParam,lParam
 
               invoke CallNextHookEx,hHook,_dwCode,_wParam,_lParam
                ;处理消息的代码
                mov    eax,返回值
                ret
 
HookProc   endp

各种类型钩子的回调函数的参数都是这样3个,但是它们的定义各不相同,就像窗口过程在收到各种不同消息的时候,wParam和lParam的定义也各不相同。不同类型的钩子回调函数的返回值定义也是各不相同的。

对于键盘钩子来说,参数的定义如下所示。

● dwCode——键盘消息的处理方式。如果是HC_ACTION,表示收到一个正常的击键消息;如果是HC_NOREMOVE,表示对应消息并没有从消息队列中移去(当某个进程用指定PM_NOREMOVE 标志的PeekMessage函数获取消息时就是如此)。

● wParam——按键的虚拟码(即Windows.inc中定义的VK_xxx值)。

● lParam——按键的重复次数、扫描码和标志等数据,不同数据位的定义如下:

■  位0~15:按键的重复次数。

■  位16~23:按键的扫描码。

■  位24:按键是否是扩展键(F1与F2等Fx键,小键盘数字键等),如果此位是1表示按键是扩展键。

■  位25~28:未定义。

■  位29:如果Alt键在按下状态,此位置1,否则置0。

■  位30:按键的原先状态,消息发送前按键原来是按下的,此位被设置为1,否则置0。

■  位31:按键的当前动作,如果是按键按下,那么此位被设置为0;按键释放的话被设置为1。

上页:第11章 动态链接库和钩子 · 11.2 Windows钩子(2) 下页:第11章 动态链接库和钩子 · 11.2 Windows钩子(4)

第11章 动态链接库和钩子

版权所有 © 云南伯恩科技 证书:粤ICP备09170368号