Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Neustart der Applikation aus Stabilitätsgründen... (https://www.delphipraxis.net/211311-neustart-der-applikation-aus-stabilitaetsgruenden.html)

BigAl 28. Aug 2022 18:43

Neustart der Applikation aus Stabilitätsgründen...
 
Hallo zusammen,

ich entwickle momentan eine Applikation, welche im Dauerbetrieb stabil laufen muss. Weiterhin sind ein helles und ein dunkles Design gefordert. Da es nach dem Umschalten des Styles immer wieder zu Fehler in der VCL kommt habe ich mich für einen etwas unkonventionellen Weg entschieden. Nachdem der Benutzer das Design ändert (sollte eigentlich nicht oft vorkommen) starte ich die Applikation neu.

Dazu habe ich im Hauptformular folgenden Destructor geschrieben:

Delphi-Quellcode:
destructor TfrmMain.Destroy;
var
  AppName, AppParam: string;
begin
  inherited;

  if SkinChangeRestart then
  begin
    AppName := ParamStr(0);
    AppParam := SKIN_RESTART_PARAM;
    ShellExecute(0, nil, PChar(AppName), PChar(AppParam), nil, SW_SHOW);
  end;
end;
Bei der Konfiguration löse ich das ganze nach einer Sicherheitsabfrage wie folgt aus:

Delphi-Quellcode:
         
  SkinChangeRestart := True;
  Application.MainForm.Close;
Das funktioniert, aber ich bin mir nicht sicher, ob das der richtige Weg ist oder ob man das anders lösen sollte.

Ehe ein Hinweis auf "löse das VCL Problem" kommt: Ich habe ja bereits einen häufig auftretenden Fehler gemeldet (RSP-38928). Ich werde bei Gelegenheit noch einen weiteren Melden der immer wieder auftritt. Mit dem Debuggen solcher Fehler bin ich überfordert bzw. dazu fehlt mir die Zeit. Das die Anwendung in Forms dynamisch erzeugte eingebettete forms und frames enthält macht das ganze nicht leichter. Aber ehe das nicht alles seitens VCL stabil ist brauche ich eine Lösung. Die vorliegende Anwendung wird z.B. ab Oktober in Mexiko und später noch in Brasilien und den USA laufen. Da kann ich nicht mal eben hinfahren...

KodeZwerg 28. Aug 2022 19:06

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Ich empfehle von Herrn Below die OneInstance unit (einfach mal hier danach suchen) zu benutzen. Läuft bei mir seit Jahren perfekt!

BigAl 28. Aug 2022 19:19

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von KodeZwerg (Beitrag 1510903)
Ich empfehle von Herrn Below die OneInstance unit (einfach mal hier danach suchen) zu benutzen. Läuft bei mir seit Jahren perfekt!

Und wie soll die bei meinem Problem helfen? Um eine Instanz sicherzustellen brauchts keine Unit. Das ist mit ein paar Codezeilen erledigt. Mir geht es darum die aktuelle Instanz zu beenden und dann automatisch eine neue zu starten...

KodeZwerg 28. Aug 2022 19:52

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Und genau dafür nutze ich seine Unit, naja wie dem auch sei...

himitsu 28. Aug 2022 22:53

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Reicht es denn nicht die Form neu zu erstellen (wobei es bei der MainForm nicht so einfach ist, das deren Freigabe standardmäßig die Anwendung beendet)
oder zumindestens die Windows-Handles/Controls neu zu generieren?

BigAl 28. Aug 2022 23:04

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von himitsu (Beitrag 1510910)
Reicht es denn nicht die Form neu zu erstellen (wobei es bei der MainForm nicht so einfach ist, das deren Freigabe standardmäßig die Anwendung beendet)
oder zumindestens die Windows-Handles/Controls neu zu generieren?

Das Problem ist, dass in der Main-Form jede Menge Initialisierung stattfindet. Ok. Die könnte man aus dem constructor / destructor auslagern. Hmm. Die Idee ist nicht schlecht. Wobei beim Umschalten des Styles eh der Handle des Hauptformulars neu erzeugt wird - spricht das Fenster des Hauptformulars vom StyleManager wohl neu erzeugt wird. Dann müsste die aktuelle Sub-Forms restauriert werden usw. Muss ich mir mal anschauen. Weiterhin müsste man wahrscheinlich "Application" austricksen. Und da wird's tricky.

Das Problem mit den Styles ist halt, dass manchmal Fehler direkt beim Umschalten stattfinden und manchmal erst später, wenn Frames neu aufgemacht / erzeugt werden. Meistens funktioniert es aber. Und das macht mir Bauchschmerzen. Ich hasse Fehler, die nicht reproduzierbar sind.

venice2 28. Aug 2022 23:06

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Und genau dafür nutze ich seine Unit, naja wie dem auch sei...
Es geht hier nicht um eine Instance also sicherstellen das nur eine erlaubt ist
sondern darum die Anwendung neu zu starten.
Dafür braucht man keine extra Unit eine Zeile reicht vollkommen aus.

Ich mache es beim Skin Wechsel auf diese weise.
Delphi-Quellcode:
if Restart then
  Result := ShellExecute(0, 'open', PWideChar(ParamStr(0)), nil, nil, SW_SHOW)
bzw. Dein Variante sollte es auch tun. Sehe da kein Problem.

KodeZwerg 28. Aug 2022 23:21

AW: Neustart der Applikation aus Stabilitätsgründen...
 
offtopic
Nur um das was ich meinte zu vervollständigen, ich nutze diese nicht-gewollte unit weil diese halt möglichkeiten bietet beim zweit-aufruf schon im code die alte instanz zu schließen, neue zu starten, automatisierte aktionen ausführt etc. Klar kann man das auch alles selbst schreiben, muss man aber nicht, war halt nur ein vorschlag. habs nicht bös gemeint.

himitsu 29. Aug 2022 00:43

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Delphi-Quellcode:
Self.RecreateWnd;


Zitat:

Zitat von venice2 (Beitrag 1510914)
Delphi-Quellcode:
if Restart then
  Result := ShellExecute(0, 'open', PWideChar(ParamStr(0)), nil, nil, SW_SHOW)

Im ersten Post war es bereits richig (nur zusätzlich noch mit einem Parameter)
Bei dir nicht. Grund siehe https://www.delphipraxis.net/211304-...ml#post1510883

PS: Wenn man die Anwendung inkl. der ursprünglichen Parameter neu starten will, dann siehe MSDN-Library durchsuchenGetCommandLine. (einfacher als die vielen ParamStr's wieder neu zusammenzusetzen)

BigAl 29. Aug 2022 05:42

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

PS: Wenn man die Anwendung inkl. der ursprünglichen Parameter neu starten will, dann siehe MSDN-Library durchsuchenGetCommandLine. (einfacher als die vielen ParamStr's wieder neu zusammenzusetzen)
Der Parameter sagt der Anwendung lediglich, dass der Restart auf Grund des Skin-Wechsels erfolgt. Damit navigiere sie dann wieder direkt an die Stelle, auf der das ganze ausgelöst wurde und schaltet die zum Einstellen benötigten Rechte frei. Das ganze ist eine Oberfläche für das UI einer Industrieanlage, welches zu 100% Touch-gesteuert ist. Es gibt also keine Tastatur. Es ist also ausgeschlossen, dass der Benutzer da Schindluder treibt mit dem Parameter (es gibt keine Tastatur)...

Maliko 29. Aug 2022 07:52

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von BigAl (Beitrag 1510919)
Es ist also ausgeschlossen, dass der Benutzer da Schindluder treibt mit dem Parameter (es gibt keine Tastatur)...

Ausgeschlossen ist das gar nicht mal. Wenn im Hintergrund ein Windows läuft und man die Anwendung schließen kann, bzw. die Startleiste von Windows zu sehen ist, dann aktiviert man einfach die Bildschirmtastatur und schon kann man "Schindluder" treiben.

BigAl 29. Aug 2022 08:19

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von Maliko (Beitrag 1510922)
Zitat:

Zitat von BigAl (Beitrag 1510919)
Es ist also ausgeschlossen, dass der Benutzer da Schindluder treibt mit dem Parameter (es gibt keine Tastatur)...

Ausgeschlossen ist das gar nicht mal. Wenn im Hintergrund ein Windows läuft und man die Anwendung schließen kann, bzw. die Startleiste von Windows zu sehen ist, dann aktiviert man einfach die Bildschirmtastatur und schon kann man "Schindluder" treiben.

Anwendung schließen geht nur mit Admin. Taskleiste ist nicht sichtbar:
Delphi-Quellcode:
    WindowState := TWindowState.wsMaximized;
    BorderStyle := bsNone;
    BoundsRect := Screen.MonitorFromWindow(Handle).BoundsRect;

venice2 29. Aug 2022 10:25

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von himitsu (Beitrag 1510916)
Delphi-Quellcode:
Self.RecreateWnd;


Zitat:

Zitat von venice2 (Beitrag 1510914)
Delphi-Quellcode:
if Restart then
  Result := ShellExecute(0, 'open', PWideChar(ParamStr(0)), nil, nil, SW_SHOW)

Im ersten Post war es bereits richig (nur zusätzlich noch mit einem Parameter)
Bei dir nicht. Grund siehe https://www.delphipraxis.net/211304-...ml#post1510883

PS: Wenn man die Anwendung inkl. der ursprünglichen Parameter neu starten will, dann siehe MSDN-Library durchsuchenGetCommandLine. (einfacher als die vielen ParamStr's wieder neu zusammenzusetzen)

Es gibt viele Wege nach Köln.

Teste es doch einfach dann wirst du sehen das es das tut was es soll.
Ohne nennenswerte Problem im Bruchteil einer Millisekunde.
Es ist so schnell das es gar nicht ins Gewicht fällt oder man es merkt das die Anwendung neu gestartet wird.

Wichtig ist das Ergebnis nicht die art und weise wie dieses erreicht wird.

BigAl 29. Aug 2022 10:33

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von venice2 (Beitrag 1510928)
Es gibt viele Wege nach Köln.

Teste es doch einfach dann wirst du sehen das es das tut was es soll.
Ohne nennenswerte Problem im Bruchteil einer Millisekunde.
Es ist so schnell das es gar nicht ins Gewicht fällt oder man es merkt das die Anwendung neu gestartet wird.

Kommt natürlich darauf an wie viel Initialisierung stattfindet. Aber ja. Geht sehr schnell.

Ich hatte eigentlich eher bedenken wann ich den Neustart durchführe. In meinem ersten Post mache ich das ja im destructor der Main. Alternativ könnte ich das ja auch hinter das "Application.Run" setzen (was ich nun auch gemacht habe...). Das ist dann der letztmöglich Zeitpunkt.

venice2 29. Aug 2022 10:43

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von BigAl (Beitrag 1510929)
Zitat:

Zitat von venice2 (Beitrag 1510928)
Es gibt viele Wege nach Köln.

Teste es doch einfach dann wirst du sehen das es das tut was es soll.
Ohne nennenswerte Problem im Bruchteil einer Millisekunde.
Es ist so schnell das es gar nicht ins Gewicht fällt oder man es merkt das die Anwendung neu gestartet wird.

Kommt natürlich darauf an wie viel Initialisierung stattfindet. Aber ja. Geht sehr schnell.

Ich hatte eigentlich eher bedenken wann ich den Neustart durchführe. In meinem ersten Post mache ich das ja im destructor der Main. Alternativ könnte ich das ja auch hinter das "Application.Run" setzen. Das wäre dann der letztmöglich Zeitpunkt...

Jo!
Ich arbeite ja ohne die VCL mit eigener Skinengine von daher habe ich wohl nicht so immense Initialisierung wie du.
Ich schicke beim ändern des Skin aus meinen Menu
Delphi-Quellcode:
               
PostQuitMessage(0);              
Restart := TRUE;
und fertig.
Letztendlich zählt das Ergebnis.

BigAl 29. Aug 2022 10:49

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von venice2 (Beitrag 1510930)
Ich arbeite ja ohne die VCL mit eigener Skinengine von daher habe ich wohl nicht so immense Initialisierung wie du.
Ich schicke beim ändern des Skin aus meinen Menu
Delphi-Quellcode:
               
PostQuitMessage(0);              
Restart := TRUE;
und fertig.
Letztendlich zählt das Ergebnis.

Mit anderer Engine hatte ich überlegt. Habe hier eine ein lifetime "almdev" Lizenz. Aber ich denke das sicherste für die Zukunft sind immer noch die Bibliotheken von Emba. Zu viele Firmen haben sich über die Jahre vom Markt verabschiedet.

Und ja: Letztendlich zählt das Ergebnis. Das Forum hilft halt bei der Meinungsfindung :-).

Uwe Raabe 29. Aug 2022 13:08

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von BigAl (Beitrag 1510929)
Alternativ könnte ich das ja auch hinter das "Application.Run" setzen (was ich nun auch gemacht habe...). Das ist dann der letztmöglich Zeitpunkt.

Die finalization Abschnitte der Units werden noch später ausgeführt. Den spätesten Zeitpunkt den du damit noch erreichen könntest, wäre das finalization einer minimalen Unit, die im Projekt als erstes in der Uses-Anweisung steht.

Zu dem Zeitpunkt sind auch alle Forms und sonstige Komponenten der Anwendung freigegeben, was direkt nach dem Run in der Regel noch nicht der Fall ist.

So eine Unit könnte in etwa so aussehen:
Delphi-Quellcode:
unit AutoRestartUnit;

interface

var
  AutoRestart: Boolean = False;
  AutoRestartCmdLine: PChar;

implementation

uses
  Winapi.ShellAPI, Winapi.Windows;

initialization
  AutoRestartCmdLine := CmdLine;
finalization
  if AutoRestart then begin
    ShellExecute(0, 'open', PChar(ParamStr(0)), AutoRestartCmdLine, nil, SW_SHOW);
  end;
end.

himitsu 29. Aug 2022 13:25

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von venice2 (Beitrag 1510928)
Teste es doch einfach dann wirst du sehen das es das tut was es soll.

Wichtig ist das Ergebnis nicht die art und weise wie dieses erreicht wird.

Ja, es mag gehen, es ist denoch falsch.

Du kannst einen kleinen Nagel auch mit einer Zange ins Holz hauen, also geht es sozusagen, aber dennoch ist es nicht richtig.


Und genau weil zuviele so denken knallt es gern mal, sobald sich mal ein bissl was ändert.



Ja, PChar entspricht aktuell PWideChar und das wird sich so schnell nicht nochmal ändern,
aber da hört es nicht auf.
* Integer anstatt LPARAM/WPARAM/LRESULT als Typen SendMessage/PostMessage
* Interger als Cast für einen Pointer
* ...

BigAl 29. Aug 2022 13:50

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1510935)
Zitat:

Zitat von BigAl (Beitrag 1510929)
Alternativ könnte ich das ja auch hinter das "Application.Run" setzen (was ich nun auch gemacht habe...). Das ist dann der letztmöglich Zeitpunkt.

Die finalization Abschnitte der Units werden noch später ausgeführt. Den spätesten Zeitpunkt den du damit noch erreichen könntest, wäre das finalization einer minimalen Unit, die im Projekt als erstes in der Uses-Anweisung steht.

Zu dem Zeitpunkt sind auch alle Forms und sonstige Komponenten der Anwendung freigegeben, was direkt nach dem Run in der Regel noch nicht der Fall ist.

So eine Unit könnte in etwa so aussehen:
Delphi-Quellcode:
unit AutoRestartUnit;

interface

var
  AutoRestart: Boolean = False;
  AutoRestartCmdLine: PChar;

implementation

uses
  Winapi.ShellAPI, Winapi.Windows;

initialization
  AutoRestartCmdLine := CmdLine;
finalization
  if AutoRestart then begin
    ShellExecute(0, 'open', PChar(ParamStr(0)), AutoRestartCmdLine, nil, SW_SHOW);
  end;
end.

Da hast Du natürlich recht. Wobei ich mich schwer tue die "uses" des Projekts manuell zu bearbeiten. Bleibt meine Unit dann auch oben? Üblicherweise pflegt doch die IDE diese "uses"-Liste...

himitsu 29. Aug 2022 14:31

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Delphi hängt Units nur an, wenn es der Meinung ist, etwas würde fehlen.
Was drin war, bleibt erhalten.

Ausnahme: Das USES in der DPR, vor allem die Units mit IN, welches vom Projektmanager verwaltet wird.
Da hier das Uses dabei komplett neu geschrieben wird, kann/wird es passieren, dass z.B. Formatierungen, Kommentare und IFDEF verloren gehen.


Deine Unit muß hierbei bloß vor/über der "Forms"-Unit liegen, denn Application gibt dort im Finalization noch existierende Forms und DataModule frei.

venice2 29. Aug 2022 15:12

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Du kannst einen kleinen Nagel auch mit einer Zange ins Holz hauen
Klar doch.
Nehme lieber einen Fingerhut damit geht's auch.

Nu dann ist die Unit von Uwe auch falsch bis auf den zusätzlichen Parameter ist es der gleiche Aufruf.
Delphi-Quellcode:
  if AutoRestart then begin
    ShellExecute(0, 'open', PChar(ParamStr(0)), AutoRestartCmdLine, nil, SW_SHOW);
PWideChar bleibt PWideChar ob ich nun PChar übergebe und der passende Pendant vom Compiler zu gewiesen wird bleibt sich gleich.
Also verwende ich die passende Konvertierung direkt.

Müßig jetzt darüber zu streiten.

himitsu 29. Aug 2022 15:28

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Zitat von venice2 (Beitrag 1510950)
Also verwende ich die passende Konvertierung direkt.

Sie sind nur zufällig passend.

ShellExecuteW und PWideChar mit einem UnicodeString oder WideString
oder ShellExecute und PChar mit einem String.

Früher dachten auch viele ShellExecute mit PAnsiChar funktioniert ja, da PChar ein PAnsiChar war. :roll:

venice2 29. Aug 2022 15:43

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Sie sind nur zufällig passend.
Ach.. Sicher doch. Zufällig!

Unit ShellAPI

Delphi-Quellcode:
function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,
  Directory: PWideChar; ShowCmd: Integer): HINST; stdcall;

function ShellExecute; external shell32 name 'ShellExecuteW';

himitsu 29. Aug 2022 16:42

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Niemand hat behauptet, dass Delphi frei von Bugs sei. :stupid:

Delphi 7
Delphi-Quellcode:
function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,
  Directory: PAnsiChar; ShowCmd: Integer): HINST; stdcall;

function ShellExecute; external shell32 name 'ShellExecuteA';
Lazarus/FreePascal
Delphi-Quellcode:
{ascfun.inc} function ShellExecute(_para1:HWND; _para2:pchar; _para3:pchar;_para4:pchar; _para5:pchar;_para6:longint):HINST; external 'shell32' name 'ShellExecuteA';

sowie
Delphi-Quellcode:
{unifun.inc} function ShellExecute(_para1:HWND; _para2:LPCWSTR; _para3:LPCWSTR; _para4:LPCWSTR; _para5:LPCWSTR;_para6:longint):HINST; external 'shell32' name 'ShellExecuteW';


DevExpress (es geht auch einfacher, bzw. delphi-typischer, inkl. automatischer String-Konvertierung)
Delphi-Quellcode:
function dxShellExecute(AHandle: HWND; const AFileName: string; AShowCmd: Integer = SW_SHOWNORMAL): Boolean; overload;




Ansonsten werden natürlich für compiler-abhängige "Alias" auch die compiler-abhängigen Typen benutzt, was ja eigentlich klar sein sollte.
Code:
SHSTDAPI_(HINSTANCE) ShellExecuteA(__in_opt HWND hwnd, __in_opt LPCSTR lpOperation, __in LPCSTR lpFile, __in_opt LPCSTR lpParameters,
    __in_opt LPCSTR lpDirectory, __in INT nShowCmd);
