Home » Tutorials » Systemnahe Programmierung » Mouse- und Tastatur-Hooks

Mouse- und Tastatur-Hooks

Unser erster Hook … die Tastatur

Als erstes werden wir einen Tastaturhook erstellen. Da der globale Hook meiner Auffassung nach eine Übermenge des lokalen Hooks ist, werden wir den Hook als global konzipieren.
Insgesamt werden wir uns bei den hiesigen Beispielen darauf beschränken, die Rückgabewerte nur auszuwerten und nicht zu modifizieren. Hier haben wir auch schon einen weiteren Vorteil von Hooks. Ich bin also in der Lage, mit Hilfe eines Hooks Messages und ihre Parameter zu bearbeiten.
Schauen wir uns erstmal die Deklarationen für die obigen Funktionen an. (In gleicher Reihenfolge, letztere könnte evtl. verwirrend sein.)

function SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST;
  dwThreadId: DWORD): HHOOK; stdcall;
function UnhookWindowsHookEx(hhk: HHOOK): BOOL; stdcall;
function CallNextHookEx(hhk: HHOOK; nCode: Integer; wParam: WPARAM;
  lParam: LPARAM): LRESULT; stdcall;
type
  TFNHookProc = function (code: Integer; wparam: WPARAM; lparam: LPARAM):
  LRESULT stdcall;

Wir schreiben also einen globalen Hook. Bekannt ist bereits, dass dieser in einer DLL ausgelagert sein muss, da nur eine DLL innerhalb anderer Prozesse ausgeführt werden kann.
Jetzt kommt’s gleich ganz dick. Hier der komplette Code für einen Tastaturhook. Dieser Hook führt keinerlei Bearbeitung oder so durch. Er soll nur zur Veranschaulichung dienen und wird sogleich erklärt. Zum Teil sind Erklärungen in Form von Kommentaren vorhanden.

library KeyboardHook;

uses
  Windows,
  Messages;

var
  HookHandle: Cardinal = 0;
  WindowHandle: Cardinal = 0;

function KeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM):
 LRESULT; stdcall;
begin
//es ist ebenfalls möglich die Bearbeitung an eine Bedingung zu knüpfen
//it's possible to call CallNextHookEx conditional only.
  Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
  case nCode < 0 of
    TRUE: exit; //wenn code kleiner 0 wird nix gemacht
                //if code smaller 0 nothing has to be done
    FALSE:
      begin
//Hier kann jetzt alles bearbeitet werden
//Here one can work with the parameters
      end;
  end;
end;

function InstallHook(Hwnd: Cardinal): Boolean; stdcall;
begin
  Result := False;
  if HookHandle = 0 then begin
//Erstmal Hook installieren
//First install the hook
    HookHandle := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc,
    HInstance, 0);
//Uebergebenes Fensterhandle sichern
//Save the given window handle
    WindowHandle := Hwnd;
    Result := TRUE;
  end;
end;

function UninstallHook: Boolean; stdcall;
begin
//Hook aus der Hookchain entfernen
//Uninstall hook from hook chain
  Result := UnhookWindowsHookEx(HookHandle);
  HookHandle := 0;
end;

exports
//Installations- und Deinstallationsroutine exportieren
//Export the installation and deinstallation routine
  InstallHook,
  UninstallHook;
end.

Tja, da denkt man erst, jetzt kommt sonstwas und dann nur so ein kleiner Schnipsel 😉
Der größte Teil dürfte verständlich sein. Aber der aufmerksame Leser und Programmierer wird sich an dieser Stelle fragen, welches Fenster ich als Handle übergeben bekomme und sichere. Nun, dies ist eine einfache Geschichte: Üblicherweise schickt man die Daten, die der Hook erhält, an ein Fenster weiter (meist mit Hilfe von Fensternachrichten) … dazu braucht man natürlich das Handle.
Ansonsten kann man sehr schön sehen, wie der Hook installiert wird, insofern er es nicht schon ist – und deinstalliert wird. Die zuständigen Routinen werden ausgelagert.
An dieser Stelle kann man also bequem mit dem Vorurteil aufräumen, Hooks seien eine komplizierte Materie. (Dies, das werdet ihr schnell mitbekommen, wird erst der Fall sein, wenn man die erhaltenen Daten modifiziert. Bei Shellhooks hat sich da mancher schon einen Neustart nicht verkneifen können, nachdem das System in etwas instabilem und unnutzbarem Zustand war …)
Übrigens ist an dieser Stelle noch zu erwähnen, dass das Verändern von WH_KEYBOARD in WH_MOUSE ausreicht, um den Hook zu einem Mousehook zu machen.