Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Start eines Keyboard-Hooks aus einem Thread (https://www.delphipraxis.net/170258-start-eines-keyboard-hooks-aus-einem-thread.html)

hesch21 7. Sep 2012 15:36

Start eines Keyboard-Hooks aus einem Thread
 
Hallo

Ich habe einen LowLevel-Keyboard-Hook ohne DLL, der an sich prächtig funktioniert. Nun sollte das Ding aber auf allen Desktops funktionieren (Default, Winlogon und Screen-Saver). Auch das tut es eigentlich. Auf XP generell, aber unter W-7 spinnen die meisten 3-D-Screen-Saver. Da ich bereits mal Mühe hatte, diese Dinger aus meinem Programm zu beenden und Microsoft bemühen musste (man muss für's Senden einer Message einen separaten Thread eröffnen), bin ich auf die Idee gekommen, das könnte auch beim KeyboardHook helfen. Faul wie ich bin, habe ich in meinem Testprogramm mal schnell eine TJvThread-Komponente auf's Formular geschmissen. Und nun habe ich zwei Varianten:
Code:
procedure TFAMMonitor.FormCreate(Sender: TObject);
begin
  Pfad    := ExtractFilePath(ParamStr(0));
  TCode1   := 34;
  TCode2   := 33;
  Zwei    := 0;
  FTDT    := CheckDesktopIsActive();
  IniDT   := copy(FTDT, 1, 2);
  AssignFile(filno,Pfad + 'AMTest.log');
  if FileExists(Pfad + 'AMTest.log') then
     DeleteFile(Pfad + 'AMTest.log');
  Rewrite(filno);
  Writeln(filno, TimeToStr(Now) + ' ' + FTDT);
  CloseFile(filno);
  Durch := False;
  JvThread1.Execute(Self);
{  HookTastatur := SetWindowsHookEx(WH_KEYBOARD_LL, @CallBackDelHook, HInstance , 0);
  Durch := True;  }
  while not Durch do
        sleep(100);
  AssignFile(filno,Pfad + 'AMTest.log');
  Append(filno);
  if HookTastatur <> 0 then
     Writeln(filno, TimeToStr(Now) + ' Hook gesetzt')
  else
     Writeln(filno, TimeToStr(Now) + ' Hook nicht gesetzt');
  CloseFile(filno);
  if not ((IniDT = 'Sc') and (CompInfo.OS.OSVersion = wvWin7)) then
     begin
     ShowWindow(Application.handle, SW_HIDE);
     SetWindowLong(Application.handle, GWL_EXSTYLE,
             GetWindowLong(application.handle, GWL_EXSTYLE) and
             not WS_EX_APPWINDOW or WS_EX_TOOLWINDOW);
     end;
 Timer1.Enabled := True;
 Timer2.Enabled := true;
end;
Das ganze ist ziemlich hässlich programmiert, dessen bin ich mir bewusst (z.B. die Ausbremserei bis der Thread durch ist). Ist ein Testprogramm! Wenn ich das Programm so laufen lassen wie hier, funktioniert der Hook nicht, wenn ich aber die Klammern um JvThread1.Execute(Self); setze und unten wegnehme, funktionierts. So, und hier der Thread:

Code:
procedure TFAMMonitor.JvThread1Execute(Sender: TObject; Params: Pointer);
var hDeskWnd : HDESK;
var hifil   : Textfile;
begin
   hDeskWnd := OpenDesktop('Default', 0, false, MAXIMUM_ALLOWED);
   if hDeskWnd <> 0 then
      begin
      if SetThreadDesktop(hDeskWnd) then
         begin
         AssignFile(hifil, Pfad + 'AMTest.log');
         Append(hifil);
         Writeln(hifil, TimeToStr(Now) + ' DesktopThread gesetzt');
         CloseFile(hifil);
         HookTastatur := SetWindowsHookEx(WH_KEYBOARD_LL, @CallBackDelHook, HInstance, 0);
         end;
      CloseDesktop(hDeskWnd);
      end;
   Durch := True;
end;
Die Ausbremserei oben übrigens wegen der Textdatei. An sich läuft der Thread richtig durch und der Hook wird 'eigentlich' gesetzt, nur reagiert er nicht. Und anstelle von HInstance habe ich schon alle erdenklichen Varianten versucht. 0 geht nicht, mit FindHInstance(@FAMMonitor) oder FindHInstance(@TFAMMonitor.JvThread1Execute) läuft er zwar ebenfalls durch und liefert einen Wert HookTastatur <> 0, aber er kommt mir nie auf die CallBack-Funktion.
Die SetWindowsHookEx ist an beiden Orten identisch. Und das OpenDesktop auf 'Default' ist natürlich nur für Testzwecke. Da käme dann 'Screen-Saver' rein. Aber wenn der Hook schon auf 'Default' nicht geht ...

Und anzumerken wäre auch noch, dass ich es auch schon erfolglos mit einer DLL versucht habe. Und für's ganze warum und wieso gibt's bereits einen anderen Thread. Deshalb hier nur noch kurz: Mein Alarmierungssystem muss eine Tastenkombination in jedem Zustand des Rechners abfangen können.

Hat jemand eine Idee, warum ich den Hook nicht aus einem Thread laden kann?

delphinub23 7. Sep 2012 16:38

AW: Start eines Keyboard-Hooks aus einem Thread
 
Zeig mal bitte wie du
Zitat:

@CallBackDelHook
implementiert hast.

hesch21 10. Sep 2012 07:42

AW: Start eines Keyboard-Hooks aus einem Thread
 
Die CallBack-Funktion fängt nur die Tastenkombination PageUp/PageDown ab. Deshalb TCode1 := 34 und TCode2 := 33.
Hier der Code:
Code:
{Abhandeln von Tasteneingaben}
function CallBackDelHook(Code:Integer; wParam:WPARAM; lParam:LPARAM): LRESULT; stdcall;
var SendStr : string;
begin
 if code = HC_ACTION then
    begin
    if (wParam = WM_KEYDOWN) and (Zwei = 0) then
       begin
       Erster := PKBDLLHookInfo(lParam).vkCode;
       Zwei   := 1;
       end;
    if (wParam = WM_KEYDOWN) and (Zwei = 1) then
       begin
       if PKBDLLHookInfo(lParam).vkCode <> Erster then
          begin
          Zweiter := PKBDLLHookInfo(lParam).vkCode;
          Zwei   := 2;
          end;
       end;
    if (wParam = WM_KEYUP) and (Zwei <> 2) then
       Zwei   := 0;
    if (wParam = WM_KEYUP) and (Zwei = 2) then
       begin
       Zwei   := 0;
       SendStr := 'AMTTHook ' + format('%3d', [Erster]) +  '¦' + format('%3d', [Zweiter]);
       if ((Erster = TCode1) and (Zweiter = TCode2)) or ((Erster = TCode2) and (Zweiter = TCode1)) then
          begin
          AssignFile(filno,Pfad + 'AMTest.log');
          Append(filno);
          Writeln(filno, TimeToStr(Now) + ' ' + SendStr);
          CloseFile(filno);
          end;
       end;
    end;
  Result := CallNextHookEx(HookTastatur, Code, wParam, lParam)
end;
Auch da gilt: ist eine Test-Variante. Normalerweise würde der SendStr nicht in eine Datei geschrieben sondern über TCP/IP (Indy) zusammen mit ein paar weiteren Angaben an ein Steuerungsprogramm im Netz übermittelt.

delphinub23 10. Sep 2012 09:38

AW: Start eines Keyboard-Hooks aus einem Thread
 
Ich kenne diese Thread-Komponente nicht - Bist du dir sicher, dass diese Thread-Komponente auch eine Nachrichtenschleife besitzt?
Ich glaube mich zu erinnern, dass ein Thread, der einen Hook hält, auch eine Nachrichtenschleife braucht.

hesch21 10. Sep 2012 10:03

AW: Start eines Keyboard-Hooks aus einem Thread
 
In der erwähnten Rountine zum 'Abschiessen' des Screen-Savers verwende ich die Komponente wie folgt:
Code:
procedure TForm1.BLKillerExecute(Sender: TObject; Params: Pointer);
var hDeskWnd : HDESK;
var Inp     : TInput;
begin
   hDeskWnd := OpenDesktop('Screen-saver', 0, false, MAXIMUM_ALLOWED);
   if hDeskWnd <> 0 then
      begin
      if SetThreadDesktop(hDeskWnd) then
         begin
         Inp.Itype := INPUT_KEYBOARD;
         Inp.ki.wVk := Ord('A');
         Inp.ki.dwFlags := 0;
         SendInput(1, Inp, SizeOf(Inp));
         Inp.Itype := INPUT_KEYBOARD;
         Inp.ki.wVk := Ord('A');
         Inp.ki.dwFlags := KEYEVENTF_KEYUP;
         SendInput(1, Inp, SizeOf(Inp));
         Application.ProcessMessages;
         Sleep(80);
         end;
      CloseDesktop(hDeskWnd);
      end
   else
      PostMessage(GetForegroundWindow(), WM_CLOSE, 0, 0);
end;
Wenn das geht, heisst das nicht, dass eine Nachrichtenschleife vorhanden ist?

delphinub23 10. Sep 2012 10:08

AW: Start eines Keyboard-Hooks aus einem Thread
 
Zitat:

Wenn das geht, heisst das nicht, dass eine Nachrichtenschleife vorhanden ist?
Ja, es gibt eine Nachrichtenschleife. Aber nur für dein Formular, nicht für den Thread.
Das Thread-Objekt benötigt eine eigene Nachrichtenschleife, sonst bekommt der Thread doch keine Callback-Nachricht.

hesch21 10. Sep 2012 10:24

AW: Start eines Keyboard-Hooks aus einem Thread
 
Dämlich, dämlich!

So wie ich das gemacht habe, wird der Thread ausgeführt und sofort wieder beendet. Und damit halt auch der Hook. Ein JvThread1.WaitFor; hat Abhilfe gebracht und jetzt funktionierts.

Jetzt kann ich dahinter, auszuprobieren, ob's auch auf Screen-Saver-Ebene klappt.

Danke für die Unterstützung!

delphinub23 10. Sep 2012 11:39

AW: Start eines Keyboard-Hooks aus einem Thread
 
Zitat:

Dämlich, dämlich!

So wie ich das gemacht habe, wird der Thread ausgeführt und sofort wieder beendet. Und damit halt auch der Hook. Ein JvThread1.WaitFor; hat Abhilfe gebracht und jetzt funktionierts.

Jetzt kann ich dahinter, auszuprobieren, ob's auch auf Screen-Saver-Ebene klappt.

Danke für die Unterstützung!
Eine Frage:
Der Hook funktioniert nun dauerhaft ohne eine Nachrichtenschleife im Thread-Objekt selbst?

Würde mich wundern. Ich dachte, dass die Callback-Funktion nur einmal aufgerufen wird und nach der Abarbeitung des Threads schließt sich dieser und damit auch der Hook.

hesch21 10. Sep 2012 13:28

AW: Start eines Keyboard-Hooks aus einem Thread
 
Ja, eigentlich hast Du schon recht, aber ich habe den Thread ja wie bereits erwähnt testeshalber einfach ganz bösartig ausgebremst, indem ich im Thread selbst ein WaitFor auf den Thread gesetzt habe. Der wird nie fertig und drum geht das.
Wie gesagt, das ganze war nur für Testzwecke und inzwischen habe ich leider feststellen müssen, dass auch das nichts hilft, um auf WinSta0\Screen-Saver verlässlich einen KeyboardHook zu setzen. Das ganze ist einfach zum heulen. Bei XP klappts immer, bei W-7 klappt's bei ein paar Bildschirmschonern (z.B. beim Seifenblasen), bei anderen aber nicht (z.B. Schleifen, 3D-Text). Und den 3D-Text gibt's ja auch schon bei XP.
Und das seltsame ist, dass eigentlich der Hokk gesetzt wird (ich bekomme ein Handle zurück), nur die CallBackFunktion wird nie angesteuert. Wenn da noch irgend jemand eine Idee hat, woran das liegen könnte, meine letzte Idee war jetzt die mit dem Start des Hooks aus einem Thread.

delphinub23 10. Sep 2012 13:54

AW: Start eines Keyboard-Hooks aus einem Thread
 
Wenn du deine Applikation mit Adminrechten aufrufst, funktioniert dann die Callback-Prozedur zuverlässig?


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:02 Uhr.
Seite 1 von 2  1 2      

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