Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Try Finally End verlassen bzw. abbrechen (https://www.delphipraxis.net/180570-try-finally-end-verlassen-bzw-abbrechen.html)

Schwedenbitter 30. Mai 2014 10:45

Try Finally End verlassen bzw. abbrechen
 
Hallo,

ich stehe vor folgendem Problem und irgendwie auf dem Schlauch:

In einem sehr einfachen Programm soll beim Klick auf einen Button etwas gemacht werden. Dazu wird der Button zunächst deaktiviert und am Ende wieder aktiviert. Wenn zwischendurch etwas nicht klappt, soll der weitere Code nicht mehr ausgeführt, der Button aber wieder aktiviert werden.
Um es übersichtlich zu haben, möchte ich nicht das ganze verschachteln und - weil vermutlich nicht lege artis - auf ein
Delphi-Quellcode:
goto
verzichten. Da es sich am Code vermutlich besser erklären lässt, folgendes Beispiel:
Delphi-Quellcode:
Procedure TForm1.BtnStartClick(Sender: TObject);
Const
   DummySpace   ='C:\$space';
Begin
   BtnStart.Enabled:=False;
   MELog.Lines.Clear;
   Try
      MELog.Lines.Append('Step 1: Allocating Memory');
      MELog.Lines.Append('- creating directory "' + DummySpace + '"');
      If (Not CreateDir(DummySpace)) And
         (Not DirectoryExists(DummySpace)) Then
      Begin
         MELog.Lines.Append(' Could not create "' + DummySpace + '".');
         MELog.Lines.Append(' Error was: "' + SysErrorMessage(GetLastError) + '"');
         MELog.Lines.Append(' Opreation aborted.');

         // Hier muss/will ich raus.

      End
      Else MELog.Lines.Append(' success...')

      // Hier nur weiter, wenn Verzeichnis angelegt wurde/existiert

   Finally
      BtnStart.Enabled:=True;
   End;
End;
Wenn Ihr mir sagt, dass es ohne
Delphi-Quellcode:
goto
nicht geht, dann soll es eben so sein. Eine andere Idee wäre auch, durch eine Division durch Null eine Exception zu produzieren. Aber auch das ist nicht kunstgerecht. Das ist bestimmt total einfach und mir zugegebener Maßen schon fast peinlich diese Frage zu stellen. Aber auch Suchworte wie "abort try finally" und dergleichen brachten mich bislang nicht weiter ...

Gruß, Alex

Uwe Raabe 30. Mai 2014 10:47

AW: Try Finally End verlassen bzw. abbrechen
 
Wenn kein weiter Code nach dem
Delphi-Quellcode:
finally-end
mehr kommt, dann kannst du auch einfach mit
Delphi-Quellcode:
Exit
raus. Auch bei
Delphi-Quellcode:
Exit
werden umschließende
Delphi-Quellcode:
finally
-Abschnitte ausgeführt.

Uwe Raabe 30. Mai 2014 10:50

AW: Try Finally End verlassen bzw. abbrechen
 
Obwohl, sauberer wäre es, den Code einfach in den entsprechenden then bzw. else Blöcken auszuführen:

Delphi-Quellcode:
Procedure TForm1.BtnStartClick(Sender: TObject);
Const
   DummySpace  ='C:\$space';
Begin
   BtnStart.Enabled:=False;
   MELog.Lines.Clear;
   Try
      MELog.Lines.Append('Step 1: Allocating Memory');
      MELog.Lines.Append('- creating directory "' + DummySpace + '"');
      If (Not CreateDir(DummySpace)) And
         (Not DirectoryExists(DummySpace)) Then
      Begin
         MELog.Lines.Append(' Could not create "' + DummySpace + '".');
         MELog.Lines.Append(' Error was: "' + SysErrorMessage(GetLastError) + '"');
         MELog.Lines.Append(' Opreation aborted.');

         // Hier muss/will ich raus.

      End
      Else begin // <<<<<
         MELog.Lines.Append(' success...')

        // Hier nur weiter, wenn Verzeichnis angelegt wurde/existiert
      end; // <<<<<

   Finally
      BtnStart.Enabled:=True;
   End;
End;

himitsu 30. Mai 2014 11:18

AW: Try Finally End verlassen bzw. abbrechen
 
Du könntest natürlich auch eine Variable setzen und danach entsprechend darauf reagieren.

Oder wie wäre es wemm du den Code in entsprechende Funktionen aufteilst? :stupid:


PS: "C:\$space" ... also im Grunde mag ich es absolut nicht, wenn irgenwelche Programme irgendwo einfach so rumschreiben.
Wie wäre es mit dem Temp-Verzeichnis?

stahli 30. Mai 2014 11:19

AW: Try Finally End verlassen bzw. abbrechen
 
Hier gab es mal einige Diskussionen zu try finally: http://www.delphipraxis.net/160164-f...ewuenscht.html

Wichtig zu wissen ist (wie Uwe schrieb), dass Exit in den finally-Block springt aber mögliche nachfolgende Anweisungen dann nichtmehr ausgeführt werden sondern die Methode verlassen wird.

Sir Rufo 30. Mai 2014 11:43

AW: Try Finally End verlassen bzw. abbrechen
 
Noch geschickter wäre es doch dafür ein Konstrukt zu schreiben, dass dann wie folgt benutzt werden kann:
Delphi-Quellcode:
LStep := TaskRunner.AddStep;
LStep.Caption := 'Allocating Memory';
LStep.Add( TSubStepDirectory.Create( 'C:\$space' ) );
LStep.Add( ... );
...

LStep := TaskRunner.AddStep;
...

TaskRunner.Run;
Der TaskRunner würde per Event bei jedem Step/SubStep benachrichtigen, Exceptions fangen/protokollieren/weiterreichen (wenn gewünscht), die einzelnen Steps z.B. in einem Thread ausführen, etc.

himitsu 30. Mai 2014 12:20

AW: Try Finally End verlassen bzw. abbrechen
 
Zitat:

Zitat von stahli (Beitrag 1260775)
Wichtig zu wissen ist ...

Und das ist auch richtig so.

Exit ist zum Verlassen da,
aber nachfolgende umgebende Finally-Blöcke werden dennoch ordnungsgemäß abgearbeitet, denn dafür sind die ja da.


Nutzloses Wissen:
Wenn Exit in einer einfachen Prodedur aufgerufen wird, dann ist das ein quasi Goto zum Ende der Prozedur.
Innerhalb von Try-Finally/Except, auch impliziten Try-Finally vom Delphi, welche z.B. zum Aufräumen von lokalen String-Variablen und Interfaces eingebaut wird, wird das Exit als stille Exception implementiert, welche allerdigns von Except-Blöcken automatisch "ignoriert" wird.

Schwedenbitter 30. Mai 2014 13:01

AW: Try Finally End verlassen bzw. abbrechen
 
Zitat:

Zitat von himitsu (Beitrag 1260779)
Nutzloses Wissen:
Wenn Exit in einer einfachen Prodedur aufgerufen wird, dann ist das ein quasi Goto zum Ende der Prozedur.
Innerhalb von Try-Finally/Except, auch impliziten Try-Finally vom Delphi, welche z.B. zum Aufräumen von lokalen String-Variablen und Interfaces eingebaut wird, wird das Exit als stille Exception implementiert, welche allerdigns von Except-Blöcken automatisch "ignoriert" wird.

Wieso nutzlos? Das ist genau die Antwort, die ich gesucht habe. Tausend Dank dafür.

Ich schreibe übrigens auch nicht sinnlos in "C:\$space" rum.
Das Programm ist eine Kreation ausschließlich für mich. Es erzeugt mehrere Dateien und trägt diese in
Delphi-Quellcode:
C:\Windows\Prefetch\Layout.ini
ein. Ein anschließendes Defragmentieren schiebt sie dann an den Anfang der Platte, so dass ich dort später dann pagefile.sys platzieren kann. Im Moment mache ich das von Hand; und das nervt sehr.
Es ist quick und dirty. Allerdings für viele Rechner und ich muss sehen, wann Fehler passieren und welche Fehler das sind. Das macht mehr Arbeit als das, was das Programm eigentlich machen soll.

So. Und jetzt muss ich bloß noch suchen, wie ich Windows oder dem Programm beibringe, dass beim Start gleich die Abfrage nach Admin-Rechten kommt für Schreibrechte in "C:\Windows\Prefetch". Aber das bekomme ich auch bald raus.

Wie gesagt: tausend Dank. Alex

P.S. Wo muss ich jetzt vermerken, dass die eigentliche Frage des Themas gelöst ist?

stahli 30. Mai 2014 14:22

AW: Try Finally End verlassen bzw. abbrechen
 
zum PS: Einfach schweigen reicht ... ;-)

