Autor Beitrag
AScomp
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Di 05.01.10 07:51 
Guten Morgen,

mit try..except kann ich im Normalfall ja das Auslösen bzw. die Anzeige von Exceptions verhindern. Bisher ging ich davon aus, dass

ausblenden Delphi-Quelltext
1:
2:
3:
4:
try
   bla;
except
end;


wirklich ALLE möglicherweise beim Aufruf von "bla" auftretenden Exceptions abgefangen werden und der Programmablauf nicht abgebrochen wird.

In einem anderen Forenbereich hatte ich jetzt von einem Problem mit folg. Sourcecode berichtet:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
     try
        if CreateLogfile then begin
           AssignFile(LogDatei, AppDataDir + 'mk.log');
           if FileExists(AppDataDir + 'mk.log'then
              Append(LogDatei)
           else
              ReWrite(LogDatei);
           WriteLn(LogDatei, Info);
        end;
     finally
        try
           CloseFile(LogDatei);
        except
        end;
        Application.ProcessMessages;
     end;


Trotz try..finally wurde nämlich beim Aufruf von "Append(LogDatei)" eine Exception ausgelöst, die von madExcept behandelt wurde.

Inzwischen hab ich die entsprechenden, möglicherweise auftretenden Exceptions in obigem Sourcecode durch den Schalter {$I-} erstmal deaktiviert.

Dann noch folgender Fall:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
        try
           FormProgress.VCLZipVerify.ReadZip;
           FormProgress.VCLZipVerify.CheckArchive;
        except
           On EUserCanceled do
              ExecutionCancelled := true;
        end;


Ich ging bisher anscheinend fälschlicherweise davon aus, dass mit diesem Sourcecode alle Exceptions abgefangen werden und nur im Falle der Exception EUserCancelled die Variable noch auf true gesetzt wird.

Doch anscheinend ist das falsch. Der obige Sourcecode fängt nur eine einzige Exception ab, eben EUserCancelled. Alle weiteren Exceptions bleiben unbehandelt und werden normal ausgegeben. Um das zu verhindern, müsste ich wohl den Sourcecode wie folgt abändern:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
        try
           FormProgress.VCLZipVerify.ReadZip;
           FormProgress.VCLZipVerify.CheckArchive;
           except
              On EUserCanceled do
                 ExecutionCancelled := true;
           else
              // alle anderen Exceptions hier abfangen
        end;


Doch was heißt das jetzt genau für:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
try
   bla;
except
end;


Heißt das, dass in diesem Beispiel ALLE Exceptions abgefangen werden (da im except-Abschnitt keine Exception explizit behandelt wird)? Und würde sich das Verhalten ändern, sobald ich im except-Abschnitt ein on EIrgendwas do einfüge (nämlich derart, dass nur noch diese eine Exception abgefangen wird, während alle anderen unbehandelt bleiben und entsprechend auch vom Programm ausgegeben werden?)?

Danke schonmal, falls jemand meinen Ausführungen überhaupt folgen konnte - wurde ja ein richtiger Roman. ;)
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 05.01.10 10:46 
user profile iconAScomp hat folgendes geschrieben Zum zitierten Posting springen:

Doch was heißt das jetzt genau für:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
try
   bla;
except
end;


Heißt das, dass in diesem Beispiel ALLE Exceptions abgefangen werden (da im except-Abschnitt keine Exception explizit behandelt wird)? Und würde sich das Verhalten ändern, sobald ich im except-Abschnitt ein on EIrgendwas do einfüge (nämlich derart, dass nur noch diese eine Exception abgefangen wird, während alle anderen unbehandelt bleiben und entsprechend auch vom Programm ausgegeben werden?)?

Ja. Allerdings ist es keine gute Idee Exceptions nicht zu behandeln. Ist ungefähr so, als wenn du im Auto die Tankanzeige ausbaust.
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Di 05.01.10 12:32 
Das ist soweit klar - danke!
jakobwenzel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Di 05.01.10 15:19 
user profile iconAScomp hat folgendes geschrieben Zum zitierten Posting springen:
Trotz try..finally wurde nämlich beim Aufruf von "Append(LogDatei)" eine Exception ausgelöst, die von madExcept behandelt wurde

