bzgl. Verhindern von Mehrfachstarts einer Applikation gibt's aus der Delphi - Ecke ja bereits einige Einträge...
u.a.
Delphi Mehrfachstart einer .exe verhindern - Delphi-PRAXIS
Doppelstart einer Anwendung
Meiner Meinung nach ist die dort - im weiteren Verlauf - beschriebene Lösung mit dem Mutex die geschickteste;
wenn man "nur" den Start unterdrücken möchten
"Schwieriger" wird's wenn man die bereits laufende Anwendung (eigentlich das Hauptfenster) nach vorne bringen und ggf. noch Daten/Parameter übergeben möchte. Da hilft der Mutex nicht wirklich weiter.
Hier im Forum gibt's noch einen Thread über
Verhalten von FindWindow unter Lazarus
in dem beschrieben wird, das FindWindow unter Lazarus, zumindest in der aktuellen Version, nichts viel Sinn macht:
der eine Übergabeparameter von FindWindow muss IMMER auf "Window" stehen, der andere ist die Caption des gesuchten Fensters
spätestens wenn zwei Fenster die gleiche Titelteile habe ist's vorbei.
Dennoch - wer damit kein grundsätzliches Problem hat - kann über FindWindow sich das Fensterhandle besorgen und dann via
Code: Alles auswählen
Windows.ShowWindow(h,SW_Restore);
Windows.SetForegroundWindow(h);
die Anwendung nach vorne bringen (h ist das Fensterhandle).
Anschließend kann man dann z.B. via PostMessage eine Nachricht an des Fenster senden - wieder basierend auf dem Handle.
Mir persönlich ist das zuviel Windowsspezifisch (selbst wenn ich ausschließlich auf Windows unterwegs wäre) und das o.g. "Restrisiko" bzgl. Fensterhandle Suche via FindWindow ist natürlich sehr unschön.
Ich würde eher empfehlen, für die gesamte Funktionalität IPC Server / Client verwenden (TSimpleIPCClient, TSimpleIPCServer - unit simpleipc; als Komponenten auf dem Tab "System").
Damit kann man
- Mehrfachstarts verhindern
- Fenster nach vorne bringen - nun ja, eher indirekt
- (beliebige) Parameter an die laufende Instanz senden
Das kann man natürlich unterschiedlich implementieren; mir gefällt folgende Version ganz gut
Code: Alles auswählen
function SendMessageToInstance(aID: string; aMsg: string): Boolean;
var
IPCClt: TSimpleIPCClient;
begin
Result:=False;
IPCClt := TSimpleIPCClient.Create(nil);
try
IPCClt.ServerID := aID;
if IPCClt.ServerRunning then
begin
IPCClt.Active:=True;
IPCClt.SendStringMessage(aMsg);
IPCClt.Active:=False;
Result:=True;
end;
finally
IPCClt.Free;
end;
end;
function SendMessageToInstance ist eine global sichtbare Funktion. Sie liefert True zurück, wenn die übergebene aMsg: string an einen IPCServer mit der ID aID: string übergeben werden konnte; d.h. die Anwendung läuft bereits. Diese Funktion kann überall aufgerufen werden, sinvollerweise "ganz am Anfang" in der *.lpr;
z.B.
Code: Alles auswählen
if not SendMessageToInstance('myIPCSrv', 'anyMsg') then
// die aID muss mit den Namen des Srvs auf dem Formular korrelieren !!
begin
Application.Initialize;
Application.CreateForm(...);
...
Application.Run;
end;
Damit erspart man sich auch ein Abwürgen der neuen Application via Exit oder Terminate.
Zur "elganten" Reaktion auf Messages muss nun noch die SimpleIIPCServer Komponente auf einem Formular platziert werden, welches automatisch erzeugt wird, also z.B. das Hauptformular.
Wichtig (Eigenschaften von TSimpleIPCServer):
- Global:=True
- ServerID:='myIPCSrv' ... muss mit dem Aufruf von SendMessagteToInstance (s.o.) korrelieren !
- Active:=False; ... darf erst nach Initialisierung der Programms (z.B. in FormShow o.ä.) auf True gesetzt werden.
Nun nur noch den geeigneten Code in das OnMessage Event des TSimpleIPCServer platzieren,
z.B. (BringToFront) und den übergebenen Parameter auswerten wie's gerade notwendig ist.