| Autor |
Beitrag |
Gausi
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: So 12.02.06 16:34
Ich hab mir gerade mal das Hook-Tutorial aus der Library angeguckt und leicht modifiziert (brauche keinen Key-Hook, sondern einen WH_SHELL-Hook). Mein dll-Code sieht so aus:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58:
| library KeyboardHook;
uses Windows, Messages, Dialogs, sysutils; var HookHandle: Cardinal = 0; MyWindowHandle: Cardinal = 0;
const APPCOMMAND_MEDIA_NEXTTRACK = 720896;
function KeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin case nCode < 0 of FALSE: begin if lparam = APPCOMMAND_MEDIA_NEXTTRACK then begin showmessage('Fange ab - ' + inttostr(MyWindowHandle)); PostMessage(MyWindowHandle,WM_APPCOMMAND,wparam,lParam); Result := 1; end else Result := CallNextHookEx(HookHandle, nCode, wParam, lParam); end; else Result := CallNextHookEx(HookHandle, nCode, wParam, lParam); end; end;
function InstallHook(Hwnd: Cardinal): Boolean; stdcall; begin Result := False; if HookHandle = 0 then begin HookHandle := SetWindowsHookEx(WH_SHELL, @KeyboardHookProc, HInstance, 0); MyWindowHandle := Hwnd; Result := True; showmessage('Installiert ' + inttostr(hwnd) + ' ' + inttostr(MyWindowHandle)); end; end;
function UninstallHook: Boolean; stdcall; begin Result := UnhookWindowsHookEx(HookHandle); HookHandle := 0; end;
exports InstallHook, UninstallHook; end. |
Mein Programm sieht im Wesentlichen so aus:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| type TForm1 = class(TForm) Label1: TLabel; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private public protected procedure MediaKey (Var aMSG: tMessage); message WM_APPCOMMAND; end;
var Form1: TForm1;
type TInstallHook = function(Hwnd: THandle): Boolean; stdcall; TUninstallHook = function: Boolean; stdcall;
var InstallHook: TInstallHook; UninstallHook: TUninstallHook; lib: Cardinal; HWND: Cardinal;
procedure TForm1.FormCreate(Sender: TObject); begin lib := LoadLibrary('KBHook.dll'); if lib <> INVALID_HANDLE_VALUE then begin InstallHook := GetProcAddress(lib, 'InstallHook'); UnInstallHook := GetProcAddress(lib, 'UninstallHook'); end else showmessage('Fehler');
if installHook(Form1.Handle) then showmessage('Hook installiert'); Label1.Caption := intTostr(Form1.Handle); end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin UninstallHook; end;
procedure TForm1.MediaKey (Var aMSG: tMessage); begin case aMSG.LParam of APPCOMMAND_MEDIA_NEXTTRACK: begin showmessage('Next'); aMsg.Result := 1; end; end; end; | Das Problem liegt darin, dass der Hook zwar scheinbar richtig installiert wird (zumindest zeigen das die ShowMessages), aber wenn dann meine Form mal nicht den Focus hat, dann ergibt dieser Zeile aus der Hook.dll showmessage('Fange ab - ' + inttostr(MyWindowHandle)); nicht mehr das FensterHandle meiner Form als integer Wert aus, sondern 0. Was mache ich falsch?
_________________ We are, we were and will not be.
|
|
digi_c
      