mkinzler 30. Mai 2014 14:24

AW: Try Finally End verlassen bzw. abbrechen
 
Zitat:

Zitat von stahli (Beitrag 1260785)
zum PS: Einfach schweigen reicht ... ;-)

Besser ist aber auf jeden Fall eine Rückmeldung.

stahli 30. Mai 2014 14:28

AW: Try Finally End verlassen bzw. abbrechen
 
Ich habe das missverständlich formuliert.
Verbale Rückmeldung und Ruhen lassen des Threads reicht aus. Ein Erledigt-Flag oder Abschließen des Threads ist nicht notwending.

himitsu 30. Mai 2014 14:35

AW: Try Finally End verlassen bzw. abbrechen
 
Ein Manifest welches ensprechende (Admin)Rechte anfordert,
oder ein externer Aufruf z.B. über Runas, oder über Eigenschaften von Verknüpfungen (lnk), oder der zugeordnete Benutzerkonto eines Services usw.


Wenn man das unbedingt markieren will, dann kann man beim Erstellen einer Frage diese als "offen" markieren und das später wieder weg machen,
oder schreibt einfach, daß und eventuell welche Lösung man genommen hat.

Dejan Vu 31. Mai 2014 08:27

AW: Try Finally End verlassen bzw. abbrechen
 
