Einzelnen Beitrag anzeigen

Prototypjack

Registriert seit: 2. Feb 2003
611 Beiträge
 
Delphi 2009 Professional
 
#1

Ein paar weitere Fragen zu Windows-Hooks

  Alt 29. Aug 2007, 13:34
Moin,

Ich habe da noch ein paar weitere Fragen zu Hooks, ich hoffe ihr könnt mir da ein wenig auf die Sprünge helfen!

Wie man in dem Source unten sieht, handelt es sich um einen Global WndProc-Hook, der bestimmte Bewegungen (wenn ein Fenster den Monitor wechselt), aufzeichnen und an mein Hauptprogramm weiterleiten soll.

Da aber erst eine Message geschickt wird, wenn das passiert, möchte ich meinen Hook direkt im Programm an/abmelden. Das heißt: Ich will, sobald das Fenster, welches ich mit der geladenen Instanz beobachte, einsatzbereit ist eine Message an mein Programm schicken, welche dieses Bestätigt. Soweit wäre das wahrscheinlich kein Problem, aber ich habe keine Ahnung wie ich an das Fensterhandle komme (Wenn ich einfach eine Globale Variable setze, die ich dazu benutze beim ersten WndProc-Ereignis eine Message zu schicken (und dann nie wieder), dann schickt der Hook extrem viele Nachrichten dieser Art auf einmal und Windows verabschiedet sich mit einem Bluescreen, was die Vermutung nahelegt, dass die WndProc mehrmals Asynchron aufgerufen wird, und deshalb meine Variable nach dem ersten Senden noch nicht gesetzt ist, was mehrmaliges Senden verursacht.)

Selbiges will ich auch beim Entladen des Hooks (durch schließen des Prozesses/Fenster, an dem die geladenen Instanz des Hooks momentan hängt, realisieren. Das funktioniert soweit auch in der Theorie (Das ist der Abschnitt, wo ich auf WM_Destroy prüfe). Die Praxis jedoch sagt mir, dass der Vergleich if IsWindowVisible(PCWPStruct(lParam)^.hwnd) and not boolean(GetWindowLong(PCWPStruct(lParam)^.hwnd, GWL_HWNDPARENT)) then , in dem Moment, wo ich die WM_Destroy abfangen könnte, nicht mehr zutrifft. Hrm

Ein weiteres Kuriosum, ist, wenn ich diesen Check (in dem Delphi Tag, über diesem Satz), auslasse. Denn dann verabschieden sich, scheinbar nach keiner erkennbaren Ordnung verschiedene Prozesse. Vor allem Antivir scheint sich recht früh zu verabschieden (Aber ich brauche ja sowieso nur die Fenster, die auch in der Taskleiste, also Visible, sichtbar sind).
Dies veranlasst mich, als einen Menschen der gerade vor ein paar Tagen mit Hooks zum ersten mal zu tun hatte, unsicher zu werden, ob der Code überhaupt fehlerfrei laufen kann oder ob ich kompletten Unfug zusammengebastelt habe. (Der Grund wieso der komplette Code unten hängt. Ich würde mich freuen, wenn mal schnell eine Grob drüber schaut ).

Außerdem fiel mir auf, dass ich, wenn ich "CallNextHookEx" aufrufe, ja kein Handle übergeben kann, denn dieses ist ja nur in der Instanz des Hooks gesetzt, welche im Mainprogramm steckt. Ein wenig Suchen machte mich darauf aufmerksam, dass dieser Gedanke gar nicht falsch ist, und man da irgendwie Globale Variable (die Prozess/Dll-Übergreifend sind?!) benutzen sollte, da sonst das Handle 0 bleibt und Windows diesen Hook als den letzten in der Kette ansieht. Wie realisieren ich solche übergreifenden Variablen?

Delphi-Quellcode:
library GlobalHook;

uses
  Windows,
  Messages,
  SysUtils,
  Classes,
  Dialogs,
  Forms;

type
  TWindowRec = record
    Handle: HWND;
    Monitor: TMonitor;
  end;

{$R *.res}

var
  HookHandle: Cardinal = 0;
  MainAppHandle: Cardinal = 0;

  WindowHandle: HWND = 0;
  Monitor: TMonitor;

function EnumWindowsProc(hWnd: hWnd; lParam: LParam): Boolean; stdcall;
var
  lTmp: PChar;
  lWindowTitle: string;
  lWindowClass: string;
begin
  GetMem(lTmp, 128);
  FillChar(lTmp^, 128, 0);
  GetWindowText(hWnd, lTmp, 127);
  lWindowTitle := lTmp;

  FillChar(lTmp^, 128, 0);
  GetClassName(hWnd, lTmp, 127);
  lWindowClass := lTmp;
  FreeMem(lTmp);

  if (Pos('tfrmmain', LowerCase(lWindowClass)) <> 0) and
    (Pos('narf', LowerCase(lWindowTitle)) <> 0) then
  begin
    MainAppHandle := hWnd;
    Result := False;
  end
  else
  begin
    Result := True;
  end;
end;

procedure SendContent(AWindow: HWND; AMessage: string);
var
  cdWork: TCopyDataStruct;
begin
  // CopyData Struktur füllen
  cdWork.dwData := 0;
  cdWork.cbData := Length(AMessage) + 1;
  cdWork.lpData := AllocMem(cdWork.cbData); // Speicher reservieren
  try
    // Und Dateinamen eintragen
    CopyMemory(cdWork.lpData, @AMessage[1], cdWork.cbData - 1);
    // Fertig, Daten kopieren
    SendMessage(AWindow, WM_COPYDATA, application.handle, lParam(@cdWork));
  finally
    // Speicher wieder freigeben
    FreeMem(cdWork.lpData, cdWork.cbData);
  end;
end;

function GlobalWindowHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM):
 LRESULT; stdcall;
