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