SHSTDAPI_(HINSTANCE) ShellExecuteW(__in_opt HWND hwnd, __in_opt LPCWSTR lpOperation, __in LPCWSTR lpFile, __in_opt LPCWSTR lpParameters,
    __in_opt LPCWSTR lpDirectory, __in INT nShowCmd);
#ifdef UNICODE
#define ShellExecute ShellExecuteW
#else
#define ShellExecute ShellExecuteA
#endif // !UNICODE
Im Prinzip ist es ein Übersetzungsfehler ... da Pascal/Delphi leider keine Makros oder Funktions-Aliase kennt, hätte hier der Header besser anders übersetzt werden sollen.
Da Delphi selber aber keine Umschaltung zwischen ANSI und Unicode kann, gibt es hier nur auf der Entwicklerseite eventuelle Problemchen.

Allerdings hat es beim anderen ShellExecuteEx hier mal richtig funktioniert.
Delphi-Quellcode:
function ShellExecuteEx(lpExecInfo: PShellExecuteInfo):BOOL; stdcall;
function ShellExecuteExA(lpExecInfo: PShellExecuteInfoA):BOOL; stdcall;
function ShellExecuteExW(lpExecInfo: PShellExecuteInfoW):BOOL; stdcall;


Anders sieht es z.B. beim IShellDispatch2.ShellExecute aus, denn Dieses ist explizit ausschließlich als Unicode deklariert.
Delphi-Quellcode:
    [SID_IShellDispatch2]
    function ShellExecute(&File: WideString; vArgs, vDir, vOperation,
      vShow: OleVariant): HRESULT; stdcall;

venice2 29. Aug 2022 16:58

AW: Neustart der Applikation aus Stabilitätsgründen...
 
Zitat:

Niemand hat behauptet, dass Delphi frei von Bugs sei.
Dann solltest du das nicht grundsätzlich als ein von mir generierten Fehler abtun
sondern dich erst einmal auf die Gegebenheiten konzentrieren.

Ich übergebe die Definitionen die seitens meines verwendeten Delphi vorgegeben sind.
Ob diese letztendlich falsch sind oder nicht mag dahin gestellt sein.
Darum geht es doch letztendlich.
Zudem denke ich auch nicht das D2010 noch in irgendeiner weise Aktualisierungen bekommen wird.

Somit dürften alle Unklarheiten beseitigt sein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:43 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