123456

 

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

posted on 2011-05-28 11:41  hgy413  阅读(199)  评论(0编辑  收藏  举报

导航