AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Ein paar weitere Fragen zu Windows-Hooks

Ein paar weitere Fragen zu Windows-Hooks

Ein Thema von Prototypjack · begonnen am 29. Aug 2007 · letzter Beitrag vom 29. Aug 2007
Antwort Antwort
Prototypjack

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

Ein paar weitere Fragen zu Windows-Hooks

  Alt 29. Aug 2007, 12: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
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: Ein paar weitere Fragen zu Windows-Hooks

  Alt 29. Aug 2007, 13:12
Über das Problem mit den globalen Variablen in Hooks bin ich auch schon gestolpert. Wenn es um das Verschicken von Daten geht, solltest du dir unbedingt Mailslots anschauen, damit lässt sich das Problem recht gut lösen (Hilfe zu Mailslot ist natürlich in der MSDN). Du musst dann allerdings den Namen des Mailslots hartcodieren. Selbiges gilt für Memory-Mapped-Files, die ebenfalls für "ganz globale Variablen" eingesetzt werden können.
Hoffe geholfen zu haben
Apollonius
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:47 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz