我的 Hook 函数停止工作

My Hook functions stop working

一段时间后崩溃,我不得不重新启动钩子

KeyboardHook 的作用

function KeyboardHook(Code: Integer; wParam : WPARAM; lParam : LPARAM): LongInt;
var
  Buffer: TEventMsg;
  Key: Cardinal;
begin
  if (wParam = 01) and
     (App.Inside) then
  begin
    Buffer := PEventMsg(lParam)^;
    Key := Buffer.message;

    if App.Inside then
    begin
      case Key of
        VK_NEXT: App.Next;
        VK_CAPITAL: App.Show;
      end;
    end;
  end;
  CallNextHookEx(Hook_ID_Keyboard, Code, wParam, lParam);
  Result := 0;
end;

启动Hook的函数

function StartHookKeyboard: Boolean; stdcall;
begin
  Hook_ID_Keyboard := SetWindowsHookEx(13, @KeyboardHook, HInstance, 0);
  If Hook_ID_Keyboard = 0  then
    Result := False else
    Result := True;
end;

我的代码有没有错误?

不要使用硬编码 magic numbers。在此上下文中,13 是 WH_KEYBOARD_LL01WM_KEYUP,等等。在您的代码中使用实际名称。它们以 WindowsMessages 单位声明。

您是否声明 KeyboardHook() 使用 stdcall 调用约定?您显示的代码没有这样做。这非常重要,这样参数值才能在调用堆栈上正确传递。

WH_KEYBOARD_LL 钩子的 lParam 值不是 PEventMsg(而是指向 EVENTMSG structure). That structure is used for WH_JOURNALPLAYBACK hooks. WH_KEYBOARD_LL uses the KBDLLHOOKSTRUCT 结构的指针。Delphi 没有声明特定的结构,因此您必须自己在代码中声明它。

并且不要忽略回调的 Code 参数,或 CallNextHookEx() 的 return 值。他们很重要。 wParamlParam 值仅在 Code 参数为 HC_ACTION (0) 时有效。而CallNextHookEx()的return值需要向上传递hook链

试试这个:

type
  PKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;
  KBDLLHOOKSTRUCT = record
    vkCode: DWORD;
    scanCode: DWORD;
    flags: DWORD;
    time: DWORD;
    dwExtraInfo: ULONG_PTR;
  end;

function KeyboardHook(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  if Code = HC_ACTION then
  begin
    if (wParam = WM_KEYUP) and (App.Inside) then
    begin
      case PKBDLLHOOKSTRUCT(lParam)^.vkCode of
        VK_NEXT: App.Next;
        VK_CAPITAL: App.Show;
      end;
    end;
  end;
  // note that CallNextHookEx() ignores the first parameter,
  // so you could pass 0 instead of ID_Keyboard...
  Result := CallNextHookEx(Hook_ID_Keyboard, Code, wParam, lParam);
end;

function StartHookKeyboard: Boolean; stdcall;
begin
  if Hook_ID_Keyboard = 0 then
    Hook_ID_Keyboard := SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardHook, HInstance, 0);
  Result := Hook_ID_Keyboard <> 0;
end;

function StopHookKeyboard: Boolean; stdcall;
begin
  if Hook_ID_Keyboard <> 0 then
  begin
    if UnhookWindowsHookEx(Hook_ID_Keyboard) then
      Hook_ID_Keyboard := 0;
  end;
  Result := Hook_ID_Keyboard = 0;
end;

如果代码仍然崩溃,可能与 App 有关。什么是 App?它在哪里以及如何声明?它是如何初始化的? Next()Show() 实际上是做什么的?您正在全局安装挂钩以挂钩所有 运行 进程,所以 App 是否以跨进程安全的方式使用?