![]() |
Ein paar weitere Fragen zu Windows-Hooks
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
Delphi-Quellcode:
, in dem Moment, wo ich die WM_Destroy abfangen könnte, nicht mehr zutrifft. Hrm :?
if IsWindowVisible(PCWPStruct(lParam)^.hwnd) and not boolean(GetWindowLong(PCWPStruct(lParam)^.hwnd, GWL_HWNDPARENT)) then
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:
Hmm, ich würde mich alleine schon deswegen freuen, wenn jemand meinen Roman hier überhaupt liest :mrgreen:
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. Danke & Grüße, Max |
Re: Ein paar weitere Fragen zu Windows-Hooks
Ü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 |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz