Autor Beitrag
alias5000
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: Mi 25.10.06 22:19 
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 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:
ausblenden 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 gehört zum Keyboardhook
    KBHHandle := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc,
    HInstance, 0);
    //...
    Result := TRUE;
  end;
  if (MHHandle = 0and (result) then begin //das hier steht dann für den Maushook
    MHHandle := SetWindowsHookEx(WH_MOUSE, @MouseHookProc, HInstance, 0);
  end else begin
    Result := true;
  end;
//...
//anschließend wird nur noch ein nonVCL- Timer erstellt, um in Zeitintervallen vergleichen zu können. An dem liegt das Probloem mit dem "Fokus" aber nicht, habs bereits getestet
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.
ausblenden 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); //Zur Erinnerung MHHandle ist das Handle des Maushooks
  if (nCode < 0then begin
    exit;
  end;
  //ab hier wird angenommen, dass eine Eingabe mit der Maus kam
  //...
end;



Ich hoffe ihr könnt damit was anfangen

Gruß alias5000

_________________
Programmers never die, they just GOSUB without RETURN
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 25.10.06 23:44 
Liegt der Code auch in einer DLL?
Reinhard Kern
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 591
Erhaltene Danke: 14



BeitragVerfasst: Do 26.10.06 03:18 
user profile iconalias5000 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 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.
ausblenden 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); //Zur Erinnerung MHHandle ist das Handle des Maushooks
  if (nCode < 0then begin
    exit;
  end;
  //ab hier wird angenommen, dass eine Eingabe mit der Maus kam
  //...
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: 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
Einloggen, um Attachments anzusehen!
_________________
Programmers never die, they just GOSUB without RETURN
alias5000 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: Do 26.10.06 16:08 
Ok, ich habe eine neue (noch nicht fertige) Version von Asserbads Tutorial auf seiner Seite gefunden.assarbad.net/stuff/t...ks/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

_________________
Programmers never die, they just GOSUB without RETURN
netspy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 75



BeitragVerfasst: Do 21.12.06 01:36 
user profile iconalias5000 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:

ausblenden Quelltext
1:
2:
WH_KEYBOARD  Thread or global
WH_MOUSE     Thread or global

Mario

_________________
So Long, and Thanks for All the Fish.
alias5000 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: 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

_________________
Programmers never die, they just GOSUB without RETURN
netspy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 75



BeitragVerfasst: Do 21.12.06 18:02 
user profile iconalias5000 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

_________________
So Long, and Thanks for All the Fish.
alias5000 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: 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

_________________
Programmers never die, they just GOSUB without RETURN
netspy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 75



BeitragVerfasst: Do 21.12.06 23:16 
user profile iconalias5000 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.

_________________
So Long, and Thanks for All the Fish.
alias5000 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: 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

_________________
Programmers never die, they just GOSUB without RETURN
netspy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 75



BeitragVerfasst: 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.

_________________
So Long, and Thanks for All the Fish.
alias5000 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: 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

_________________
Programmers never die, they just GOSUB without RETURN
Raffo
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 300



BeitragVerfasst: Fr 22.12.06 06:46 
user profile iconalias5000 hat folgendes geschrieben:
Konkret geht es um die Implementierung eines automatischen Away- Modus in einem Chatprogramm.


siehe hier www.delphi-forum.de/...2&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

ausblenden 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// Ausgabe in Sekunden

if d>5 then
   idleTimeLabel.Color:=clred // user inactive
else
   idleTimeLabel.Color:=clgreen; // user active

idleTimeLabel.Caption := Format('Idle since %d s', [d]);
end;
netspy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 75



BeitragVerfasst: Fr 22.12.06 12:31 
user profile iconalias5000 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.

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.

_________________
So Long, and Thanks for All the Fish.
alias5000 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: 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

_________________
Programmers never die, they just GOSUB without RETURN
thepaine91
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 763
Erhaltene Danke: 27

Win XP, Windows 7, (Linux)
D6, D2010, C#, PHP, Java(Android), HTML/Js
BeitragVerfasst: 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:

ausblenden Delphi-Quelltext
1:
var MHHandle: Cardinal;					

MHHandle wird i-wo ein Wert zugewiesen. z.B.

ausblenden Delphi-Quelltext
1:
2:
procedure installHook(Hwnd: Thandle);  // o. (Hwnd: Cardinal)
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.