Das soll auch so, try...finally ist dazu da um etwas (beispielsweise das Freigeben von Objekten) auch dann durchzuführen wenn eine Exception auftrat. Gefangen wird die Exception nur im try...except.

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Di 05.01.10 15:34 
user profile iconjakobwenzel hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconAScomp hat folgendes geschrieben Zum zitierten Posting springen:
Trotz try..finally wurde nämlich beim Aufruf von "Append(LogDatei)" eine Exception ausgelöst, die von madExcept behandelt wurde

Das soll auch so, try...finally ist dazu da um etwas (beispielsweise das Freigeben von Objekten) auch dann durchzuführen wenn eine Exception auftrat. Gefangen wird die Exception nur im try...except.


Sicher? Ich bezweifle, dass es so ist. Im Beitrag www.delphi-forum.de/...ryfinally_96919.html kam das auch so rüber, als ob finally eher die Exception "schlucken" würde.

Demzufolge müsste man dann except und finally auch gemeinsam nutzen können.

Also beispielsweise sowas:


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
     try
        if CreateLogfile then begin
           AssignFile(LogDatei, AppDataDir + 'mk.log');
           if FileExists(AppDataDir + 'mk.log'then
              Append(LogDatei)
           else
              ReWrite(LogDatei);
           WriteLn(LogDatei, Info);
        end;
     except
     finally
        try
           CloseFile(LogDatei);
        except
        end;
        Application.ProcessMessages;
     end;


Sprich: Wenn im try-Abschnitt eine Exception auftritt, soll diese "geschluckt" werden und der finally-Abschnitt abgearbeitet werden.
JDF
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 29

WinNT, Win2k, WinXP, Win2003
d6ent, d7pro, bds2006ent, vs2003
BeitragVerfasst: Di 05.01.10 15:54 
Hi,

Zitat:
Demzufolge müsste man dann except und finally auch gemeinsam nutzen können.


ist eine schöne Idee, andere Programmiersprachen können das.

Im Delphi kenne ich nur die Schachtelung von try..except und try..finally.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure Test;
begin
  TRY
    Objekt.Erstellung;
    TRY
      TRY
        Objekt.Nutzung;
      EXCEPT
        Objekt-Anhängige Fehlerbearbeitung;
      END;
    FINALLY
      Objekt.Beendigung;
    END;
  EXCEPT
    Objekt-Unabhängige Fehlerbearbeitung;
  END;
end;


Ohje, der Konstrukt sieht schlimm aus.

Gruß
Jürgen
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Di 05.01.10 16:04 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
    TRY
      TRY
        Objekt.Nutzung;
      EXCEPT
        Objekt-Anhängige Fehlerbearbeitung;
      END;
    FINALLY
      Objekt.Beendigung;
    END;


Ich meine, dass das try..finally hier überhaupt keine Wirkung hat. Genauso gut hätte man doch folg. machen können:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
      TRY
        Objekt.Nutzung;
      EXCEPT
        Objekt-Anhängige Fehlerbearbeitung;
      END;
      Objekt.Beendigung;


Bzw. falls im except nicht alle möglichen Exceptions abgefangen werden:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
      TRY
        Objekt.Nutzung;
      EXCEPT
        Objekt-Anhängige Fehlerbearbeitung;
      ELSE
      END;
      Objekt.Beendigung;
jakobwenzel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Di 05.01.10 16:10 
Wenn hier aber in der Objekt-Anhängigen Fehlerbearbeitung nochmal ne Exception auftritt hast du ein nicht freigegebenes Objekt.

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Do 11.03.10 20:42 
Hallo,

hätte nochmal eine Frage hierzu:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
function _GetFileSize(const FileName: string): Int64;
var
  FileStream: TFileStream;
begin
  Result := -1;
  try
    try
       FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
       Result := FileStream.Size;
    except
    end;
  finally
    try
      FileStream.Free;
    except
    end;
  end;
end;


Geht das nicht einfacher?

Ein

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
try
  ..
except
  ..
finally
  ..
end;


gibt's ja anscheinend nicht.

Wie löse ich also obige Mini-Funktion sauber?

Das try..finally bräuchte ich ja eigentlich nicht, da ich die Exceptions ohnehin fange und der zweite try..except-Block somit ja in jedem Fall aufgerufen wird, richtig?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
function _GetFileSize(const FileName: string): Int64;
var
  FileStream: TFileStream;
begin
  Result := -1;
  try
     FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
     Result := FileStream.Size;
  except
  end;
  try
    FileStream.Free;
  except
  end;
end;


Sieht auch nicht viel besser aus.

Vielen Dank!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 11.03.10 20:58 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function _GetFileSize(const FileName: string): Int64;
var
  FileStream: TFileStream;
begin
  Result := -1;
  try
    FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
    try
       Result := FileStream.Size;
    finally
      FileStream.Free;
    end;
  except
    //Catch the exception
  end;
end;

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Do 11.03.10 21:13 
Danke dir, das hatte ich auch schon - was mich stört ist, dass es zwei try-Blöcke sind.

Aber da es keine try..except..finally-Blöcke zu geben scheint, wird das wohl die einzige Möglichkeit sein.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 11.03.10 21:24 
user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function _GetFileSize(const FileName: string): Int64;
var
  FileStream: TFileStream;
begin
  Result := -1;
  try
    FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
    try
       Result := FileStream.Size;
    finally
      FileStream.Free;
    end;
  except
    //Catch the exception
  end;
end;

Was soll der äußere try-except-Block? Und was sagt der Delphi Compiler dazu?

Richtig wäre:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
Objekt erstellen
try
  try
    mit Objekt arbeiten
  except
    Excpetions behandeln
  end
finally
  Objekt freigeben
end
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Do 11.03.10 21:29 
Warum? Ich möchte ja, dass keine Exception angezeigt wird.

Wenn in deinem Beispiel der FileStream nicht erstellt werden kann, wird trotzdem der finally-Abschnitt aufgerufen und versucht, den FileStream wieder freizugeben.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 11.03.10 21:46 
dann so rum:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
try
  <Resource belegen>
  try
    <Mit der Resource arbeiten>
  finally
    <Resource freigeben>
  end;
except
  <Ausnahme behandeln>
end;


Aber was für ein Grund gibt es einen aufgetretenen Fehler unterdrücken zu wollen? Der Benutzer wäre über eine aussagekräftige Fehlermeldung bestimmt sehr erfreut, als einfach so im dunklen stehen gelassen zu werden und eventuell einen Datenverlust zu erleiden.
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Do 11.03.10 21:51 
Dass ich die Exception DORT nicht abfange heißt ja nicht, dass sie überhaupt nicht abgefangen wird. Nur eben nicht an dieser Stelle. ;)