Ich würde das so lösen:
Delphi-Quellcode:
Procedure TForm1.BtnStartClick(Sender: TObject);
Const
   DummySpace  ='C:\$space';

   Procedure _DemandDirectoryCreated(string aDirectory);
   Begin
      CreateDir(aDirectory);
      if Not DirectoryExists(aDirectory) Then
         Abort;
   end;

Begin
   BtnStart.Enabled:=False;
   MELog.Lines.Clear;
   Try
      MELog.Lines.Append('Step 1: Allocating Memory');
      MELog.Lines.Append('- creating directory "' + DummySpace + '"');

      _DemandDirectoryCreated(DummySpace);
     
     MELog.Lines.Append(' success...');
      // Hier nur weiter, wenn Verzeichnis angelegt wurde/existiert

   Except
      MELog.Lines.Append(' Could not create "' + DummySpace + '".');
      MELog.Lines.Append(' Error was: "' + SysErrorMessage(GetLastError) + '"');
      MELog.Lines.Append(' Opreation aborted.');
   End;
   BtnStart.Enabled:=True;
End;

Sir Rufo 31. Mai 2014 08:35

AW: Try Finally End verlassen bzw. abbrechen
 
@Dejan Vu

Das kann evtl. funktionieren, allerdings muss der Aufruf von
Delphi-Quellcode:
GetLastError
direkt im Anschluss der Funktion aufgerufen werden, wo dieser Fehler (hier
Delphi-Quellcode:
CreateDir
) aufgetreten ist.

Ansonsten ist nicht gewährleistet, dass man auch wirklich die Fehlermeldung bekommt, die man eigentlich haben möchte.

EDIT
Eigentlich arbeitet
Delphi-Quellcode:
GetLastError
nur dann zuverlässig, wenn man gesichert direkt vorher eine Windows-Funktion aufgerufen hat.

Bei Delphi-Referenz durchsuchenSysUtils.CreateDir kann man sich da aber nicht wirklich sicher sein ...

Delphi-Quellcode:
type
  // Wenn ein Arbeitsschritt fehlschlägt, dann diese Exception werfen
  EStepException = class(Exception);

procedure TForm1.BtnStartClick( Sender : TObject );
begin
  BtnStart.Enabled := False;
  try
    try

      MELog.Lines.Append('Step 1: Allocating Memory');
      MELog.Lines.Append('- creating directory "' + DummySpace + '"');

      if ForceDirectories( DummySpace )
      then
        MELog.Lines.Append( ' success' )
      else
        raise EStepException.CreateFmt( 'Could not create "%s"', [DummySpace] );

      // nächste Schritte

    except
      on E: EStepException do
        begin
          MELog.Lines.Append( E.Message );
          MELog.Lines.Append( 'Operation aborted.' );
          raise;
        end;
    end;
  finally
    BtnStart.Enabled := True;
  end;
