AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Problem beim Programmneustart mit Instanzkontrolle
Thema durchsuchen
Ansicht
Themen-Optionen

Problem beim Programmneustart mit Instanzkontrolle

Ein Thema von Opa Knack · begonnen am 7. Nov 2013 · letzter Beitrag vom 10. Nov 2013
Antwort Antwort
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#1

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 7. Nov 2013, 05:40
Also in der JCL gibt es die Klasse TJclAppInstances (Unit JclAppInst) die alle Probleme mit den Instanzen abdeckt.
Wenn man z.B. eine zweite Instanz startet obwohl nur eine erlaubt ist, dann gibt die 2. Instanz seine Aufrufparameter an die 1. Instanz weiter und beendet sich sich.
Sind mehrere Instanzen zugelassen können diese untereinander kommunizieren.

Wenn man das Rad nicht neu erfinden will ist diese Klasse die beste Lösung.
fork me on Github
  Mit Zitat antworten Zitat
musicman56
(Gast)

n/a Beiträge
 
#2

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 7. Nov 2013, 12:58
Wenn man das Rad nicht neu erfinden will ist diese Klasse die beste Lösung.
Prinzipiell stimme ich dir zu. Wenn ich aber die JCL nicht installiert habe, stellt sich die Frage, ob man wegen einem Liter Milch eine Kuh kaufen sollte?
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#3

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 7. Nov 2013, 16:47
Wenn ich aber die JCL nicht installiert habe, stellt sich die Frage, ob man wegen einem Liter Milch eine Kuh kaufen sollte?
Du trinkst wahrscheinlich viel mehr Milch als dir bewusst ist. (und die Kuh ist ja kostenlos)
Mal ernsthaft, jede Anwendung die über ein Hobbyprogrämmchen hinaus geht kann von der JCL profitieren.
Alles was Borland/Embacadero in der RTL vergessen hat findet man in der JCL.
fork me on Github
  Mit Zitat antworten Zitat
Opa Knack

Registriert seit: 28. Dez 2004
Ort: Köln
166 Beiträge
 
#4

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 7. Nov 2013, 23:47
Den Bezug zwischen JCL und der Kuh übernehme ich dann mal in meinen Sprachgebrauch...

Wenn ich das richtig verstehe (sorry, Musicman, aber in D2006 ist CharInSet nicht verfügbar, somit konnte ich das nicht ausprobieren), muss ich den Mutex freigeben, bevor ich ihn erzeuge (was ja auch logisch ist). Dann ergibt sich aber aus meiner Sicht das Problem, dass ich den Neustart ja vom Programm aus initiiere, der Mutex also noch besteht, und das dieser erst freigegeben werden kann, wenn das Programm auch beendet ist. Oder sehe ich das falsch?

Ich habe inzwischen ausprobiert, ob ich den Mutex dadurch freigeben kann, dass ich vor Programmende versuche, ihn neu zu erzeugen und bei Vorhandensein über CloseHandle freizugeben, leider jedoch ohne Erfolg.

Hat jemand noch eine andere praktikable Idee?
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.684 Beiträge
 
Delphi 5 Professional
 
#5

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 8. Nov 2013, 00:31
Ich mache es so: der/das Mutex wird erst erzeugt, nachdem alle Programmparameter abgearbeitet sind. Die zweite Instanz wird mit einem bestimmten Parameter gestartet und wenn der gefunden wird, schließt die zweite Instanz die erste bereits laufende.

Mal in Code-Form (Auszug aus der .dpr):
Delphi-Quellcode:
begin
    if (ParamCount > 0) then
    begin
        Params:= ParamStr(1);
        if (Params = 'runas') then
        begin
            SendMessage(StrToInt(ParamStr(2)), WM_CLOSE, 0, 0);
        end;
    end;

    hMutex:= CreateMutex(nil, True, PRODUCTNAME + PRODUCTNAME + PRODUCTCOPYRIGHT);
    if GetLastError = ERROR_ALREADY_EXISTS then
    (* Weiterer hierfür nicht relevanter Code *)

    if hMutex <> 0 then
        CloseHandle(hMutex);
end.
Ich glaube, ParamStr(2) war die PID oder so, damit die Message nur an die laufende erste Instanz gesendet wird.

MfG Dalai
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 8. Nov 2013, 00:41
Wenn ich das richtig verstehe (sorry, Musicman, aber in D2006 ist CharInSet nicht verfügbar, somit konnte ich das nicht ausprobieren), muss ich den Mutex freigeben, bevor ich ihn erzeuge (was ja auch logisch ist).
Das ist richtig
Dann ergibt sich aber aus meiner Sicht das Problem, dass ich den Neustart ja vom Programm aus initiiere, der Mutex also noch besteht, und das dieser erst freigegeben werden kann, wenn das Programm auch beendet ist. Oder sehe ich das falsch?
Das siehst du richtig, dass du das falsch siehst
Ich habe inzwischen ausprobiert, ob ich den Mutex dadurch freigeben kann, dass ich vor Programmende versuche, ihn neu zu erzeugen und bei Vorhandensein über CloseHandle freizugeben, leider jedoch ohne Erfolg.
Du hast vom Seil etwas abgeschnitten und festgestellt, dass es immer noch zu kurz ist?
Hat jemand noch eine andere praktikable Idee?
Ja, gib den Mutex vor dem Aufruf von ShellExecute mit CloseHandle frei.

Dann wird das Handle geschlossen (übersetzt heißt CloseHandle -> SchließeHandle).
Wird der Prozess beendet, dann werden alle noch offenen Handles von diesem Prozess automatisch geschlossen.
Aber in diesem Falle musst du den halt vorher manuell freigeben.

Delphi-Quellcode:
  // Nun ja ... wenn schon dann bitte mit Self
  {form1}Self.Close;
  // Da wir aber die Anwendung schließen wollen, müssen wir das HauptFormular schließen, also besser
  Application.MainForm.Close;

  // wozu das? unnötig!
  // application.ProcessMessages;

  // Hier jetzt das Handle vom Mutex freigeben
  CloseHandle( MyAppMutexHandle );

  // Nicht das Application.Handle übergeben sondern 0
  ShellExecute({Application.Handle} 0, 'open', Pchar(ParamStr(0)), nil, nil, sw_SHOWNORMAL);
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 8. Nov 2013, 01:37
Hier die versprochene Klasse
Delphi-Quellcode:
unit AppMutex;

interface

type
  TAppMutexStrategy = class abstract
  private
    procedure SetActive( const Value : Boolean );
  protected
    function GetActive : Boolean; virtual; abstract;
    procedure AquireMutex; virtual; abstract;
    procedure ReleaseMutex; virtual; abstract;
  public
    destructor Destroy; override;
  end;

  TAppMutex = class
  private
    class var FStrategy : TAppMutexStrategy;
  private
    class procedure SetActive( const Value : Boolean ); static;
    class function GetActive : Boolean; static;
    class destructor Destroy;
  public
    class property Active : Boolean read GetActive write SetActive;
    class procedure SetStrategy( AStrategy : TAppMutexStrategy );
  end;

  TNamedAppMutexStrategy = class( TAppMutexStrategy )
  private
    FHandle : Cardinal;
    FName : string;
  protected
    procedure AquireMutex; override;
    procedure ReleaseMutex; override;
    function GetActive : Boolean; override;
    function GetName : string; virtual;
    property Name : string read GetName;
  public
    constructor Create( const AName : string );
  end;

  TLocalAppMutexStrategy = class( TNamedAppMutexStrategy )
  protected
    function GetName : string; override;
  end;

  TGlobalAppMutexStrategy = class( TNamedAppMutexStrategy )
  protected
    function GetName : string; override;
  end;

implementation

uses
  Windows,
  SysUtils;

{ TAppMutex }

class destructor TAppMutex.Destroy;
begin
  FreeAndNil( FStrategy );
end;

class function TAppMutex.GetActive : Boolean;
begin
  Result := FStrategy.GetActive;
end;

class procedure TAppMutex.SetActive( const Value : Boolean );
begin
  FStrategy.SetActive( Value );
end;

class procedure TAppMutex.SetStrategy( AStrategy : TAppMutexStrategy );
begin
  if Assigned( FStrategy )
  then
    FreeAndNil( FStrategy );

  FStrategy := AStrategy;
end;

{ TAppMutexStrategy }

destructor TAppMutexStrategy.Destroy;
begin
  SetActive( False );
  inherited;
end;

procedure TAppMutexStrategy.SetActive( const Value : Boolean );
begin
  if Value = GetActive
  then
    Exit;

  if Value
  then
    AquireMutex
  else
    ReleaseMutex;
end;

{ TNamedAppMutexStrategy }

procedure TNamedAppMutexStrategy.AquireMutex;
var
  LLastError : Cardinal;
begin
  FHandle := CreateMutex( nil, True, PChar( Name ) );

  LLastError := GetLastError;

  if LLastError = ERROR_ALREADY_EXISTS
  then
    begin
      CloseHandle( FHandle );
      FHandle := 0;
    end;
end;

constructor TNamedAppMutexStrategy.Create( const AName : string );
begin
  inherited Create;
  FName := AName;
end;

function TNamedAppMutexStrategy.GetActive : Boolean;
begin
  Result := ( FHandle <> 0 );
end;

function TNamedAppMutexStrategy.GetName : string;
var
  LIdx : Integer;
begin
  Result := FName;
  for LIdx := 1 to Length( Result ) do
    begin
      if not CharInSet( Result[LIdx], ['0' .. '9', 'A' .. 'Z', 'a' .. 'z', '-'] )
      then
        Result[LIdx] := '_';
    end;
end;

procedure TNamedAppMutexStrategy.ReleaseMutex;
begin
  CloseHandle( FHandle );
  FHandle := 0;
end;

{ TLocalAppMutexStrategy }

function TLocalAppMutexStrategy.GetName : string;
begin
  Result := 'Local\' + inherited;
end;

{ TGlobalAppMutexStrategy }

function TGlobalAppMutexStrategy.GetName : string;
begin
  Result := 'Global\' + inherited;
end;

end.
Im Einsatz so
Delphi-Quellcode:
program MutexTest;

uses
  Forms,
  MainView_Form in 'MainView_Form.pas{MainView} ,
  AppMutex in 'AppMutex.pas',
  AlertView_Form in 'AlertView_Form.pas{AlertView};

{$R *.res}

begin
  // Strategie einstellen
  TAppMutex.SetStrategy( TGlobalAppMutexStrategy.Create( '6D274674-150A-490E-B8D0-726C6D556F29' ) );
  // Aktivieren
  TAppMutex.Active := True;

  // Überprüfung
  if not TAppMutex.Active
  then
  begin
    TAlertView.Create( nil ).ShowModal;
    Halt;
  end;

  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm( TMainView, MainView );
  Application.Run;

end.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
musicman56
(Gast)

n/a Beiträge
 
#8

AW: Problem beim Programmneustart mit Instanzkontrolle

  Alt 8. Nov 2013, 10:04
Hallo,

vielen Dank Sir Rufo, ich werd's mal ausprobieren
  Mit Zitat antworten Zitat
Antwort Antwort


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 15:35 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