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

Mouse- und Tastatur-Hooks

Abseits des Themas…

So. Für das Thema Hook soll es das erstmal soweit gewesen sein, ich habe den Quelltext kommeniert, so dass Ihr Euch dort ohne weiteres zurechtfinden solltet.
Wir wenden uns nun dem Drumherum zu. Ich erkläre dazu kurz den Import von Funktionen aus einer DLL und zwar sowohl dynamisch als auch statisch. Zum Schluss als kleines Schmankerl noch eine Routine, um die DLL nach dem Einkompilieren als Ressource wieder zu extrahieren.
Hier also erstmal die dynamische Variante:

type
  TInstallHook = function(Hwnd: THandle): Boolean; stdcall;
  TUninstallHook = function: Boolean; stdcall;

var
  InstallHook: TInstallHook;
  UninstallHook: TUninstallHook;
  lib: Cardinal;

begin
  lib := LoadLibrary('keyboardhook.dll');
  if lib <> INVALID_HANDLE_VALUE then begin
    InstallHook := GetProcAddress(lib, 'InstallHook');
    UnInstallHook := GetProcAddress(lib, 'UninstallHook');
  end; // else ERROR
end;

Zuerst wird hier der jeweilige Typ für die exportierten Funktionen deklariert, welche importiert werden sollen. Hernach definiert man Variablen mit eben diesen Typen und lädt als erstes die DLL. Nachdem die DLL geladen ist, wird mit Hilfe des Instanzenhandles versucht, die Prozedureinsprungspunkte zu erhalten. Im Endeffekt kann man die Funktionen dann benutzen, als wären sie über eine Unit eingebunden. Wenn man die DLL nicht mehr benötigt, sollte man sie über FreeLibrary() wieder entladen.
Und jetzt die statische Variante:

function InstallHook(Hwnd: THandle): Boolean; stdcall;
  external 'keyboardhook.dll';
function UninstallHook: Boolean; stdcall; external 'keyboardhook.dll';

Hier könnte man ja nun denken, aha, die Variante ist ja einfacher. Von der Sache her korrekt – allerdings versperrt sie einige Optionen. Die statische Variante wird in der Importtabelle des Programms festgehalten. Diese Tabelle ist eine Art Platzhalter für die einzelnen Adressen und wird vom Loader gefüllt. Aus diesem Grunde muss die DLL auch verfügbar sein, wenn das Programm startet, ansonsten gibt es einen Fehler. Um dies zu verhindern, benutzt man eben dynamisches Laden. Damit wird es ermöglicht, vor dem Laden der DLL Code auszuführen, um z.B. einen Fehler auszugeben, wenn die DLL nicht vorhanden ist. Dies ist m.M. immer besser als die statische Form des Imports und bei Anwendungen, die systemspezifische Funktionen (LANMAN, NT native API, NT security API) benutzen, unabdingbar!!! Nichtsdestotrotz wird die statische Variante häufiger verwendet.