WinApi SetWindowsHookEx WH_KEYBOARD

Пример на Delphi 7:
## Код:
```
library msdopcelhook;

(*
  Alexander Shiryaev, 2010.04.29

  Для обнаружения нажатий клавиш в другой программе
*)

{$OVERFLOWCHECKS ON}
{$RANGECHECKS ON}

uses Windows, Messages, SysUtils;

const
  DllName = 'dopcelhook';
  MemMapFile = DllName + '.memmapfile';
  trace = False;

type
  PDLLGlobal = ^TDLLGlobal;
  TDLLGlobal = packed record
    HookHandle: Windows.HHOOK;

    res: Integer;
    wParam: WPARAM;
    lParam: LPARAM
  end;

var
  GlobalData: PDLLGlobal;
  MMF: THandle;

function HookProc (code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
  if GlobalData <> nil then begin
    if code < 0 then begin
      Result := CallNextHookEx(GlobalData^.HookHandle, code, wParam, lParam)
    end else begin
      // MessageBox(0, PAnsiChar(IntToHex(wParam, 4)), '', MB_OK);
      (* TODO: wParam, lParam filter here *)
        GlobalData^.wParam := wParam;
        GlobalData^.lParam := lParam;
        GlobalData^.res := 0; (* data available *)
      Result := CallNextHookEx(GlobalData^.HookHandle, code, wParam, lParam)
    end
  end else begin
    Result := 0 (* FIXME *)
  end
end (* HookProc *);

procedure CreateGlobalHeap;
begin
  MMF := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0,
    SizeOf(TDLLGlobal), MemMapFile);

  if MMF <> 0 then begin
    GlobalData := MapViewOfFile(MMF, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TDLLGlobal));
    if GlobalData = nil then begin
      CloseHandle(MMF)
    end else begin
      (* FIXME *)
        // GlobalData^.HookHandle := INVALID_HANDLE_VALUE;
        GlobalData^.res := 3 (* no data available *)
    end
  end else begin
    GlobalData := nil
  end
end (* CreateGlobalHeap *);

procedure DeleteGlobalHeap;
begin
  if GlobalData <> nil then begin
    UnmapViewOfFile(GlobalData);

    GlobalData := nil;

    if MMF <> INVALID_HANDLE_VALUE then begin
      CloseHandle(MMF)
    end
  end
end (* DeleteGlobalHeap *);

procedure RunHook; stdcall;
begin
  if GlobalData <> nil then begin
    GlobalData^.HookHandle := SetWindowsHookEx(WH_KEYBOARD, @HookProc, HInstance, 0);
    if GlobalData^.HookHandle = INVALID_HANDLE_VALUE then begin
      MessageBox(0, 'RunHook: fail: SetWindowsHookEx', DllName, MB_OK)
    end else begin
      if trace then begin
        MessageBox(0, 'RunHook: ok', DllName, MB_OK)
      end
    end
  end else begin
    MessageBox(0, 'RunHook: fail: GlobalData = nil', DllName, MB_OK)
  end
end (* RunHook *);

procedure KillHook; stdcall;
begin
  if GlobalData <> nil then begin
    if GlobalData^.HookHandle <> INVALID_HANDLE_VALUE then begin
      UnhookWindowsHookEx(GlobalData^.HookHandle);
      GlobalData^.HookHandle := INVALID_HANDLE_VALUE;
      if trace then begin
        MessageBox(0, 'KillHook: ok', DllName, MB_OK)
      end
    end else begin
      MessageBox(0, 'KillHook: already killed', DllName, MB_OK)
    end
  end else begin
    MessageBox(0, 'KillHook: fail: GlobalData = nil', DllName, MB_OK)
  end
end (* KillHook *);

procedure Get (var wParam: WPARAM; var lParam: LPARAM; var res: Integer); stdcall;
begin
  if GlobalData <> nil then begin
    if GlobalData^.HookHandle <> INVALID_HANDLE_VALUE then begin
      if GlobalData^.res = 0 then begin
        wParam := GlobalData^.wParam;
        lParam := GlobalData^.lParam;
        // MessageBox(0, PAnsiChar('W:' + IntToHex(GlobalData^.wParam, 4) + ' L:' + IntToHex(GlobalData^.lParam, 4)), '', MB_OK)
      end;
      res := GlobalData^.res;
      GlobalData^.res := 4; (* no new data available *)
    end else begin
      res := 2 (* hook not runned *)
    end
  end else begin
    res := 1 (* memory control error *)
  end
end (* Get *);

procedure DLLEntry (dwReason: DWORD);
begin
  case dwReason of
  DLL_PROCESS_ATTACH:
    begin
      CreateGlobalHeap;
      // RunHook
    end;
  DLL_PROCESS_DETACH:
    begin
      // KillHook;
      DeleteGlobalHeap
    end;
  end
end (* DLLEntry *);

exports
  KillHook, RunHook, Get;

begin
  DllProc := @DLLEntry;
  DLLEntry(DLL_PROCESS_ATTACH)
end.
```
