![]() |
WndProc bei Programmen im Hintergrund
Hi,
ich hab da in einem Programm folgenden Code, um z.B. Play und Stop per Fernbedienung zu realisieren (Stichwort HID USB):
Delphi-Quellcode:
Das läuft soweit. Aber nur, solange das Programm in Vordergrund aktiv ist.
type
TMainForm = class(TForm) ... protected procedure WndProc(var Message: TMessage); override; public procedure StopMyPlayback; procedure StartMyPlayback; end; var MainForm: TMainForm; implementation {$R *.dfm} procedure TMainForm.WndProc(var Message: TMessage); const FAPPCOMMAND_MASK = $F000; var cmd: integer; begin inherited; if (Message.Msg = WM_APPCOMMAND) then begin cmd := Message.LParamHi and not FAPPCOMMAND_MASK; case cmd of APPCOMMAND_MEDIA_STOP: StopMyPlayback; APPCOMMAND_MEDIA_PLAY: StartMyPlayback; end; end; end; Was ist zu tun, damit es auch startet und stoppt, wenn das Prog minimiert ist? Wo finde ich vielleicht ein Beispiel? Ich ahne bereits, dass da irgendein gewaltiger zusätzlicher Overhead nötig wird (Hook, dll etc.), aber vielleicht geht es doch ganz einfach. Uli |
AW: WndProc bei Programmen im Hintergrund
Du könntest dich in die Messageloop der Applikation einklinken:
Delphi-Quellcode:
procedure TMainForm.HandleOnMessage(var Msg: TMsg; var Handled: Boolean);
begin // Vorsicht! hier rauschen ALLE Messages der Anwendung durch // Debuggen ist schwierig weil jede Bewegung des Mauszeigers neu Messages auslöst if Msg.Message = WM_APPCOMMAND then begin ... end; end; ... procedure TMainForm.FormCreate(Sender:TObject); begin Application.OnMessage := self.HandleOnMessage; |
AW: WndProc bei Programmen im Hintergrund
Ich hab das mit dem HandleOnMessage probiert, es klappt aber nicht.
Wenn ich anstelle von
Delphi-Quellcode:
testweise einmal
if Msg.Message = WM_APPCOMMAND then
Delphi-Quellcode:
verwende und mir dazu eine Testausgabe mache, dann klappt es.
if Msg.Message = WM_KEYDOWN then
D.h. dass also das WM_APPCOMMAND im HandleOnMessage anscheinend nicht ankommt. Uli |
AW: WndProc bei Programmen im Hintergrund
Eine weitere Feststellung:
Beim Tastendruck auf die Fernbedienung wird auch das Ereignis WM_KEYDOWN ausgelöst. Nun gut, evtl. wäre da mit einer entsprechenden Auswertung auch irgendwas darstellbar. ABER: wenn das Programm im Hintergrund läuft, wird auch kein WM_KEYDOWN mehr verarbeitet. Insofern hilft das Application.OnMessage auch nicht weiter. Es bekommt keine Tastatur-Message sobald das Programm nicht aktiv im Vordergrund steht. Uli |
AW: WndProc bei Programmen im Hintergrund
Während es keine weitere Antwort mehr gegeben hat habe ich mich durch gefühlte 1001 Links zum Thema Global Hooks etc. gewühlt.
Eine Lösung habe ich bekommen mit RegisterHotkey. Dabei fängt aber dann mein Programm eben die Taste der Fernbedienung ab und andere Programme, z.B. Mediaplayer, bekommen dann die Funktion nicht mehr mitgeteilt. Ein globales Hooken mit eigener zusätzlicher dll ist ebenfalls reichlich aufwendig. Die Lösung, die nun genau das tut, was es soll, sieht so aus (dabei werden zwei externe Windows API-Funktionen eingebunden):
Delphi-Quellcode:
Damit kommen die Kommandos der Fernbedienung an, egal ob das Programm im Vorergrund ist oder nicht. Und die Kommandos werden auch an andere Programme weitergereicht (so sie es denn sollen).
type
TMainForm = class(TForm) ... private ShellHookMessage: Integer; protected procedure WndProc(var Message: TMessage); override; public procedure StopMyPlayback; procedure StartMyPlayback; end; var MainForm: TMainForm; function RegisterShellHookWindow(hWnd: hWnd): boolean; stdcall; external 'User32.dll' name 'RegisterShellHookWindow'; function DeregisterShellHookWindow(hWnd: hWnd): boolean; stdcall; external 'User32.dll' name 'DeregisterShellHookWindow'; implementation {$R *.dfm} procedure TMainForm.WndProc(var Message: TMessage); const FAPPCOMMAND_MASK = $F000; var cmd: integer; begin inherited; if (Message.Msg = ShellHookMessage) and (Message.WParam = HSHELL_APPCOMMAND) then begin cmd := Message.LParamHi and not FAPPCOMMAND_MASK; case cmd of APPCOMMAND_MEDIA_STOP: StopMyPlayback; APPCOMMAND_MEDIA_PLAY: StartMyPlayback; end; end; end; procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); begin DeregisterShellHookWindow(Handle); end; procedure TMainForm.FormCreate(Sender: TObject); begin ShellHookMessage := RegisterWindowMessageA('MYSHELLHOOK'); RegisterShellHookWindow(Handle); end; Vielleicht hilft der Code ja auch mal anderen.:-D Uli |
AW: WndProc bei Programmen im Hintergrund
Delphi-Quellcode:
'MYSHELLHOOK' ist auch nicht so toll. Da gibt es bestimmt einige. Nimm eine GUID und du bist auf der sicheren Seite.
RegisterWindowMessageA('MYSHELLHOOK');
Ich würde noch prüfen, ob RegisterShellHookWindow nicht fehl geschlagen ist. |
AW: WndProc bei Programmen im Hintergrund
Zitat:
Müsste denn ein optimierter Code nicht in etwa so aussehen?
Delphi-Quellcode:
Ansonsten, wenn RegisterShellHookWindow fehlschlägt, dann findet ja schlichtweg das WndProc mit
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin if shellHookWindowRegisteredSuccessfully then DeregisterShellHookWindow(Handle); end; procedure TMainForm.FormCreate(Sender: TObject); begin ShellHookMessage := RegisterWindowMessageA(myGUID); if ShellHookMessage <> 0 then shellHookWindowRegisteredSuccessfully := RegisterShellHookWindow(Handle); if not shellHookWindowRegisteredSuccessfully then MachIrgendeineFehlerbehandlung; end;
Delphi-Quellcode:
nicht statt. MachIrgendeineFehlerbehandlung dient dann nur dazu, den Anwender gezielt zu informieren.
Message.Msg = ShellHookMessage
Eine generelle Frage, vermutlich einen eigenen Thread wert: man findet x Beispiele, welche die Funktionsergebnisse von API-Aufrufen nicht auswerten. Was ist besser: trotzdem auswerten und das Programm mit Fehlerauswertungen aufblähen oder doch auch ab und zu das Ignorieren von Funktionsergebnissen zulassen? Klar ist, dass das erstere das sicherere Verfahren ist. |
AW: WndProc bei Programmen im Hintergrund
Zitat:
|
AW: WndProc bei Programmen im Hintergrund
:-D
Das Handle in
Delphi-Quellcode:
ist kein Rückgabewert sondern ein Eingabewert, hier also das Handle des Programms (ich glaube Self.Handle wäre in diesem Fall dasselbe). Der Rückgabewert der API-Funktion ist boolean und zeigt lediglich an, dass die Registrierung erfolgreich war.
RegisterShellHookWindow(Handle)
Siehe auch ![]() Der eigentlich verwendete Rückgabewert ist im gegebenen Fall die Variable ShellHookMessage, die in WndProc verwendet wird. |
AW: WndProc bei Programmen im Hintergrund
Erst kündigst Du eine generelle Frage an, und dann beziehst Du Dich doch auf das spezifische Problem?
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:24 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz