AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Start eines Keyboard-Hooks aus einem Thread

Start eines Keyboard-Hooks aus einem Thread

Ein Thema von hesch21 · begonnen am 7. Sep 2012 · letzter Beitrag vom 13. Sep 2012
Antwort Antwort
Seite 1 von 2  1 2   
hesch21

Registriert seit: 31. Aug 2004
Ort: Basel
114 Beiträge
 
Delphi XE2 Enterprise
 
#1

Start eines Keyboard-Hooks aus einem Thread

  Alt 7. Sep 2012, 15:36
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?
Heinz Schneider

Geändert von hesch21 ( 7. Sep 2012 um 15:48 Uhr)
  Mit Zitat antworten Zitat
delphinub23

Registriert seit: 27. Okt 2010
Ort: Chemnitz
110 Beiträge
 
Delphi XE3 Professional
 
#2

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 7. Sep 2012, 16:38
Zeig mal bitte wie du
Zitat:
@CallBackDelHook
implementiert hast.
  Mit Zitat antworten Zitat
hesch21

Registriert seit: 31. Aug 2004
Ort: Basel
114 Beiträge
 
Delphi XE2 Enterprise
 
#3

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 07:42
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.
Heinz Schneider
  Mit Zitat antworten Zitat
delphinub23

Registriert seit: 27. Okt 2010
Ort: Chemnitz
110 Beiträge
 
Delphi XE3 Professional
 
#4

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 09:38
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.
  Mit Zitat antworten Zitat
hesch21

Registriert seit: 31. Aug 2004
Ort: Basel
114 Beiträge
 
Delphi XE2 Enterprise
 
#5

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 10:03
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?
Heinz Schneider
  Mit Zitat antworten Zitat
delphinub23

Registriert seit: 27. Okt 2010
Ort: Chemnitz
110 Beiträge
 
Delphi XE3 Professional
 
#6

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 10:08
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.
  Mit Zitat antworten Zitat
hesch21

Registriert seit: 31. Aug 2004
Ort: Basel
114 Beiträge
 
Delphi XE2 Enterprise
 
#7

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 10:24
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!
Heinz Schneider
  Mit Zitat antworten Zitat
delphinub23

Registriert seit: 27. Okt 2010
Ort: Chemnitz
110 Beiträge
 
Delphi XE3 Professional
 
#8

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 11:39
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.
  Mit Zitat antworten Zitat
hesch21

Registriert seit: 31. Aug 2004
Ort: Basel
114 Beiträge
 
Delphi XE2 Enterprise
 
#9

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 13:28
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.
Heinz Schneider
  Mit Zitat antworten Zitat
delphinub23

Registriert seit: 27. Okt 2010
Ort: Chemnitz
110 Beiträge
 
Delphi XE3 Professional
 
#10

AW: Start eines Keyboard-Hooks aus einem Thread

  Alt 10. Sep 2012, 13:54
Wenn du deine Applikation mit Adminrechten aufrufst, funktioniert dann die Callback-Prozedur zuverlässig?

Geändert von delphinub23 (10. Sep 2012 um 13:56 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

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 10:38 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