end;

Dejan Vu 31. Mai 2014 10:45

AW: Try Finally End verlassen bzw. abbrechen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1260849)
...allerdings muss der Aufruf von
Delphi-Quellcode:
GetLastError
direkt im Anschluss der Funktion aufgerufen werden, wo dieser Fehler (hier
Delphi-Quellcode:
CreateDir
) aufgetreten ist.

Korrekt. War mir da auch nicht sicher. Mir ging es primär um den Kontrollfluss (exceptions, statt IF-Schl... Verzweigungen). Aber wenn man Code postet, sollte der schon 100% richtig sein. Und 'ForceDirectories' hatte ich nicht mehr auf dem Schirm.

Leider ist Delphi da noch nicht konsequent und bietet durchweg Methoden an, die knallen, anstatt einen Rückgabewert zu liefern. Dann dadurch wird man ja gerade dazu verleitet, IF-THEN-Verschachtelngsorgien zu 'feiern'.

Gehört hier aber nicht hin.

himitsu 31. Mai 2014 13:06

AW: Try Finally End verlassen bzw. abbrechen
 
Exceptions sind nicht zur standardmäßigen Flusssteuerung vorgesehen und vorallem beim Debuggen fällt man mit soeinem Schrott einfach nur voll auf die Fresse.

Wobei hier das ja auch als Ausnahme gesehen werden kann, wenn man auf das Verzeichnis nicht zugreifen kann und demnach nachfolgene Operationen, welche ja die Hauptfunktionalität darstellen, nicht mehr ausführbar sind.

Dejan Vu 31. Mai 2014 13:53

AW: Try Finally End verlassen bzw. abbrechen
 
Zitat:

Zitat von himitsu (Beitrag 1260880)
Exceptions sind nicht zur standardmäßigen Flusssteuerung vorgesehen

Doch. In der modernen Softwarearchitektur schon.

Edit: 'standardmäßigen' ist das Zauberwort. Da hast Du recht. Aber es war ein ungünstiger Kommentar zu einem imho legitimen Einsatz von Exceptions.

Ich bezeichne das als happy path programming. Der Kontrollfluß zeigt, wie es im Normalfall (der happy path) aussieht und die Ausnahmen hüpfen einfach raus (bzw. in den Except/Finally Teil).

mkinzler 31. Mai 2014 13:54

AW: Try Finally End verlassen bzw. abbrechen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1260887)
Zitat:

Zitat von himitsu (Beitrag 1260880)
Exceptions sind nicht zur standardmäßigen Flusssteuerung vorgesehen

Doch. In der modernen Softwarearchitektur schon.

Also fahren nach Gehör!

BUG 31. Mai 2014 14:12

AW: Try Finally End verlassen bzw. abbrechen
 
Der Fall, das ein Verzeichnis nicht angelegt werden kann und nicht existiert, ist meiner Meinung nach eine ziemliche Ausnahme (abgesehen von merkwürdigen Ordner-Namen oder nicht existierenden Eltern-Ordnern, die sollte man vielleicht vorher abfangen).
Außerdem wird die Operation abgebrochen und ein Log-Eintrag dazu angelegt.

Was muss noch alles dazu kommen, das eine Exception gerechtfertigt ist? Random Memory Corruption? :mrgreen:

Dejan Vu 31. Mai 2014 16:58

AW: Try Finally End verlassen bzw. abbrechen
 
Zitat:

Zitat von mkinzler (Beitrag 1260888)
Zitat:

Zitat von Dejan Vu (Beitrag 1260887)
Doch. In der modernen Softwarearchitektur schon.

Also fahren nach Gehör!

Eher übersichtlichen Code produzieren!

Zitat:

Zitat von BUG (Beitrag 1260890)
Der Fall, das ein Verzeichnis nicht angelegt werden kann und nicht existiert...

Hat mich auch gewundert. Aber wenn Du das Verzeichnis anlegst und dann wird die Festplatte ausgetauscht?.... :stupid:


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