Entwickler-Ecke
Windows API - Tastatur- und Maushook reagiert nicht systemweit
alias5000 - Mi 25.10.06 22:19
Titel: Tastatur- und Maushook reagiert nicht systemweit
Hi!
Ich habe mir, um festzustellen,
ob (also nicht welche) in einer bestimmten Zeitspanne Eingaben via Tastatur oder Maus gemacht wurden, einen Tastatur- und einen Maushook geschrieben. Ich habe mich daran am Tutorial von
http://www.dsdt.info orientiert.
Konkret geht es um die Implementierung eines automatischen Away- Modus in einem Chatprogramm.
Allerdings habe ich das Problem, dass mein folgender Code nur Nachrichten abfängt, wenn die Maus über einer Form der Anwendung ist, bzw. die Tastatureingabe an meine Anwendung geht (sie also den Fokus hat). Bewegt sich die Maus abseits einer Form der Anwendung, bzw. geht eine Tastatureingabe an ein anderes Programm als meins, so scheint der Hook gar nichts mitzubekommen. Zusätzlich habe ich das chronische Problem, ständig neu booten zu müssen (allerdings erst, wenn der Hook schon eine Weile läuft). Es scheint also ein Fehler in der Anwendung der Hooks zu sein und nicht, dass ich bloß die falschen Features oder so benutze ;)
Meine beiden Hooks erstelle ich so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| function StartAwayMonitoring(Hwnd: Cardinal; AlertProc: TAlertProc; Intervall: integer): Boolean; stdcall; begin Result := False; if KBHHandle = 0 then begin KBHHandle := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc, HInstance, 0); Result := TRUE; end; if (MHHandle = 0) and (result) then begin MHHandle := SetWindowsHookEx(WH_MOUSE, @MouseHookProc, HInstance, 0); end else begin Result := true; end; end; |
Als Handle in StartAwayMonitoring übergebe ich in der aufrufenden Anwendung
Application.Handle.
Den Code zum deinstallieren der Hooks lass ich mal weg, da er ja hier nicht von Relevanz sein wird.
Interessant könnte nich die HookProcedure sein. Ich habe hier mal die vom Maushook reingestellt, die vom Keyboard ist äquivalent aufgebaut.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin Result := CallNextHookEx(MHHandle, nCode, wParam, lParam); if (nCode < 0) then begin exit; end; end; |
Ich hoffe ihr könnt damit was anfangen
Gruß alias5000
Delete - Mi 25.10.06 23:44
Liegt der Code auch in einer DLL?
Reinhard Kern - Do 26.10.06 03:18
Titel: Re: Tastatur- und Maushook reagiert nicht systemweit
alias5000 hat folgendes geschrieben: |
Hi!
Ich habe mir, um festzustellen, ob (also nicht welche) in einer bestimmten Zeitspanne Eingaben via Tastatur oder Maus gemacht wurden, einen Tastatur- und einen Maushook geschrieben. Ich habe mich daran am Tutorial von http://www.dsdt.info orientiert.
Konkret geht es um die Implementierung eines automatischen Away- Modus in einem Chatprogramm.
Allerdings habe ich das Problem, dass mein folgender Code nur Nachrichten abfängt, wenn die Maus über einer Form der Anwendung ist, bzw. die Tastatureingabe an meine Anwendung geht (sie also den Fokus hat). Bewegt sich die Maus abseits einer Form der Anwendung, bzw. geht eine Tastatureingabe an ein anderes Programm als meins, so scheint der Hook gar nichts mitzubekommen. Zusätzlich habe ich das chronische Problem, ständig neu booten zu müssen (allerdings erst, wenn der Hook schon eine Weile läuft). Es scheint also ein Fehler in der Anwendung der Hooks zu sein und nicht, dass ich bloß die falschen Features oder so benutze ;)
....
Interessant könnte nich die HookProcedure sein. Ich habe hier mal die vom Maushook reingestellt, die vom Keyboard ist äquivalent aufgebaut.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin Result := CallNextHookEx(MHHandle, nCode, wParam, lParam); if (nCode < 0) then begin exit; end; end; |
Ich hoffe ihr könnt damit was anfangen
Gruß alias5000 |
Hallo,
zu CallNextHookEx: geht irgendetwas in der Hook-Kette schief (auch Kollegen können Fehler machen, an dieser Stelle ganz besonders), kehrt dieser Call nie zurück, deine Bearbeitung kommt also nie zum Zug. Das würde auch die Fehler erklären: deine Hook-Routine wird immer wieder aufgerufen, kehrt aber nie zurück und bereinigt daher auch nie den Stack vom Aufruf.
Ich würde mal testhalber meine eigene Bearbeitung VOR CallNextHookEx ausführen oder CallNextHookEx ganz weglassen; Laut SDK ist CallNextHookEx optional, aber natürlich werden dann andere Hooks nicht mehr bedient, also ist das Weglassen zumindest unfein.
Gruss Reinhard
alias5000 - Do 26.10.06 15:37
(das ist jetzt der vierte Anlauf diesen Text zu schreiben, nachdem ich den PC dreimal lahmgelegt hatte :autsch: )
@Luckie: Danke. Ne, aber das ist schon in der DLL :wink:
@Reinhard:
Naja, das Problem liegt wanders. (Ich rede jetzt mal nur vom Maushook, aber der Tastaturhook verhält sich entsprechend)
Es ist vielmehr so, dass der Hook korrekt arbeitet (was das bekommen der Nachrichten betrifft), solange sich die Maus auf einer Form meiner Anwendung befindet. Wenn ich aber die Maus nicht mehr über einer Form meiner Anwendung bin, wird die HookProcedure nachweislich nicht mehr aufgerufen. (habs einfach mit Beep ausgeben lassen ;) ). Wenn ich das CallNextHookEx rauslasse, habe ich mit dem gesamten System ein ziemliches Problem, weil ich nix mehr steuern kann. Wenn ich das ans Ende setze, hab ich dasselbe Verhalten, wie wenns vorne dran steht. Also existiert kein Problem mit fremden Hooks.
Was mir noch spanisch vorkommt ist das ständige Abschmieren, meines Programms, wenn der Hook aktiv ist.
Zu dem Zweck hänge ich die entsprechende Hook- Unit mal unten an.
Kleine Funktionsbeschreibung dazu:
Es geht wie gesagt darum, einen automatischen Away-Modus in einem Chat zu realisieren. Dazu starte ich die "Überwachung", wie es mit der Eingabeaktivität (an Tastatur und Maus) aussieht mit StartAwayMonitoring. StopAwayMonitoring ist dann das entsprechende Gegenstück dazu. Zur Überwachung, ob man away ist, habe ich, um die DLL klein zu halten, einen nonVCL Timer integriert. Die TAlertProc ist die Prozedur, die dann aufgerufen wird, wenn sich der Away-Status verändert. Diese Procedure wird beim Aufruf von StartAwayMonitoring durch die Hauptanwendung an die DLL übergeben, so dass man das ganze eigentlich als ganz normales Event bezeichnen könnte.
Gruß alias5000
alias5000 - Do 26.10.06 16:08
Ok, ich habe eine neue (noch nicht fertige) Version von Asserbads Tutorial auf seiner Seite gefunden.
http://assarbad.net/stuff/tutorials/hooks/hook_tutorial.pdf
Das Problem liegt wohl am verwendeten Hook. Es ist klar, dass ich außerhalb meiner Forms nix mitbekommen kann, wenn ich nur einen Thread-lokal Hook (WH_MOUSE, WH_KEYBOARD) verwende. Ich hab jetzt mal stattdessen WH_KEYBOARD_LL und WH_MOUSE_LL gesetzt (die systemglobal sind). Jetzt funktionierts. Anscheinend auch ohne Abstürze.
Jetzt hab ich halt noch das Problem, dass die (laut Tut) nur unter NT-Systemen funktionieren. Muss mich da mal erkundigen, wie ich das ändern kann, damit ich auch Win 98/ME unterstützen kann, ohne auf den Hook verzichten zu müssen.
Gruß alias5000
netspy - Do 21.12.06 01:36
alias5000 hat folgendes geschrieben: |
Das Problem liegt wohl am verwendeten Hook. Es ist klar, dass ich außerhalb meiner Forms nix mitbekommen kann, wenn ich nur einen Thread-lokal Hook (WH_MOUSE, WH_KEYBOARD) verwende. Ich hab jetzt mal stattdessen WH_KEYBOARD_LL und WH_MOUSE_LL gesetzt (die systemglobal sind). Jetzt funktionierts. Anscheinend auch ohne Abstürze.
Jetzt hab ich halt noch das Problem, dass die (laut Tut) nur unter NT-Systemen funktionieren. Muss mich da mal erkundigen, wie ich das ändern kann, damit ich auch Win 98/ME unterstützen kann, ohne auf den Hook verzichten zu müssen. |
WH_MOUSE und WH_KEYBOARD sind schon richtig und funktionieren auch global. So stehts auch in der Win-API Doku:
Quelltext
1: 2:
| WH_KEYBOARD Thread or global WH_MOUSE Thread or global |
Mario
alias5000 - Do 21.12.06 18:00
Und wie unterscheide ich das? Ich finde in meinem PSDK nix zu.. :roll:
Bisher habe ich das mit den Konstanten für NT-Systeme realisiert. Unter Win 9x funktioniert der Hook leider nur lokal auf diese Weise
Gruß alias5000
netspy - Do 21.12.06 18:02
alias5000 hat folgendes geschrieben: |
Und wie unterscheide ich das? Ich finde in meinem PSDK nix zu.. :roll:
Bisher habe ich das mit den Konstanten für NT-Systeme realisiert. Unter Win 9x funktioniert der Hook leider nur lokal auf diese Weise |
Unter Wind 9x kann ich hier nicht mehr testen. Auf XP geht WH_MOUSE aber auf jeden Fall global.
Mario
alias5000 - Do 21.12.06 18:48
Ich hab das jetzt mal die Konstanten durch WH_MOUSE und WH_KEYBOARD ersetzt, aber unter XP bekomme ich damit nur einen lokalen Hook, so wie es im Tut. von Asserbad steht. Was unter Win98 passiert hab ich noch nicht getestet. Dort bekam ich mit WH_MOUSE_LL halt bisher immer einen lokalen Mousehook (und entsprechend Keyboard)
EDIT: unter Win98 ist der auch nur lokal, nicht global
netspy - Do 21.12.06 23:16
alias5000 hat folgendes geschrieben: |
Ich hab das jetzt mal die Konstanten durch WH_MOUSE und WH_KEYBOARD ersetzt, aber unter XP bekomme ich damit nur einen lokalen Hook, so wie es im Tut. von Asserbad steht. |
Nein, das steht da nicht. Auf Seite 15 im PDF wird WH_MOUSE und WH_KEYBOARD für den globalen Hook gesetzt und das funktioniert auch so. Vielleicht hast du die Hook-Prozedur nicht in einer extra DLL. Das würde erklären, warum es bei dir nur lokal und nicht global funktiniert.
alias5000 - Do 21.12.06 23:31
Der Code ist der, der da oben steht. Das ganze habe ich schon in einer extra DLL, die statisch mit meiner Anwendung gelinkt wird.
Gruß alias5000
netspy - Do 21.12.06 23:43
Dann kann ich es leider auch nicht erklären. WH_MOUSE und WH_KEYBOARD sind auf jeden Fall global, so stehts in der API-Doku, bei Asserbad und so funktioniert es auch bei mir unter XP.
alias5000 - Do 21.12.06 23:46
Könntest du evtl. deinen Code nochmal posten, wenn du sagst, dass es bei dir geht?
Vllcht gibts doch irgendwie, irgendwo einen entscheidenden Unterschied...
(oder auch per PN)
Wäre sehr nett von dir
Gruß alias5000
Raffo - Fr 22.12.06 06:46
Titel: Re: Tastatur- und Maushook reagiert nicht systemweit
alias5000 hat folgendes geschrieben: |
Konkret geht es um die Implementierung eines automatischen Away- Modus in einem Chatprogramm.
|
siehe hier
http://www.delphi-forum.de/viewtopic.php?t=66512&highlight=idle very simple, ohne DLL, ohne Hook.
Könnte man auch ohne Funktionsaufruf implementieren, Timer "idleTimer" auf TForm setzen (Interval z.B. 5 Sek.)
und ein Label "idleTimeLabel", ach ja, das Ganze funzt erst ab D5
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm1.idleTimerTimer(Sender: TObject); var d:longint; LInput: TLastInputInfo; begin
LInput.cbSize := SizeOf(TLastInputInfo); GetLastInputInfo(LInput); d := (GetTickCount - LInput.dwTime) div 1000; if d>5 then idleTimeLabel.Color:=clred else idleTimeLabel.Color:=clgreen; idleTimeLabel.Caption := Format('Idle since %d s', [d]); end; |
netspy - Fr 22.12.06 12:31
alias5000 hat folgendes geschrieben: |
Könntest du evtl. deinen Code nochmal posten, wenn du sagst, dass es bei dir geht? |
Mein Code ist vom Prinzip nicht anders als deiner. Ich kann zumindest keine Unterschiede erkennen, die erklären würden, warum es bei dir nicht geht. Gerade habe ich aber noch eine bessere Möglichkeit gefunden, wie man Mouse- und Tastaturereignisse außerhalb der Anwendung auch ohne DLL abfangen kann.
http://www.delphipraxis.net/post654235.html
Das erste Beispiel von Mazel mit einem JournalRecordProc Hook funktioniert super, kommt ohne DLL aus und geht laut API-Doc ab Windows 95. Da das Ereignis dann im Thread-Kontext der eigenen Anwendung erfolgt, kann man sich SendMessage oder MMF auch gleich sparen.
alias5000 - Fr 22.12.06 15:23
Hm zwei sehr interessante Lösungen :) Vielen Dank!
Mal schaun, was ich dann verwende ;)
Gruß alias5000
Edit: Schade, Raffos Variante funktioniert erst ab Windows 2000, hat also noch größere Einschränkungen als mein Hook (ab Win NT). Ich versuch jetzt mal die andere Variante, die ja ab Win95 laufen soll :D
thepaine91 - Mo 26.10.09 12:35
Auch wenn das hier ganz schön alt ist Antworte ich trotzdem mal falls jemand auf das Thema stößt und das selbe Problem hat.
Dein Fehler ist sicher folgender:
Delphi-Quelltext
1:
| var MHHandle: Cardinal; |
MHHandle wird i-wo ein Wert zugewiesen. z.B.
Delphi-Quelltext
1: 2:
| procedure installHook(Hwnd: Thandle); MHHandle := Hwnd; |
Problem wäre in dem fall folgendes:
Daten in Dlls liegen immer im Aufrufendem Prozess d.h. nur dein eigenes Programm hat den Wert MHHandle dem zu folge funktioniert der Hook nur dann wenn die Maus auf deinem Fenster ist.
Ist sie auf einem anderen Bereich hat MHHandle i-einen Wert nur sicher nicht den richtigen.
In dem fall z.B. CreateFileMapping ansehen. Gibt noch mehr möglichkeiten dazu.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!