AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Anwendung sauber beenden bei Shutdown
Thema durchsuchen
Ansicht
Themen-Optionen

Anwendung sauber beenden bei Shutdown

Ein Thema von TUX_der_Pinguin · begonnen am 6. Dez 2010 · letzter Beitrag vom 7. Dez 2010
Antwort Antwort
TUX_der_Pinguin

Registriert seit: 1. Jun 2005
Ort: Anholt (NRW)
608 Beiträge
 
Delphi 11 Alexandria
 
#1

Anwendung sauber beenden bei Shutdown

  Alt 6. Dez 2010, 14:50
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:
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.
Ich habe zwar diverse Beiträge gefunden zu dem Thema gefunden, da durch bin ich erst auf WM_QUERENDSESSION
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?

mfg

TUX

p.s. Entwicklungsumgebung ist Delphi 2009 Prof.

Anbei die Test-Anwendung
Angehängte Dateien
Dateityp: zip Shutdown-Test.zip (258,8 KB, 5x aufgerufen)
  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
 
#2

AW: Anwendung sauber beenden bei Shutdown

  Alt 6. Dez 2010, 15:05
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
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 ChrisE
ChrisE

Registriert seit: 15. Feb 2006
Ort: Hechingen
504 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

AW: Anwendung sauber beenden bei Shutdown

  Alt 6. Dez 2010, 15:10
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]
Christian E.
Es gibt 10 Arten von Menschen, die die Binär lesen können und die die es nicht können

Delphi programming rules
  Mit Zitat antworten Zitat
dfried

Registriert seit: 16. Aug 2005
486 Beiträge
 
#4

AW: Anwendung sauber beenden bei Shutdown

  Alt 6. Dez 2010, 15:13
ich glaube WM_ENDSESSION ist Dein Freund....
Fast, es ist WM_QUERYENDSESSION
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.139 Beiträge
 
Delphi 12 Athens
 
#5

AW: Anwendung sauber beenden bei Shutdown

  Alt 6. Dez 2010, 15:21
Laß' die Schleife in WMEndSession weg.

Grund.

Application.ProcessMessages; verarbeitet die Nachrichten behandlung.
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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von ChrisE
ChrisE

Registriert seit: 15. Feb 2006
Ort: Hechingen
504 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#6

AW: Anwendung sauber beenden bei Shutdown

  Alt 6. Dez 2010, 15:24
Fast, es ist WM_QUERYENDSESSION
Ich glaube, das bräuchte man nicht zu reimplementieren. Das Löst OnCloseQuery aus. Aber dort wird nicht unterschieden, ob es vom Anwender kommt (X oder Alt+F4) oder ob es ein Shutdown ist. Außerdem sollte man in diesem Ereignis nicht all zu lange rum machen, nur quasi schnell antworten ob ein Schliessen möglich ist oder nicht.

WM_ENDSESSION wird hingegen unter anderen Bedingungen ausgelößt und man erkennt wie gesagt an dem WPARAM der Message woher der Aufruf kommt.

Laß' die Schleife in WMEndSession weg.
Dem kann ich mich nur anschliessen. Ich würde in WM_ENDSESSION nur dafür sorgen, dass die Methode abgebrochen wird.

Gruß, Chris
Christian E.
Es gibt 10 Arten von Menschen, die die Binär lesen können und die die es nicht können

Delphi programming rules
  Mit Zitat antworten Zitat
TUX_der_Pinguin

Registriert seit: 1. Jun 2005
Ort: Anholt (NRW)
608 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Anwendung sauber beenden bei Shutdown

  Alt 7. Dez 2010, 11:32
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:
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;
Die eigentliche Routine die die Arbeit erledigt steht im Thread und sieht wie folgt aus.
Delphi-Quellcode:
procedure TUpdate.Execute;
begin
  while (Counter < 500000) and not Terminated do begin
    Synchronize(Show);
    Inc(Counter);
  end;{while}
end;
Anbei noch mal das gesamte Test-Projekt.

Vielen dank für die Tipps und Anregungen.

MFG

TUX
Angehängte Dateien
Dateityp: zip Shutdown-Test.zip (263,8 KB, 23x aufgerufen)
  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 22:39 Uhr.
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