Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung (https://www.delphipraxis.net/187698-windows-toetet-delphi-anwendung-noch-vor-unit-finalisierung.html)

Der schöne Günther 23. Dez 2015 19:08

Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Es geht um das Herunterfahren bzw. Abmelden des Benutzers. Ich stelle hier grade fest dass beim Herunterfahren Code im
Delphi-Quellcode:
finalization
-Abschnitt einer Unit nicht ausgeführt wird. Wenn ich das Herunterfahren "fälsche" indem ich mir selbst einfach eine
Delphi-Quellcode:
WM_ENDSESSION
-Nachricht schicke beendet sich die VCL-Anwendung zwar auch, führt aber auch ordentlich alles im finalization-Abschnitt aus.

Mein kompletter Code sieht folgendermaßen aus:

Delphi-Quellcode:
procedure TForm3.FormCreate(Sender: TObject);
begin
   Application.HookMainWindow(wndProcHook);
end;

function TForm3.wndProcHook(var message: TMessage): Boolean;
begin
   Result := false;
   case message.Msg of
      WM_ENDSESSION: begin
         placefile('ZZzzz 1');
         sleep(5000);
         placefile('ZZzzz 2');
         Halt(0);
      end;
   end;
end;

initialization
finalization
   placeFile('unit finalization');
end.
Delphi-Quellcode:
placeFile(..)
legt nur eine leere Datei im gleichen Verzeichnis wie die exe an.

Wenn ich das Herunterfahren "fälsche" erhalte ich die drei Dateien "ZZzzz 1", "ZZzzz 2" und "unit finalization". Melde ich mich richtig ab, fehlt das "unit finalization" einfach.

Ich habe keine Ahnung wie ich das debuggen könnte. Meine Vermutung: Irgendeine Unit-Finalisierung der VCL ist vor meiner dran. Dort drin werden wohl weiter kurz Messages abgearbeitet. Das ist tödlich, denn Windows nimmt so etas nach einem
Delphi-Quellcode:
WM_ENDSESSION
zum Anlass das Programm direkt abzuschießen.

Siehe hier: Once you return from the WM_ENDSESSION message, your process can be terminated at any time.


Es ist eine schwache Vermutung, aber die einzige die ich habe. Mein Ziel ist es, dass die Finalisierung aller Units ausgeführt wird und Windows meine Anwendung nicht vorher abschießt. Kann mir jemand helfen? :pale:

Uwe Raabe 23. Dez 2015 20:27

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Ich meine, die 5 Sekunden sind genau die Zeit, die Windows wartet, bis es eine Anwendung als unresponsive einfach killt.

Slightly OT: Den Hook kannst du dir sparen. Dies tut's auch:

Delphi-Quellcode:
    procedure wmEndSession(var Message: TMessage); message WM_ENDSESSION;

Sir Rufo 23. Dez 2015 21:03

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Wenn du noch etwas zu erledigen hast, dann musst du das währen der
Delphi-Quellcode:
WM_ENDSESSION
Nachricht machen.

Nach dieser Nachricht kann alles passieren (z.B. Windows killt den Prozess).

jaenicke 23. Dez 2015 22:19

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Und wenn du etwas erledigen musst, das länger dauert, musst du Windows das mitteilen. Du kannst dich entsprechend registrieren und wirst dann auch auf dem Herunterfahren-Bildschirm angezeigt in der Liste der Anwendungen, die das Herunterfahren blockieren.

Wir haben keinerlei wichtigen Code in finalization drin. Es gibt Startup- und Shutdown-Abläufe, die aber sämtlich innerhalb des begin..end des Projekts ablaufen. In finalization passieren nur noch Sachen, auf die wir keinen Einfluss haben (Delphi-Units, 3rd-Party Units, ...).
Das macht auch das Debuggen deutlich einfacher.

Luckie 23. Dez 2015 23:00

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Wobei, ab Vista ist Windows da nicht mehr so gutmütig. Und das ist auch richtig.

Sorg dafür, dass da nichts wichtiges mehr passiert.

Der schöne Günther 24. Dez 2015 06:48

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Vielen Dank für die Antworten bislang.

Zitat:

Zitat von Sir Rufo (Beitrag 1325164)
musst du das währen der
Delphi-Quellcode:
WM_ENDSESSION
Nachricht machen.

Aber das tue ich doch. :warn: In "Halt" beendet sich Delphi sogar mit ExitProcess selbst anstatt darauf zu warten dass Windows es tut. De facto antwortet die Anwendung nie auf WM_ENDSESSION, sondern schießt sich selbst vorher ab. Was ja auch an sich nicht verkehrt ist.

Zitat:

Zitat von jaenicke (Beitrag 1325166)
Und wenn du etwas erledigen musst, das länger dauert, musst du Windows das mitteilen. Du kannst dich entsprechend registrieren und wirst dann auch auf dem Herunterfahren-Bildschirm angezeigt in der Liste der Anwendungen, die das Herunterfahren blockieren.

Du meinst ShutdownBlockReasonCreate(..), richtig? Ich versuche es nochmal, das hat aber keinen Unterschied gemacht.
Vielleicht könnte es doch helfen, denn vielleicht gelten die von Uwe angesprochenen fünf Sekunden ja nachträglich wenn die Anwendung plötzlich kein sichtbares Fenster mehr hat:
Zitat:

Zitat von Uwe Raabe (Beitrag 1325162)
die Windows wartet, bis es eine Anwendung als unresponsive einfach killt.

Aber ich kann die "Sleep"-Zeit im Beispiel auch auf 15 Sekunden hochdrehen. Das zweite "ZZzz" wird trotzdem immer problemlos auf die Platte gespeichert. Das Problem ist nicht die Zeit, sondern das, was durch "Halt" in irgendeiner der Unit-Finalisierungen passiert...



Zitat:

Zitat von jaenicke (Beitrag 1325166)
Wir haben keinerlei wichtigen Code in finalization drin. In finalization passieren nur noch Sachen, auf die wir keinen Einfluss haben (Delphi-Units, 3rd-Party Units, ...).

Das heißt theoretisch müsste man sagen "Unit-Finalisierung und Klassen-Destruktoren: Naja- Können ausgeführt werden, vielleicht aber auch nicht."?
Wir haben leider durchaus Anwendungen welche im Klassen-Destruktor noch beispielsweise Dateien flushen und schließen. Jetzt im Nachhinein zu sehen dass höchstwahrscheinlich nicht ausgeführt wird wenn Windows heruntergefahren wird und die Anwendung noch offen ist schockiert mich ehrlich gesagt etwas ziemlich.

Zitat:

Zitat von Luckie (Beitrag 1325169)
Sorg dafür, dass da nichts wichtiges mehr passiert.

Wie soll das gehen? Ich könnte nach WM_QUERYENDSESSION schon anfangen die Zelte abzubauen, aber helfen tut mir das im Endeffekt doch auch nichts...


Meine Vermutung zur Ursache des vorzeitigen Ablebens bleibt weiterhin dass irgendeine Unit-Finalisierung der VCL/RTL weiterhin in der Nachrichtenschleife der Anwendung wühlt und Windows die Anwendung darauf hin direkt killt.

Sir Rufo 24. Dez 2015 09:40

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1325181)
Zitat:

Zitat von Sir Rufo (Beitrag 1325164)
musst du das währen der
Delphi-Quellcode:
WM_ENDSESSION
Nachricht machen.

Aber das tue ich doch. :warn: In "Halt" beendet sich Delphi sogar mit ExitProcess selbst anstatt darauf zu warten dass Windows es tut. De facto antwortet die Anwendung nie auf WM_ENDSESSION, sondern schießt sich selbst vorher ab. Was ja auch an sich nicht verkehrt ist.

Du sagst, dass du deiner Anwendung schon selber ein
Delphi-Quellcode:
WM_ENDSESSION
geschickt hast.

Wie schickst du denn? Mit
Delphi-Quellcode:
SendMessage
?
Dann bleibt also diese sendende Anwendung hängen? (Weil
Delphi-Quellcode:
SendMessage
blockiert, bis es eine Rückmeldung bekommt)

Oder bekommst du dort doch eine Rückmeldung?

Einfach mal ausprobieren und ich wette, da kommt etwas zurück :)

nahpets 24. Dez 2015 10:09

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Nur mal so al "Spekulatius":

Warum Halt?

Würde das Programm lieber "regulär" beenden, statt
Delphi-Quellcode:
Halt(0);
mit
Delphi-Quellcode:
Application.MainForm.Close;
.
Beende meine Programme eigentlich immer damit, dass ich das Hauptformular schließe.