Beiträge: 1905
W98, XP
D7 PE, Lazarus, WinAVR
|
Verfasst: So 12.02.06 19:13
Beim InstallHook() kriegt die DLL aber den richtigen Handle? Weil du initialisierst den ja mit 0, ich würde vermuten das es da ein Problem gibt.
|
|
uall@ogc
      
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: So 12.02.06 19:29
Da der initialsisierte Wert von MyWindowHandle 0 ist und du erst mit InstallHook den Wert setzt gilt dies nur für alle Programme die InstallHook aufrufen.
Und das macht nur dein Programm welches den Hook lädt, alle anderen Programme führen sozusagen LoadLibrary('KBhook.dll') auf, wonach der MyWindowHandle wert auf 0 steht.
Enwteder du basut dir eine Fenstersuche mit der du dein Programm findest, oder nutzt IPC. Anders wüßte ich auch nicht wie du an das WindowHandle von dem Programm kommst welches InstallHook aufruft.
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: So 12.02.06 19:49
Die eine Möglichkeit ist also, in der KeyboardHookProc das Handle meiner Anwendung zu bestimmen, richtig?
Und das andere könnte ich z.B. hiermit machen, indem ich in InstallHook mein Handle als IPC-Objekt in den Speicher lege, und in der KeyboardHookProc auf dieses Objekt zugreife?
Heute fang ich damit nicht mehr an, aber habe ich das in etwa richtig verstanden?
_________________ We are, we were and will not be.
|
|
uall@ogc
      
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: So 12.02.06 20:01
Das 1. ist richtig, das 2. nicht.
zu 1) FindWindow etc.
zu 2) Etwa mit MMFs. Hab mir jetzt nicht den Link genauer angeschaut, aber da InstallHook nur von deinem Programm aufgerufen wurde bringt es den anderen Anwendungen nichts. Du musst halt ein Merkmal nehmen wonach beim laden der DLL die dll selbst rasufinden kann wie sie mit deinem Programm kommuniziert.
D.h. irgendetwas muss statisch sein. z.b. Fenstername (siehe Punkt 1) oder per MMF der PChar im letzten Parmater
CreateFileMapping(....,'meinPlayer')
Dann greifen alle Programme die ebenfalls das selbe FileMapping erstellen auf den selben Speicherbereich zu. Den kannst du dann z.b. in InstallHook initialsieren indem du dan einfach dein WindowHandle reinschreibst. In allen anderen Prozessen kann die dll dann diesen Wert auslesen und kann dann an dieses Fenster daten schicken. ODer halt die MMF selbst dafür benutzen.
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: So 12.02.06 20:35
Doch, das scheint doch zu klappen
Im HookInstall setze ich sowas:
Delphi-Quelltext 1: 2:
| oDemoObj := TWDB_IPCDemoObj.Create('NempNochEinMP3Player'); oDemoObj.Data := Hwnd; | und später beim eigentlichen hooken dann das:
Delphi-Quelltext 1: 2: 3: 4:
| oDemoObj := TWDB_IPCDemoObj.Create('NempNochEinMP3Player'); PostMessage(oDemoObj.Data,WM_APPCOMMAND,wparam,lParam); |
Zumindest mein Testprogramm ist jetzt empfänglich für die Next-Taste. Ohne iTouch, ohne Focus.
Ob da jetzt MMFs oder ne andere Technik benutzt wird, konnte ich in dem Quelltext nicht so auf Anhieb rausfinden.
_________________ We are, we were and will not be.
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 13.02.06 12:12
Den Hook habe ich jetzt also zum Laufen gebracht, allerdings habe ich jetzt ein neues Problem. Mein Hook-Code sieht jetzt so aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| function KeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin oDemoObj := TWDB_IPCDemoObj.Create('NempNochEinMP3Player'); case nCode < 0 of FALSE: begin if (lparam = APPCOMMAND_MEDIA_NEXTTRACK) or (lparam = APPCOMMAND_MEDIA_PREVIOUSTRACK) or (lparam = APPCOMMAND_MEDIA_STOP) or (lparam = APPCOMMAND_MEDIA_PLAY_PAUSE) then begin PostMessage(oDemoObj.MainWindow,WM_APPCOMMAND,wparam,lParam); Result := 1; end else Result := CallNextHookEx(HookHandle, nCode, wParam, lParam); end; else Result := CallNextHookEx(HookHandle, nCode, wParam, lParam); end; end; |
Das funktioniert ganz gut. Das Problem ist aber, dass meine Anwendung (an die die so gehookten Nachrichten gesendet werden) die Nachricht mehrfach erhält (ca. 20 mal), wenn die Logitech-Software iTouch läuft, die (wahrscheinlich?) auch einen Hook einsetzt, um die Nachrichten an (alle?) Fenster weiterzuleiten. Wenn ich iTouch stoppe (oder nach Start meiner Anwendung starte), dann kommt die nachricht immer nur einmal an, so wie es sein sollte.
Und wieder mal die Frage: was mache ich falsch? Oder (als Workaround): Wie kann ich in meiner Anwendung feststellen, ob dieses Nachrichten schon gehookt werden, so dass ich dann ggf. meinen Hook nicht installiere?
_________________ We are, we were and will not be.
|
|
digi_c
      
Beiträge: 1905
W98, XP
D7 PE, Lazarus, WinAVR
|
Verfasst: Mo 13.02.06 13:12
Konnte man die Nachricht nicht aus der Queue nehmen? Aber der Logitech Prozess hat ja als erstes gehookt. Hmm...
Du kannst natürlich eine FindWindow Such Orgie loslassen aber das muss doch besser gehen.
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 13.02.06 13:36
digi_c hat folgendes geschrieben: | | Konnte man die Nachricht nicht aus der Queue nehmen? Aber der Logitech Prozess hat ja als erstes gehookt. Hmm... |
Ich dachte eigentlich, dass das mit Result := 1; passiert. In der Hauptanwendung, wo ich dann die WM_APPCOMMAND Message verarbeite, setze ich aMsg.Result auch auf 1. Eigentlich sollte dann die Nachricht dann als abgearbeitet gelten, oder?
digi_c hat folgendes geschrieben: | | Du kannst natürlich eine FindWindow Such Orgie loslassen aber das muss doch besser gehen. |
Meinst du zum Suchen meiner Anwendung im Hook, oder zum Finden von iTouch? Meine Form suchen brauch ich nicht, da ich das Handle meiner Form im InstallHook in ein MMF ablege (hoffe, die Sprechweise ist so richtig  ). Und iTouch hat eigentlich keine Form - da könnte ich höchstens den Prozess suchen. Allerdings gibt das mir keine garantie darüber, dass evtl. ein anderes Ding die Nachricht auch schon hooked.
_________________ We are, we were and will not be.
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mi 15.02.06 15:42
Ich push hier mal.
Problem ist geblieben. Wenn iTouch vor meinem Programm läuft, dann wird der iTouch-Hook zuerst abgearbeitet. So, wie ich mir das denke, leitet dieser an jedes Fenster den entsprechenden Befehl weiter. Diese weitergeleitete Message wird dann von meinem Hook abgefangen, und an meine Anwendung geschickt, wo sie verarbeitet wird.
Es scheint jetzt so zu sein, dass in diesem Fall iTouch die Nachricht nochmal an das nächste Fenster sendet, und wieder und wieder und wieder. Jedes mal wird das von mir abgefangen, und an meine Anwendung weitergeleitet. (Die Anzahl der ankommenden Nachrichten hängt tatsächlich von der Anzahl der geöffneten Fenster ab)
Jemand ne Idee?
_________________ We are, we were and will not be.
|
|
digi_c
      
Beiträge: 1905
W98, XP
D7 PE, Lazarus, WinAVR
|
Verfasst: Do 16.02.06 08:29
Vielleicht kann Assarbard dir da direkt helfen?
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mi 22.02.06 17:30
Da es scheinbar auch in der DP keinen gibt, der mir da weiterhelfen kann ( *klick*), habe ich erstmal einen Workaround ausprobiert, der allerdings auf Benutzer-Eingaben angewiesen ist:
Zunächst wird der Hook installiert und ein Flag "MediaTest" auf True gesetzt. Dieser bewirkt, dass in der MediaKey-Prozedur der Hauptform nur eine globale Variable "MediaCount" hochgezählt wird.
Dann wird eine "TestForm" Modal geöffnet, die dazu auffordert, einmal eine MediaTaste zu drücken. Drückt der User eine Taste, dann wird über Form1 der OK-Button auf Enabled gesetzt (und MediaCount um eins erhöht).
Ist nach Schließen der TestForm MediaCount=0 (d.h. Userklick auf "Abbrechen", weil z.B. gar keine Mediatasten da sind  ) oder größer als 1 (d.h. aus dem einen Tastendruck wurden auf magische Art und Weise mehrere), dann wird der Hook wieder deinstalliert. Anschließend wird "MediaTest" wieder auf False gesetzt.
Unschön daran ist, dass man nicht entscheiden kann, ob der User zweimal gedrückt hat, oder die mehrfachen Counts durch den hier beschriebenen Fehler zustande kommen. Ist der User also ein Mehrfach-Drücker, dann ist die Entscheidung, den Hook zu deinstallieren möglicherweise verkehrt.
Die Entscheidung wird dann in der Ini gespeichert, damit der Test beim nächsten Start nicht wieder automatisch gestartet wird.
Aber die Frage bleibt: Was ist an meiner Hook-Technik verkehrt? 
_________________ We are, we were and will not be.
|
|
|