Zitat:

dann so rum:


So hat es BenBe doch vorgeschlagen, oder entgeht mir schon wieder was? :D
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 11.03.10 22:10 
Mist, stimmt. Ich schiebe das jetzt mal auf meine Kopfschmerzen.
AScomp Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 162


Delphi 5, Delphi 7, Delphi 2007, Delphi 2009, Delphi XE, Delphi 10 Seattle
BeitragVerfasst: Do 11.03.10 22:11 
Gute Besserung!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 12.03.10 01:23 
@Luckie: Die Fehlerbehandlung wird in dieser Routine basierend auf dem Result erledigt. Sauberer wäre es aber mit CreateFile die Datei zu öffnen und über das Handle wenn möglich einen THandleStream aufzubauen. Wobei man für diesen Fall auch gleich komplett über die WinAPI gehen könnte, was sogar die Nutzung einer Exception hier ganz vermeidet ...

P.S.: Sollte man schlafen gehen, wenn man im vorigen Post "Gute Bescherung" liest?

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Fr 12.03.10 03:34 
Die Kombination CreateFile/GetFileSizeEx/CloseHandle ist an der Stelle tatsächlich vorzuziehen.
Allein schon, weil man dann volle Kontrolle über Fehlercodes hat, und außerdem um den Aufwand der Klasseninstantiierung herum kommt.

P.S.: Ja, direkt bis zum Dezember durchschlafen...

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."