Die Hilfe von Delphi 7 sagt zu Halt:
Zitat:

Zitat von Delphi-Hilfe
Beschreibung

Die Prozedur Halt löst einen Programmabbruch aus und gibt die Steuerung an das Betriebssystem zurück.

und genau das scheint ja auch zu passieren. Warum soll denn dann noch was ausgeführt werden?

Ansonsten: Wie wäre es mit dem ebenfalls in der Hilfe beschriebenen:
Zitat:

Zitat von Delphi-Hilfe
Beschreibung

Rufen Sie Terminate auf, um die Anwendung programmgesteuert zu beenden. Durch einen Aufruf der Methode Terminate wird das Anwendungsobjekt nicht einfach gelöscht, die Anwendung kann vielmehr ordnungsgemäß heruntergefahren werden.

Also
Delphi-Quellcode:
Application.Terminate;
?

Warum das Programm "brutal" mit Halt beenden, wenn es auch moderat geht?

Der schöne Günther 24. Dez 2015 10:15

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Zitat:

Zitat von nahpets (Beitrag 1325207)
Warum Halt?

Halt nehme ich da es
1. Die VCL auch von selbst so macht (siehe weiter unten)
2. Ich keine andere Möglichkeit kenne die Units finalisieren zu lassen


Zitat:

Zitat von Sir Rufo (Beitrag 1325198)
Einfach mal ausprobieren und ich wette, da kommt etwas zurück :)

Uh, nein, da kommt gar nichts zurück. Die Vcl sagt standardmäßig:

Delphi-Quellcode:
Vcl.Forms.TApplication.WndProc(..)
begin
   [...]
   WM_ENDSESSION:
      begin
         [...]
         if EndSessionMsg.EndSession then begin
            Application.Terminate;
            Halt;
            end;
   [...]
end;
Delphi-Quellcode:
Halt
ist, soweit ich weiß, die einzige Möglichkeit, die Unit-Finalisierung aufzurufen.

System.Halt sagt:

Delphi-Quellcode:
procedure _Halt0;
begin
   [...]
   FinalizeUnits;
   [...]
   WinApi.Windows.ExitProcess(ExitCode);
end;
Eine VCL-Anwendung antwortet somit nie auf ein
Delphi-Quellcode:
WM_ENDSESSION
, sondern schießt sich vorher ab. Klingt komisch, ist aber doch völlig legitim. Ich denke eher das Abräumen der Formulare sorgt dafür dass Windows denkt "So, der ist ja durch. Weg mit dem".

Ich versuche mal, schon alle Formulare in
Delphi-Quellcode:
WM_QUERYENDSESSION
zu zerstören. Vielleicht bringt das ja was...

Sir Rufo 24. Dez 2015 10:15

AW: Windows tötet Delphi-Anwendung noch vor Unit-Finalisierung
 
Zitat:

Zitat von nahpets (Beitrag 1325207)
Warum das Programm "brutal" mit Halt beenden, wenn es auch moderat geht?

Weil Borlacadero das so in
Delphi-Quellcode:
procedure TApplication.WndProc(var Message: TMessage);
programmiert hat? :stupid:


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:57 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz