• Win32help翻译(Hooks)


    hook提供一种机制,使得程序可以在消息的传递过程中加入自己的处理方法。由于hook增加了消息传递过程中的处理,所以会影响系统性能,应该仅在必须的时候使用hook

    Windows提供多种不同的hook,每一种访问不同的消息处理,例如,程序可以使用WH_MOUSE来监视鼠标消息。对每种hook,Windows都提供了单独的hook chain。A hook chain is a list of pointers to special, application-defined callback functions called hook procedures。当消息产生时挂接到特定的钩子上,Windows将消息逐个传递给消息链上定义的钩子函数。钩子函数可以截取的消息取决于钩子的定义,有些钩子函数可以只能监视消息,有些则可以修改或取消消息。

    为了处理hook,必须声明钩子函数并使用SetWindowsHookEx来安装到hook chain的最前端。
    hook procedure的格式如下:
    LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
    nCode的值取决于hook类型,每种hook都有不同的nCode值域。wParam和lParam取决于nCode
    hook procedure可以通过CallNextHookEx将消息传递到下一个hook procedure。

    hook procedure如果为global,则监视系统中所有线程的消息;如果特定于线程,则只监视特定线程的消息。全局钩子函数必须在DLL中实现;如果钩子函数监视自身创建的线程,则可以在程序内实现钩子函数;如果监视的是不同进程的消息,则必须在DLL中实现。

    钩子类型:
    ==================================================
    ◎ WH_CALLWNDPROC and WH_CALLWNDPROCRET Hooks
    ==================================================

    WH_CALLWNDPROC钩子监视SendMessage消息的传递,WM_CALLWNDPROCRET在消息被处理、函数返回后被调用(看名称多了一个ret),它们都只能监视消息而不能修改。WH_CALLWNDPROC需要用到的结构:

    LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
    nCode:如果nCode为HC_ACTION则proc必须处理消息,如果小于0,则必须不作处理的传递给CallNextHookEx并且result:=CallNextHookEx
    wParam:如果消息是当前进程发送的,则值为非零,否则为零。
    这两个参数都不知道效果,感觉第三个比较有用
    lParam:指向CWPSTRUCT结构的指针

    typedef struct tagCWPSTUCT{LPARAM lParam; WPARAM wParam; UINT message; HWND hwnd;} CWPSTRUCT
    hwnd标识将要接收消息的窗体,其他的都是SendMessage的参数

    HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
    idHook:type of hook
    lpfn:hook procedure,如果是监视其他进程的hook,hook proc必须在dll中实现
    hMod:标识包含hook procedure的DLL。如果是程序内的hook procedure则必须为NULL
    dwThreadId:标识hook procedure要处理的thread,如果为0,则处理所有线程。
    返回值:如果成功返回hook procedure的handle,如果失败返回NULL

    应用方法:点击按钮时改变窗体caption,当加载hook后,会弹出对话框显示修改后的标题
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FMsg := RegisterWindowMessage('ANUSERMSG'); //注册自定义消息
      Application.OnMessage := OnCustomMessage; //消息发生时进行处理
      EnableCWPHook; //启用hook,函数在DLL中实现
    end;

    procedure TForm1.OnCustomMessage(var msg: TMsg; var handled: Boolean);
    begin
      if (msg.message = FMsg) and (not handled) then
      begin
        handled := True; //有什么作用?
        ShowMessage(PChar(msg.lParam)); //自定义消息的参数在lParam中传递
      end;
    end;

    按钮点击事件:SendMessage(Handle, WM_SETTEXT, 0, Integer(PChar('abc'))); //发送消息,hook proc中捕捉WM_SETTEXT消息并发送自定义消息
    窗体释放的时候取消hook:DisableCWPHook;

    DLL中的实现

    procedure EnableCWPHook;
    begin
      user_msg := RegisterWindowMessage('ANUSERMSG'); //注册自定义消息,必须在DLL和EXE中都进行注册
      hHookProc := SetWindowsHookEx(WH_CALLWNDPROC, CallWNDProc, HInstance, 0); //调用函数注册钩子
    end;

    function CallWNDProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
    var  dw: DWORD;
    begin
      if PCWPSTRUCT(lParam).message = WM_SETTEXT then //lParam见上面的结构说明
      begin
        dw := BSM_ALLCOMPONENTS;
        //广播消息,以便APP可以接收
        BroadcastSystemMessage(BSF_POSTMESSAGE, @dw, user_msg, 0, PCWPSTRUCT(lParam).lParam);
      end;
      Result := 0; // the return value of CallWNDProc should always be zero.
    end;

    ==================================================
    ◎WH_KEYBOARD Hook
    ==================================================
    WH_KEYBOARD钩子可以监视键盘消息,当程序调用GetMessage或PeekMessage时,会得到WM_KEYDOWN和WM_KEYUP消息,此种hook截获这个消息供程序处理

    LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);
    code:表示如何处理消息。HC_ACTION、HC_NOREMOVE,如果code<0,必须调用CallNextHookEx来处理并返回处理结果
    wParam:键盘的virtual-key code
    lParam:32位数值,详细含义可以查阅
    Keystroke Message Flags
    返回值:如果返回值为0,则消息在hook chain上传递,若返回值不为0,则消息不再继续传递(按键失效)

    示例,监视按键(仅字母),在edit中显示按键

    HKeyHook := SetWindowsHookEx(WH_KEYBOARD, @KeyBoardProc, 0, GetCurrentThreadId);

    function KeyBoardProc(iCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; //注意调用方式
    var c: char; iCaps: Integer; pc: PChar;
    begin
      Result := 0; //允许消息的继续传递
      if iCode < 0 then //iCode<0必须不作处理并返回处理结果
      begin
        Result := CallNextHookEx(HKeyHook, iCode, wParam, lParam);
        Exit;
      end;
      GetMem(pc, 20);
      GetKeyNameText(lParam, pc, 20); //获得按键名称,如:Caps Lock, Shift, Right Alt
      if wParam in [$41..$5A] then //只处理字母
      begin
        iCaps := (GetKeyState(VK_SHIFT) shr 31) xor (GetKeyState(VK_CAPITAL) and 1); //检查shift和caps状态确定大小写
        c := Char(wParam + (1 - iCaps) * $20); //小写字母要加20h
        Form1.edt2.Text := c + ' 0x' + IntToHex(Ord(c), 2) + ' lParam:0x' + IntToHex(lParam, 8);
      end;
      Form1.edt3.Text := pc;
      FreeMem(pc);
    end;

    ==================================================
    ◎WH_MOUSE Hook
    ==================================================
    WM_MOUSE钩子可以用来监视鼠标消息

    LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
    nCode:同KeyboardHookProc,nCode<0只能传递处理
    wParam:鼠标消息的标识,鼠标单击、双击右击等
    lParam:MOUSEHOOKSTRUCT结构的指针
    返回值:0继续传递,1不传递

    typedef stuct tagMOUSEHOOKSTRUCT{POINT pt; HWND hwnd; UINT wHitTestCode; DWORD dwExtraInfo;} MOUSEHOOKSTRUCT;
    pt:光标位置
    hwnd:将要接受鼠标消息的窗口handle
    wHitTestCode:标识鼠标所在位置 HTxx常量
    dwExtraInfo:额外信息

    示例,光标移动时在窗体caption显示光标位置信息。当光标不在当前窗口时,是无法收到光标消息的,因此使用全局hook

    function MouseHookProc(iCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
    var  hookStruct: PMOUSEHOOKSTRUCT; sText: PChar; i: Integer;
    begin
      Result := 0;
      if iCode < 0 then
      begin
        Result := CallNextHookEx(hHookProc, iCode, wParam, lParam);
        Exit;
      end;
      hookStruct := PMOUSEHOOKSTRUCT(lParam);
      i := (hookStruct.wHitTestCode); //具体值查询WM_NCHITTEST
      sText := PChar(Format('X:%.4d Y:%.3d %d %d', [hookStruct.pt.X, hookStruct.pt.Y, i, wParam]));
      SendMessage(hWindow, WM_SETTEXT, 0, Integer(sText));
    end;

    hWindow := FindWindow('TForm1', nil);

    ==================================================
    ◎WH_SHELL Hook
    ==================================================
    shell程序使用WH_SHELL钩子获得重要的信息。windows在shell程序将要被激活或顶级窗口被创建和删除是调用WH_SHELL

    LRESULT CALLBACK ShelProc( int nCode, WPARAM wParam, LPARAM lParam);
    nCode:NT可用的只有以下三个
      HSHELL_ACTIVATESHELLWINDOW:shell应当激活主窗体。wParam=0
      HSHELL_WINDOWCREATED:顶级无主窗体被创建,当调用时窗体已存在。wParam为窗体的handle
      HSHELL_DESTROYED:顶级无主窗体将要被销毁,调用时窗体仍存在。lParam为窗体handle
    返回值:0

    不知道何所谓shell程序,仅提供窗体实现当双击文件夹时修改窗体caption,显示计数

    function shellProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
    begin
      Result := 0;
      if nCode < 0 then
      begin
        Result := CallNextHookEx(hHookProc2, nCode, wParam, lParam);
        Exit;
      end;
      if nCode = HSHELL_WINDOWCREATED then
      begin
        Inc(i); // i 为全局变量,计数用
        SendMessage(hWindow, WM_SETTEXT, 0, Integer(PChar('create ' + IntToStr(i))));
        
    //SendMessage(wParam, WM_CLOSE, 0, 0); 这句执行的话,那可就……^_^
      end;
    end;

    ==================================================
    ◎WH_CBT Hook
    ==================================================
    当系统发生以下事件时,调用WH_CBT hook函数:before activating, creating, destroying, minimizing, maximizing, moving, or sizing a window; before completing a system command; before removing a mouse or keyboard event from the system message queue; before setting the input focus; or before synchronizing with the system message queue. CBT hook主要应用于computer-based traing程序

    LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam);
    nCode:见win32help CBTProc 一节
    wParam, lParam:含义依赖于nCode

    示例作一个比shell hook中更过分的,禁止所有窗口的创建

    if nCode = HCBT_CREATEWND then Result := 1 //返回 1 表示不允许创建
    else Result := 0;

    程序中的调用也换换口味

    procedure TForm1.FormCreate(Sender: TObject);
    var
      hInstDll: HINST;
      hookProc: Pointer;
    begin
      hInstDll := LoadLibrary('CBTHook.dll');
      hookProc := GetProcAddress(hInstDll, 'CBTHookProc');
      hookProcResult := SetWindowsHookEx(WH_CBT, hookProc, 0, GetCurrentThreadId);
    end;

    ==================================================
    ◎WH_DEBUG Hook
    ==================================================

    ==================================================
    ◎WH_FOREGROUNDIDLE Hook
    ==================================================

    ==================================================
    ◎WH_GETMESSAGE Hook
    ==================================================

    ==================================================
    ◎WH_JOURNALPLAYBACK Hook
    ==================================================

    ==================================================
    ◎WH_JOURNALRECORD Hook
    ==================================================

    ==================================================
    ◎WH_MSGFILTER and WH_SYSMSGFILTER Hooks

  • 相关阅读:
    读取XML类
    服务器每隔一段时间执行一次任务
    关于购物网站的支付接口(.NET)
    CentOS学习
    CentOS6.4 V1.0
    jquery选择器 选择器性能问题
    css选择器总结
    遮罩层,可拖动
    第四次作业结对编程
    C++中常用类型的转换总结
  • 原文地址:https://www.cnblogs.com/hgy413/p/3693640.html
Copyright © 2020-2023  润新知