![]() |
Anwendung sauber beenden bei Shutdown
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe eine kleine Anwendung die per Timer eine Prozedur startet die einige Daten verarbeitet. Will der Benutzer diese Anwendung beenden geht dies nur wenn die Prozedur nicht läuft. Der Anwender kann die Prozedur anhalten, und dann das Programm beenden. Wird jetzt der Computer heruntergefahren während die Prozedur läuft so soll sich die Prozedur beenden und die Anwendung soll kurz warten bis die Prozedur durchgelaufen ist und dann soll der Computer herunterfahren. Der erste Teil funktioniert jedoch gibt es Probleme wenn der Computer heruntergefahren wird, so wird zwar die Prozedur angehalten jedoch scheint die Prozedur nicht korrekt beendet worden zu sein. Es scheint als würde er aus der Prozedur springen. Um das besser zu verstehen habe ich eine kleine Testanwendung gebastelt die das gleiche Problem hat. Ich habe den Timer durch einen Button ersetzt, der Button (btnStart) stößt die Prozedur "Routine" an.
Delphi-Quellcode:
Ich habe zwar diverse Beiträge gefunden zu dem Thema gefunden, da durch bin ich erst auf WM_QUERENDSESSION
unit uMain;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm4 = class(TForm) btnStart: TButton; Edit1: TEdit; btnCancel: TButton; Edit2: TEdit; procedure FormCreate(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure btnStartClick(Sender: TObject); procedure btnCancelClick(Sender: TObject); procedure Routine; procedure WMEndSession(var Msg: TMessage); message WM_ENDSESSION; procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION; private { Private-Deklarationen } bShutdown: Boolean; bStarted: Boolean; bBreak: Boolean; public { Public-Deklarationen } end; var Form4: TForm4; implementation {$R *.dfm} procedure TForm4.btnStartClick(Sender: TObject); begin Routine; end; procedure TForm4.btnCancelClick(Sender: TObject); begin //Flag zum Abbruch der Routine setzen bBreak := True; end; procedure TForm4.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin //Anwendung beenden ohne Nachfrage beim Shutdown if bShutdown then begin CanClose := True; end else begin //Läuft die Routine kann die Anwendung nicht beendet werden. if bStarted then begin CanClose := False; Application.MessageBox('Das Programm kann nicht beendet werden!', 'Hinweis', 48); end else begin //Routine läuft nicht, Anwender fragen ob Anwendung wirklich beendet werden soll if Application.MessageBox('Soll das Programm beendet werden?', 'Frage', 36) = ID_YES then CanClose := True else CanClose := False; end;{else} end;{else} end; procedure TForm4.FormCreate(Sender: TObject); begin //init bShutdown := False; bStarted := False; bBreak := False; end; procedure TForm4.Routine; var Counter: Integer; begin //Routine wurde gestartet btnStart.Enabled := False; bStarted := True; bBreak := False; Edit1.Clear; //Routine läuft... Counter := 0; while (Counter < 500000) and not bBreak do begin Edit1.Text := IntToStr(Counter); Inc(Counter); Application.ProcessMessages; end;{while} //Dieser teil wird nicht mehr ausgeführt beim Shutdown, warum auch immer //Routine ist fertig, Flags zurücksetzen etc. Edit1.Text := 'Fertig'; bStarted := False; btnStart.Enabled := True; end; procedure TForm4.WMEndSession(var Msg: TMessage); begin //Warten bis die Routine beendet wurde (Hier hängt die Anwendung, da bStarted nicht auf False gesetzt wird) while bStarted do begin Edit2.Text := FormatDateTime('hh:nn:ss:zzz', Now); Application.ProcessMessages; Sleep(100); end;{while} //Bestätigung das Windows herruntergefahren wird Msg.Result := 1; end; procedure TForm4.WMQueryEndSession(var Msg: TMessage); begin //Computer soll herruntergefahren, neugestartet oder abgemeldet werden bShutdown := True; //Flag zum Abbruch der Routine setzen bBreak := True; //Bestätigung das Windows herruntergefahren werden darf Msg.Result := 1; end; end. etc. gestoßen. Ich konnte nur nichts vergleichbares finden. Alle Beispiele haben erst in der Nachrichten Verarbeitung Routinen zum "Aufräumen" aufgerufen das scheint wohl auch so zu klappen. Nur wie bringe ich meinem Programm bei die Prozedur nicht zu verlassen sondern sauber sich zu beenden? :gruebel: mfg TUX p.s. Entwicklungsumgebung ist Delphi 2009 Prof. Anbei die Test-Anwendung |
AW: Anwendung sauber beenden bei Shutdown
Die Nachrichten sind doch aber schon in TForm implementiert
OnClose, OnCloseQuery Und da gibt es auch die Möglichkeit entsprechende Rückmeldungen zu geben (ob da jetzt was geschlossen werden darf). Problematisch ist es, zu erkennen, ob die Close-Anfrage vom Benutzer kommt (Klick auf das X oder Task beenden via TaskManager) oder eben vom ShutDown-Vorgang. Die Information, ob das System jetzt heruntergefahren werden soll, sollte aber beschaffbar sein |
AW: Anwendung sauber beenden bei Shutdown
Hallo,
ich glaube WM_ENDSESSION ist Dein Freund. Wenn da der WPARAM von Message <> 0 ist dann ist es glaube ich ein Schließen ohne das Kreuz. Müßte man aber nochmals genau nachschauen. Gruß, Chris [EDIT] Meines wissens nach wird dann auch FormClose nicht ausgelößt, wenn man Runterfährt. Deshalb habe ich das damals auch gebraucht[/EDIT] |
AW: Anwendung sauber beenden bei Shutdown
Zitat:
|
AW: Anwendung sauber beenden bei Shutdown
Laß' die Schleife in WMEndSession weg.
Grund.
Delphi-Quellcode:
verarbeitet die Nachrichten behandlung.
Application.ProcessMessages;
Dabei wartet die Abarbeitung in Routine natürlich auf das Ende von ProcessMessages. Nun wird in ProcessMessages die das WMEndSession abgearbeitet. In WMEndSession gibt es nun eine weitere Schleifen, welche neue Nachrichten behandelt, wärend auf das Ende der von Routine geawartet wird. Routine wird aber nie fertig, da es ja auf das Ende von WMEndSession wartet. :wink: |
AW: Anwendung sauber beenden bei Shutdown
Zitat:
WM_ENDSESSION wird hingegen unter anderen Bedingungen ausgelößt und man erkennt wie gesagt an dem WPARAM der Message woher der Aufruf kommt. Zitat:
Gruß, Chris |
AW: Anwendung sauber beenden bei Shutdown
Liste der Anhänge anzeigen (Anzahl: 1)
Guten Morgen,
nach reichlicher Überlegung und stundenlangem Probieren bin ich zu einer Lösung gekommen. Das Problem war das das Warten auf Beendigung der Prozedur den Ablauf der Prozedur blockiert hat. Daher habe ich die Routine in einen Thread verlagert. So ist es nun möglich diesen Thread vorzeitig zubeenden und auf dessen Beendigung zu warten.
Delphi-Quellcode:
Die eigentliche Routine die die Arbeit erledigt steht im Thread und sieht wie folgt aus.
procedure TfrmMain.btnStartClick(Sender: TObject);
begin if not bThreadRunning then begin //Flag setzen, Thread wird erzeugt und gestartet bThreadRunning := True; //Buttons btnStart.Enabled := False; btnCancel.Enabled := True; //Thread Erzeugen UpdateThread := TUpdate.Create(True); UpdateThread.FreeOnTerminate := True; UpdateThread.Priority := tpNormal; UpdateThread.OnTerminate := UpdateThreadTerminate; UpdateThread.Resume; end;{if} end; //Merkwürdigerweise wird das Ereignis OnCloseQuery beim Shutdown nicht mehr ausgeführt, obwohl in //der Richtigen Anwendung das der Fall war. Aber es ist ja ganz einfach möglich die Sicherheitsabfrage //beim Shutdown zu überspringen procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin //Anwender fragen ob Anwendung wirklich beendet werden soll if (Application.MessageBox('Soll das Programm beendet werden?', 'Frage', 36) = ID_YES) then begin //Falls Routine noch läuft wird diese beendet if bThreadRunning then begin //Thread beenden UpdateThread.Terminate; //Kurz warten bis der Thread sich beendet hat while bThreadRunning do begin Application.ProcessMessages; end;{while} end;{if} //Anwendung kann geschlossen werden CanClose := True; end else CanClose := False; end; //Dieses Ereignis wird sowohl beim Beenden durch den Anwender als auch beim Shutdown durchgeführt //Das ist es was ich die ganze Zeit wollte, explizit die Routine beenden und entsprechen "aufräumen" procedure TfrmMain.UpdateThreadTerminate(Sender: TObject); begin //Routine wurde beendet bThreadRunning := False; Edit1.Text := 'Fertig'; //Buttons btnStart.Enabled := True; btnCancel.Enabled := False; //deinitialisieren UpdateThread := nil; //Nur zu Testzwecken das man sehen kann das die Routine bis hierher "durchgelaufen" ist pDelay(1000); end; procedure TfrmMain.WMEndSession(var Msg: TMessage); begin //Kurz warten bis der Thread sich beendet hat while bThreadRunning do begin Application.ProcessMessages; end;{while} //Bestätigung das der Computer herruntergefahren wird Msg.Result := 1; end; procedure TfrmMain.WMQueryEndSession(var Msg: TMessage); begin //Falls Routine läuft muss diese abgebrochen werden if bThreadRunning then UpdateThread.Terminate; //Bestätigung das Windows herruntergefahren werden darf Msg.Result := 1; end;
Delphi-Quellcode:
Anbei noch mal das gesamte Test-Projekt.
procedure TUpdate.Execute;
begin while (Counter < 500000) and not Terminated do begin Synchronize(Show); Inc(Counter); end;{while} end; Vielen dank für die Tipps und Anregungen. MFG TUX |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:04 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