var
  CurrentWinMonitor: TMonitor;
begin
  Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
  case nCode < 0 of
    False:
    begin
      if IsWindowVisible(PCWPStruct(lParam)^.hwnd) and not
        boolean(GetWindowLong(PCWPStruct(lParam)^.hwnd, GWL_HWNDPARENT)) then
      begin
        if WindowHandle = 0 then
        begin
          WindowHandle := PCWPStruct(lParam)^.hwnd;
          Monitor := Screen.MonitorFromWindow(PCWPStruct(lParam)^.hwnd);
        end;
        if MainAppHandle = 0 then
        begin
          EnumWindows(@EnumWindowsProc, 0);
        end;
        if PCWPStruct(lParam)^.message = WM_MOVING then
        begin
          CurrentWinMonitor := Screen.MonitorFromWindow(PCWPStruct(lParam)^.hwnd);
          if Monitor <> CurrentWinMonitor then
          begin
            Monitor := CurrentWinMonitor;
            SendContent(MainAppHandle, IntToStr(Monitor.MonitorNum) + ':' +
              IntToStr(WindowHandle));
          end;
        end;
        if PCWPStruct(lParam)^.message = WM_DESTROY then
        begin
          SendContent(MainAppHandle, 'd:' + IntToStr(WindowHandle));
        end;
      end;
    end;
  end;
end;

function InstallHook(Hwnd: Cardinal): Boolean; stdcall;
begin
  Result := False;
  if HookHandle = 0 then
  begin
    HookHandle := SetWindowsHookEx(WH_CALLWNDPROC, @GlobalWindowHook, HInstance,
      0);
    MainAppHandle := Hwnd;
    Result := TRUE;
  end;
end;

function UninstallHook: Boolean; stdcall;
begin
  Result := UnhookWindowsHookEx(HookHandle);
  HookHandle := 0;
end;

exports
  InstallHook,
  UninstallHook;

begin

end.
Hmm, ich würde mich alleine schon deswegen freuen, wenn jemand meinen Roman hier überhaupt liest

Danke & Grüße,
Max
Max
„If you have any great suggestions, feel free to mail me, and I'll probably feel free to ignore you.“ . Linus Torvalds
  Mit Zitat antworten Zitat