Zuallererst: 'Tschuldigung für so ein langes Erst-Posting...
Ich möchte in meinem Programm die Benutzung der Multimediatasten einer Tastatur ermöglichen. Das mache ich so:
Delphi-Quellcode:
TForm1 = class(TForm)
protected
procedure MediaKey (Var aMSG: tMessage); message WM_APPCOMMAND;
end;
//...
procedure TForm1.MediaKey (Var aMSG: tMessage);
begin
case aMSG.LParam of
APPCOMMAND_MEDIA_NEXTTRACK:
begin
Memo1.lines.add('Next');
aMsg.Result := 1;
end;
APPCOMMAND_MEDIA_PREVIOUSTRACK:
begin
Memo1.lines.add('Prev');
aMsg.Result := 1;
end;
//usw.
end;
end;
Das funktioniert so weit ganz gut. Da die Steuerung auch dann funktionieren soll, wenn mein Fenster nicht den Fokus hat, hab mich mal mit Hooks beschäftigt. (Das Problem habe ich übrigens im
DF auch schon erläutert:
*klick*)
Mein Hook-Code sieht so aus:
Delphi-Quellcode:
function InstallHook(Hwnd: Cardinal): Boolean; stdcall;
begin
Result := False;
if HookHandle = 0 then begin
//Erstmal Hook installieren
HookHandle := SetWindowsHookEx(WH_SHELL, @KeyboardHookProc, HInstance, 0);
//Uebergebenes Fensterhandle sichern
MyWindowHandle := Hwnd;
oDemoObj := TWDB_IPCDemoObj.Create('NempNochEinMP3Player');
oDemoObj.MainWindow := Hwnd;
oDemoObj.HookHandle := HookHandle;
Result := True;
showmessage('Installiert ' + inttostr(HookHandle) + ' ' + inttostr(MyWindowHandle));
end;
end;
function UninstallHook: Boolean; stdcall;
begin
Result := UnhookWindowsHookEx(oDemoObj.HookHandle);
end;
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
SendMessage(oDemoObj.MainWindow,WM_APPCOMMAND,wparam,lParam);
//showmessage('Abgefangen ' + inttostr(oDemoObj.HookHandle) + ' ' + inttostr(oDemoObj.MainWindow));
Result := 1;
end
else
Result := CallNextHookEx(oDemoObj.HookHandle, nCode, wParam, lParam);
end;
else
Result := CallNextHookEx(oDemoObj.HookHandle, nCode, wParam, lParam);
end;
end;
Dabei benutze ich
diese Unit, um sehr einfach ein MMF zu erstellen (oDemoObj ist von dieser Kalsse abgeleitet und hat die Eigenschaften MainWindow und HookHandle).
Das funktioniert soweit auch - das heißt, wenn meine Anwendung den Hook installiert, dann erscheinen in der Memo der Hauptanwendung auch brav die Tastendrücke. Auch dann, wenn das Fenster nicht den Fokus hat.
Aber: Ich habe bei mir auch "iTouch" laufen. Dies ist ein Tool von Logitech. Was es genau macht, weiß ich nicht. Ich vermute sehr stark, dass es ebenfalls die APPCOMMAND_MEDIA_xxx Messsages (und andere) hookt und an sämtliche andere Fenster weiterleitet, damit diese die Multimediatasten ohne eigene Hooks benutzen können. (D.h. Meine Anwendung bekommt auch ohne meinen Hook die Nachrichten, aber ich möchte nicht voraussetzen, dass überall iTouch installiert ist).
Und da gibts jetzt Probleme. Wenn dieses iTouch vor meinem Hook gestartet wird (was die Regel sein dürfte), dann fängt iTouch die Message zuerst ab und sendet sie weiter, was dann von meinem Hook abgefangen wird und an meine Anwendung weitergeleitet wid. Und das passiert leider nicht nur einmal, sondern öfter (die genaue Zahl hängt von der Zahl der offenen Fenster ab). D.h. ein Druck auf die Taste Next bewirkt, dass meine Anwendung ca. 20 mal die Nachricht erhält. Das (hier auskommentierte) ShowMessage erscheint übrigens mit den entsprechenden Anwendungstiteln, die gerade laufen. Also ein paar mal "explorer", ein paar mal "delphi" usw.
Die Frage ist nun, was ich da falsch mache. Und für den unwahrscheinlichen Fall, dass ich nichts falsch mache, sondern das Problem bei iTouch liegt, wie kann ich das umgehen? D.h. wie kann ich feststellen, ob die Nachrichten, die ich hooken möchte, bereits gehookt werden? Damit mein Hook nicht zusätzlich installiert wird (in der Hoffnung, dass es dann schon klappt).