Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Exception richtig behandeln (https://www.delphipraxis.net/141185-exception-richtig-behandeln.html)

Jens Hartmann 4. Okt 2009 12:30


Exception richtig behandeln
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo zusammen,

ich habe mal eine Frage zur Behandlung von Exceptions. Ich lese Daten aus einer Textdatei in eine Datenbank ein.

Wenn jetzt z.B. Das eingelesen Datum kein gültigen Datumswert hat, wird natürlich eine Meldung beim eintragen in die Datenbank erzeugt, die mir sagt, '' ist kein gültiges Datum. (siehe Anhang). Wie kann ich jetzt in mein Commit eine sauber Exeptionbehandlung einbauen, die diese Datensätze einfach nicht übernimmt.

Probiert habe ich das ganz so, funktioniert aber leider nicht.

Delphi-Quellcode:
  VST.BeginUpdate;
  for i := 0 to High(Parser.EntriesMB256) do begin
  Daten := TOMBSerie.Create;
  with Daten do
  begin
  DM_PS.Qry_InsertMB256.Close;
  DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr;
  DM_PS.QryImportMB256.ParamByName('Datum').AsDate := StrToDate(Parser.EntriesMB256[i].Datum);
  DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit);
  DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis;
  DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer;
  DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich;

  DM_PS.QryImportMB256.ExecSQL;

  try

    DM_PS.ConPSSecur.Commit;
    DM_PS.QrySelectMaxIDMB256.Open;

  except
    on e : Exception Do begin
      ShowMessage(e.Message);
      end;

  end;



    Daten.ID := DM_PS.QrySelectMaxIDMB256.FieldByName('ID').AsInteger;
    Daten.LfdNr := Parser.EntriesMB256[i].LfdNr;
    Daten.Datum := Parser.EntriesMB256[i].Datum;
    Daten.Uhrzeit := Parser.EntriesMB256[i].Uhrzeit;
    Daten.Ereignis := Parser.EntriesMB256[i].Ereignis;
    Daten.Teilnehmer := Parser.EntriesMB256[i].Teilnehmer;
    Daten.Bereich := Parser.EntriesMB256[i].Bereich;
  end;
  VST.AddChild(nil, Daten);
  DM_PS.QrySelectMaxIDMB256.Close;
  Label6.Caption := IntToStr(StrToInt(Label6.Caption)+1);
  ProgBarDatei.Position := ID;
  Inc(ID);
  VST.ScrollIntoView(VST.GetLast, true);
  VST.EndUpdate;

  DM_PS.QrySelectMaxIDMB256.Close;
  end;
end;
Danke schon mal und Gruß

Jens

jaenicke 4. Okt 2009 12:37

Re: Exception richtig behandeln
 
Der Fehler tritt ja beim StrToDate auf, das jedoch fängst du gar nicht ab. Du solltest lieber mit TryStrToDate usw. arbeiten, dann kannst du bei nicht erfolgreicher Umwandlung auch die Eintragung gar nicht erst versuchen.

alzaimar 4. Okt 2009 12:51

Re: Exception richtig behandeln
 
Grundsätzlich sollten solche Funktionen nur mit garantiert gültigen Parametern aufgerufen werden. Das bedeutet für Dich, das du eine Sicherheitsschicht um diese eigentliche Funktion bauen musst. Diese Sicherheitsschicht nimmt die Parameter entgegen, prüft sie und wirft ggf eine Exception. Erst bei Korrektheit wird die Funktion aufgerufen. Diese kann dann wieder Fehler verursachen, die dann aber isoliert und 'in Ruhe' betrachtet werden können.

sx2008 4. Okt 2009 12:55

Re: Exception richtig behandeln
 
Ich würde an deiner Stelle eine StringListe erzeugen oder der Funktion von Aussen übergeben um darin alle Fehlermeldungen zu sammeln.
Delphi-Quellcode:
except
  on e : Exception Do
  begin
    fehlerliste.Add(Format('Entry %d: %s|%s',[i, e.Classname, e.Message]));
  end;
end;
Die Fehlerliste wird dem Benutzer am Ende präsentiert ohne dass der Benutzer jeden Fehler einzeln quittieren muss.
(ein riesen Vorteil, wenn es mal 50 oder mehr Fehler werden sollten)
Ausserdem wird auch die Entry-Nummer festgehalten; das ist wichtig, wenn man die Ursache der Fehler herausfinden möchte.

Jens Hartmann 4. Okt 2009 14:06

Re: Exception richtig behandeln
 
Hallo,

also irgendwie zue ich mir mit Exceptionbehandlungen noch sehr schwer. Ich habe die jetzt geändert, aber der Fehler ist immer noch da. Hier mal mein neuer Code.

Delphi-Quellcode:
  try
  DM_PS.Qry_InsertMB256.Close;
  DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr;
  DM_PS.QryImportMB256.ParamByName('Datum').AsDate := StrToDate(Parser.EntriesMB256[i].Datum);
  DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit);
  DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis;
  DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer;
  DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich;

  DM_PS.QryImportMB256.ExecSQL;
  DM_PS.ConPSSecur.Commit;
  except
    on e : Exception Do
      begin
        Fehlerliste.Add(Format('Entry %d: %s|%s',[i, e.Classname, e.Message]));
      end;
    end;
Vieleicht kann mir ja mal jemand sagen, wo der Fehler liegt, und mal erklären, wie ich am besten an eine solch Try/Except Sache dran gehe.

Danke schon aml

Gruß Jens

jaenicke 4. Okt 2009 15:22

Re: Exception richtig behandeln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Was heißt der Fehler ist noch da? Dass Delphi den anzeigt, wenn du das Programm aus Delphi startest? Das passiert immer, wenn der Debugger aktiv ist.

Um das zu verhindern, kannst du (wenn der Fehler angezeigt wird) dessen Anzeige einfach mit der CheckBox deaktivieren. (Siehe Anhang)
Oder einfach das Programm nicht aus Delphi sondern separat starten (Menü Start --> Ohne Debugger ausführen).

// EDIT:
Auf TryStrToDate stattdessen habe ich ja schon hingewiesen, das wäre noch besser...

Jens Hartmann 4. Okt 2009 15:43

Re: Exception richtig behandeln
 
Liste der Anhänge anzeigen (Anzahl: 3)
Das ist mir schon klar.

Der Fehler, kommt aber auch, wenn ich ohne Debugger ausführe, da ja ein Fehler vorhanden ist. Ich muss ja realisieren, wodurch der Fehler kommt, um diesen dann auszuschliessen. Nur wenn ich im Debugger auf Anhalten klicke, um an die Stelle im Code zu gelangen, wo der Fehler passiert, lande ich irgendwo im Quellcode der ZEOS Kompo und wieß jetzt nicht, wie ich anfangen kann diesen Abzufangen.

Hier nochmal die Fehlermeldungen und der Code in dem ich bei Anhalten lande.

Delphi-Quellcode:
procedure CheckInterbase6Error(PlainDriver: IZInterbasePlainDriver;
  StatusVector: TARRAY_ISC_STATUS; LoggingCategory: TZLoggingCategory = lcOther;
  SQL: string = '');
var
  Msg: array[0..1024] of Char;
  PStatusVector: PISC_STATUS;
  ErrorMessage, ErrorSqlMessage: string;
  ErrorCode: LongInt;
begin
  if (StatusVector[0] = 1) and (StatusVector[1] > 0) then
  begin
    ErrorMessage:='';
    PStatusVector := @StatusVector;
    while PlainDriver.isc_interprete(Msg, @PStatusVector) > 0 do
      ErrorMessage := ErrorMessage + ' ' + StrPas(Msg);

    ErrorCode := PlainDriver.isc_sqlcode(@StatusVector);
    PlainDriver.isc_sql_interprete(ErrorCode, Msg, 1024);
    ErrorSqlMessage := StrPas(Msg);

{$IFDEF INTERBASE_EXTENDED_MESSAGES}
    if SQL <> '' then
      SQL := Format(' The SQL: %s; ', [SQL]);
{$ENDIF}

    if ErrorMessage <> '' then
    begin
      DriverManager.LogError(LoggingCategory, PlainDriver.GetProtocol,
        ErrorMessage, ErrorCode, ErrorSqlMessage + SQL);

{$IFDEF INTERBASE_EXTENDED_MESSAGES}
      raise EZSQLException.CreateWithCode(ErrorCode,
        Format('SQL Error: %s. Error Code: %d. %s',
        [ErrorMessage, ErrorCode, ErrorSqlMessage]) + SQL);

Zitat:

Zitat von jaenicke
Auf TryStrToDate stattdessen habe ich ja schon hingewiesen, das wäre noch besser...

Und das versteh ich noch nicht so ganz.

MFG

jens

haentschman 4. Okt 2009 15:56

Re: Exception richtig behandeln
 
Hallo Jens,

Exception 2: Erklärt sich von selbst. irgendwo, wo ein Date Wert sein sollte ist nix.
Exception 1: Kommt ganz gern, wenn die Länge des Strings die Feldgröße überschreitet.

die Zugriffsverletztung :gruebel:

jaenicke 4. Okt 2009 15:59

Re: Exception richtig behandeln
 
Zitat:

Zitat von Jens Hartmann
Und das versteh ich noch nicht so ganz.

Der Umwandlungsfehler wird bei dem StrToDate kommen. Und das kannst du vorher prüfen:
Delphi-Quellcode:
var
  DateValue: TDate;
begin
  ...
  if not TryStrToDate(DeinString, DateValue) then
  begin
    ShowMessage('Fehler bei Umwandlung von ' + DeinString + ' in einen Datumswert');
    Exit; // abbrechen oder so
  end;
  ...
  // Wenn alles erfolgreich war, dann die Werte benutzen:
  DateValue ...
// EDIT:
Ja, ich weiß, Exit ist nicht unbedingt ein schöner Programmfluss, kann man natürlich auch umgekehrt formulieren.

Zu den SQL-Fehlern sage ich mangels Erfahrung lieber nix. :mrgreen:

DeddyH 4. Okt 2009 16:06

Re: Exception richtig behandeln
 
Zitat:

Delphi-Quellcode:
DM_PS.Qry_InsertMB256.Close;
...
DM_PS.ConPSSecur.Commit;

Machst Du das wirklich bei jedem Datensatz? Und wenn im Erfolgsfall ein Commit erfolgen werden soll, muss im Fehlerfall ja wohl ein Rollback erfolgen (und dann eine neue Transaktion gestartet werden). Ansonsten wie angesprochen vorher auf gültiges Datum/Uhrzeit prüfen, im Fehlerfall loggen und zum nächsten Datensatz.

haentschman 4. Okt 2009 16:10

Re: Exception richtig behandeln
 
wenn ich dich richtig verstanden habe möchtest du nur die Datensätze eintagen, die kpl. und gültige Werte haben. Alles andere soll über die Exception abgefangen werden.

sinngemäß, da du mit Zeos arbeitest.
Delphi-Quellcode:
for ... do
  begin
    StartTransaction
    try
      SQL.Text:= ....
      Parameter ....
      ExecSQL

      Commit;
    except
      Rollback;
      .....
    end
  end
damit hat jeder Datensatz eine eigene Transaktion bekommen. Wenn die Werte ungültig sind läuft das ganze in´s except und die Transaktion wird zurückgenommen. Vieleicht solltest du aber schon beim Parser auf ungültige Werte prüfen und entsprechend reagieren. Die Feldgrößen würde ich größer wählen falls du nicht weist, wie die Strings ausfallen.

:hi:


:roll: wie immer zu langsam

Jens Hartmann 4. Okt 2009 18:17

Re: Exception richtig behandeln
 
Hallo und danke an alle,

habe das ganze jetzt mal nach Euren Vorschlägen umgebaut und es funktioniert. Wäre jetzt nur die Frage, weil ich wie schon gesagt, mit den Exeptions nicht so sicher bin, ob das Soweit OK ist.

Hier mal der funktionierende Code...

Delphi-Quellcode:
procedure TImportForm.DisplayResult(Parser: TMySimpleBaseParser);
var
  i: Integer;
  ID : Integer;
  Daten : TOMBSerie;
  Fehlerliste : TStringlist;
  OutDatum : TDateTime;
begin
  ID := 1;
  ProgBarDatei.Max := High(Parser.EntriesMB256);
  VST.BeginUpdate;

  for i := 0 to High(Parser.EntriesMB256) do begin
    Daten := TOMBSerie.Create;
      with Daten do
        begin
          try
          if TryStrToDate(Parser.EntriesMB256[i].Datum,OutDatum) = true then
          begin
          DM_PS.Qry_InsertMB256.Close;
          DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr;
          DM_PS.QryImportMB256.ParamByName('Datum').AsDate := OutDatum;
          DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit);
          DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis;
          DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer;
          DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich;
          DM_PS.QryImportMB256.ExecSQL;
          DM_PS.ConPSSecur.Commit;
          end
          else
          begin
            FehlerMemo.Lines.Add('Fehler in Datensatz '+IntToStr(Parser.EntriesMB256[i].LfdNr));
            FehlerMemo.Lines.Add('In Datei');
            FehlerMemo.Lines.Add(Label1.Caption);
            FehlerMemo.Lines.Add('');
            Label9.Caption := IntToStr(StrToInt(Label9.Caption)+1);
          end;
          except
          DM_PS.ConPSSecur.Rollback;

          end;

          DM_PS.QrySelectMaxIDMB256.Open;

          Daten.ID := DM_PS.QrySelectMaxIDMB256.FieldByName('ID').AsInteger;
          Daten.LfdNr := Parser.EntriesMB256[i].LfdNr;
          Daten.Datum := Parser.EntriesMB256[i].Datum;
          Daten.Uhrzeit := Parser.EntriesMB256[i].Uhrzeit;
          Daten.Ereignis := Parser.EntriesMB256[i].Ereignis;
          Daten.Teilnehmer := Parser.EntriesMB256[i].Teilnehmer;
          Daten.Bereich := Parser.EntriesMB256[i].Bereich;
        end;
      VST.AddChild(nil, Daten);
      DM_PS.QrySelectMaxIDMB256.Close;
      Label6.Caption := IntToStr(StrToInt(Label6.Caption)+1);
      ProgBarDatei.Position := ID;
      Inc(ID);
  end;
  VST.ScrollIntoView(VST.GetLast, true);
  VST.EndUpdate;
  DM_PS.QrySelectMaxIDMB256.Close;
end;
:gruebel:

Danke nochmal

Gruß Jens

DeddyH 4. Okt 2009 18:26

Re: Exception richtig behandeln
 
Ich würde es andersherum schreiben:
Delphi-Quellcode:
...
      with Daten do
        begin
         
          if TryStrToDate(Parser.EntriesMB256[i].Datum,OutDatum){ = true} then
            try
              DM_PS.Qry_InsertMB256.Close;
              DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr;
              DM_PS.QryImportMB256.ParamByName('Datum').AsDate := OutDatum;
              DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit);
              DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis;
              DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer;
              DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich;
              DM_PS.QryImportMB256.ExecSQL;
              DM_PS.ConPSSecur.Commit;
            except
              DM_PS.ConPSSecur.Rollback;
            end
          else
          begin
            FehlerMemo.Lines.Add('Fehler in Datensatz '+IntToStr(Parser.EntriesMB256[i].LfdNr));
            FehlerMemo.Lines.Add('In Datei');
            FehlerMemo.Lines.Add(Label1.Caption);
            FehlerMemo.Lines.Add('');
            Label9.Caption := IntToStr(StrToInt(Label9.Caption)+1);
          end;
...
Wobei ich vielleicht nicht jeden Datensatz committen würde, sondern in Blöcken von z.B. 50. Und müsste anschließend nicht eine neue Transaktion gestartet werden?

haentschman 4. Okt 2009 18:59

Re: Exception richtig behandeln
 
Hallo Jens,

ich vermisse auch den Start der Transaktion. Zeos kann nur eine. Wenn AutoCommit deiner Connection auf True steht wird automatisch mit ExecSQl ein "Commit" ausgeführt. (Wie wir wissen, nur ein SoftCommit) Somit greift dein Commit eh nicht. Wie es mit dem Rollback aussieht hab ich noch nicht getestet, da ich immer eine separate Transaktion aufmache. (StartTransaktion...Commit...Rollback)

:hi:

Jens Hartmann 4. Okt 2009 19:19

Re: Exception richtig behandeln
 
Also, das was DeddyH gezeígt hat, kann ich umsetzten und funktioniert auch. Allerdings das von

Zitat:

Zitat von haentschmen
ich vermisse auch den Start der Transaktion. Zeos kann nur eine. Wenn AutoCommit deiner Connection auf True steht wird automatisch mit ExecSQl ein "Commit" ausgeführt. (Wie wir wissen, nur ein SoftCommit) Somit greift dein Commit eh nicht. Wie es mit dem Rollback aussieht hab ich noch nicht getestet, da ich immer eine separate Transaktion aufmache. (StartTransaktion...Commit...Rollback)

mit der Start Transaktion versteh ich nicht so ganz. Die Daten werden doch bei mir in die Datenbank geschrieben, das funktioniert doch alles.

Kannst Du mir das mal erklären.

Gruß Jens

haentschman 4. Okt 2009 19:31

Re: Exception richtig behandeln
 
Zeos hat standardmäßig eine Transaktion. Das heißt mit jedem ExecSQL (bei AutoCommit = True) wird diese Transaktion intern Commited und eine neue geöffnet. Dein Commit ist unnötig.

wenn du jetzt z.B. mehrere SQL Anweisungen als "Block" abarbeiten willst machst du eine neue Transaktion auf.

StartTransaktion
try
ExecSQL1
ExecSQL2
ExecSQL3
Commit
except
Rollback
end

tritt in einer der SQL Anweisungen ein Fehler auf werden alle SQL Anweisungen zurückgenommen, da sie in einer Transaktion laufen.

Unterschied verstanden ? :hi:

PS: ich mache mir standardmäßig eine neue auf. Auch mit nur einer SQL Anweisung. Es könnte ja noch eine dazukommen und du kannst genau festlegen wann Commited wird.

Jens Hartmann 4. Okt 2009 19:40

Re: Exception richtig behandeln
 
Ich habe in meiner Connection AutoCommit auf false sitzen. Deshalb führe ich das Commit aus.

Dachte bislang das das OK so ist.

Sollte man das anders machen??? :gruebel:

Gruß Jens

haentschman 4. Okt 2009 19:49

Re: Exception richtig behandeln
 
wenn AutoCommit = False dann ist dein Commit ok und nötig. Dann ist das so in Ordnung. Wenn du aber z.B. in mehrere Tabellen schreiben möchtest und die Daten immer komplett sein müssen solltest du eine neue Transaktion öffnen und die SQL Anweisungen damit "zusammenfassen".

hoffe trotzdem dir geholfen zu haben :hi:

Jens Hartmann 4. Okt 2009 20:04

Re: Exception richtig behandeln
 
Ja, aufjedenfall.

Ich bin echt immer und über jede Hilfe froh. Es ist als Hobbyprogrammierer nicht immer einfach, wenn man die Sachen alle erlesen muss. Das Thema Programmieren, ist ja schließlich kein kleines.

Also nochmal Danke.

Gruß Jens

haentschman 4. Okt 2009 20:10

Re: Exception richtig behandeln
 
Geht mir nicht anders, sich in etwas einzuarbeiten und auszuprobieren ist das zeitaufwändigste überhaupt.

einen schönen Sonntag noch :hi:

TheReaper 4. Okt 2009 21:11

Re: Exception richtig behandeln
 
Nur so als Hinweis: alle StrToXXX Konverter Funktionen können die selbe Exception werfen wie bei StrToDate. Dafür gibts immer die passende TryStrToXXX Funktion. :warn:

Jens Hartmann 5. Okt 2009 07:16

Re: Exception richtig behandeln
 
Zitat:

Zitat von TheReaper
Nur so als Hinweis: alle StrToXXX Konverter Funktionen können die selbe Exception werfen wie bei StrToDate. Dafür gibts immer die passende TryStrToXXX Funktion.

:thumb:

Danke für die Info. Ich denke, das ich das in alle meine Funktionen noch integrieren werde.

Gruß Jens

Jens Hartmann 8. Nov 2009 14:57

Re: Exception richtig behandeln
 
Hallo,

ich bin immer noch dabei meine Exceptionbehandlungen zu ergänzen. Ist es OK, wenn ich am Anfang meiner Funktion, in der verschiedene Fehler auftreten können, Umwandlungen von Zeit in String oder String in Integer etc. in einem großen gemeinsamen

Delphi-Quellcode:
try

except
Block packe. Und wäre es OK, wenn der
Delphi-Quellcode:
except
Teil dann leer ist. Wenn ich wie unten das so machen würde, dann wäre ja im except Block keine Anweisung notwendig, da ja der obere
Delphi-Quellcode:
try
Block komplett abgebrochen wird. Also denke ich brauche ich auch kein Rollback und so.

Delphi-Quellcode:
procedure TForm1.TreeViewResultMB100(ParserTreeViewMB100: TMyBaseParser);
var
  Daten : TOMBSerie;
begin
try
  QryMB100.Close;
  QryMB100.SQL.Text := 'INSERT INTO MB100'+
      '(LFDNR, DATUM, UHRZEIT, EREIGNIS, TEILNEHMER, BEREICH)'+
      'VALUES(:LfdNr,:Datum,:Uhrzeit,:Ereignis,:Teilnehmer,:Bereich)';

  QryMB100.ParamByName('Lfdnr').AsInteger := ParserTreeViewMB100.EntriesMB100[0].LfdNr;
  QryMB100.ParamByName('Datum').AsDate := StrToDate(ParserTreeViewMB100.EntriesMB100[0].Datum);
  QryMB100.ParamByName('Uhrzeit').AsTime := StrToTime(ParserTreeViewMB100.EntriesMB100[0].Uhrzeit);
  QryMB100.ParamByName('Ereignis').AsString := ParserTreeViewMB100.EntriesMB100[0].Ereignis;
  QryMB100.ParamByName('Teilnehmer').AsString := ParserTreeViewMB100.EntriesMB100[0].Teilnehmer;
  QryMB100.ParamByName('Bereich').AsString := ParserTreeViewMB100.EntriesMB100[0].Bereich;

  QryMB100.ExecSQL;
  ConSecurdat.Commit;

  QryMB100.Close;
  QryMB100.SQL.Text := 'Select Max(ID) As ID From MB100';
  QryMB100.Open;

  VST.BeginUpdate;
  Daten := TOMBSerie.Create;
  with Daten do
  begin
    Daten.ID := QryMB100.FieldByName('ID').AsInteger;
    Daten.LfdNr := ParserTreeViewMB100.EntriesMB100[0].LfdNr;

    Daten.Datum := ParserTreeViewMB100.EntriesMB100[0].Datum;
    Daten.Uhrzeit := ParserTreeViewMB100.EntriesMB100[0].Uhrzeit;

    Daten.Ereignis := ParserTreeViewMB100.EntriesMB100[0].Ereignis;

    Daten.Teilnehmer := ParserTreeViewMB100.EntriesMB100[0].Teilnehmer;

    Daten.Bereich := ParserTreeViewMB100.EntriesMB100[0].Bereich;
  end;
  VST.AddChild(nil, Daten);

  if VST.RootNodeCount >= 4001 then
          begin
            VST.DeleteNode(VST.GetFirst);
          end;
  VST.EndUpdate;
  VST.ScrollIntoView(VST.GetLast, true);

  QryMB100.Close;
  DataMB256plus := '';
except

end;
end;
Danke schon mal Gruss


Jens

jaenicke 8. Nov 2009 18:15

Re: Exception richtig behandeln
 
Ein leerer except-Block sieht aber komisch aus. Wie wäre es, wenn du den Benutzer darüber informierst, dass da etwas schief gegangen ist?

Das ist bei dir ein wenig so als ob bei einem Auto der Reifen überhitzt, der Bordcomputer das feststellt, aber trotzdem nur die Lüftungszufuhr verschließt, damit im Auto der Rauch nicht stört... (bis der Reifen platzt)

Jens Hartmann 8. Nov 2009 18:59

Re: Exception richtig behandeln
 
Das Problem, ist eigendlich das mich der Teil normalerweise nicht interesiert.

Sollte in dem
Delphi-Quellcode:
try
Block ein Exception auftreten, entsteht diese zu 99,9% bei einem RESET der Hardware, da der dann folgende 1.Datensatz unterumständen nicht Ordnungsgemäß ist. Das soll heißen, das bei 100000 Datensätzen, das eventuell das bei einem mal passieren kann.

Gut wenn eine unerwartet Exception auftritt, wäre es eventuell Sinnvoll. Dann müsste ich dies vieleicht in ein Fehlerprotokoll oder so schreiben.

Ist es den ansonsten OK, den
Delphi-Quellcode:
try except
Block über die gesamte Funktion zu legen.

MFG

Jens

jaenicke 8. Nov 2009 19:05

Re: Exception richtig behandeln
 
Ja, gut, wenn das normal ist, dass die Daten nicht immer korrekt analysiert werden können, dann braucht man das nicht anzeigen. Allerdings wäre es dann umso sinnvoller wie bereits angesprochen zuerst zu prüfen, ob die Daten valide sind bevor diese einfach eingetragen werden bzw. das versucht wird. Die Try... Funktionen wurden ja angesprochen und ich hatte gedacht du wolltest das auch entsprechend umbauen?

Zitat:

Zitat von Jens Hartmann
Ist es den ansonsten OK, den
Delphi-Quellcode:
try except
Block über die gesamte Funktion zu legen.

Ich würde es zumindest soweit trennen, dass ein Fehler beim Parsen ignoriert wird, ein Fehler beim Eintragen in die Datenbank z.B. aber vielleicht doch behandelt werden sollte (also in einem weiteren Exception-Block). Denn da sollte dann ja wohl keine Exception auftreten. Und wenn doch, könnte das ein Problem darstellen, oder?

Jens Hartmann 8. Nov 2009 19:13

Re: Exception richtig behandeln
 
Ja, das stimmt wohl. Ich werde das jetzt mal umschreiben und dann mal hier einstellen.

Danke erstmal

Gruß Jens

Jens Hartmann 7. Jan 2010 22:47

Re: Exception richtig behandeln
 
Hallo mal wieder zusammen, :chat:

ich will mal wieder ein altes Thema von mir aufleben lassen. Ich habe vor kurzer Zeit ein wenig an meinen Exceptionbehandlungen gearbeitet. Ich habe mich nochmal in das Thema eingelesen und einen Teil von meinem Programm angefangen auf meine Kenntnisse anzupassen. Da ich aber jetzt nicht unnötig arbeiten will und gerne mal Eure Meinung hören würde, wäre es schön wenn ihr mal kurz zu dem folgenden Code Eure Meinung sagen könnte. :idea:

Delphi-Quellcode:
{HTML in Datei speichern}
function THTMLExportForm.SaveHTML(HTMLFile : TStringlist):string;
begin
  if SaveDialog1.Execute then
    HTMLFile.SaveToFile(SaveDialog1.FileName);
    Result := SaveDialog1.FileName;
end;

{HTML-Datei für MB-Serie erstellen}
procedure THTMLExportForm.HTMLErzeugenMBSerie;
Var
  slHTML : TStringList;
  i : integer;
  mrResult: Integer;
  FileName : String;
begin
  try  //start try Block mit finally für HTML.Free
    try //start try Block Erstellung HTML
      slHTML := TStringList.Create;

      slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"');
      slHTML.Add('<html>');

      slHTML.Add('<head>');
      slHTML.Add('<link rel="stylesheet" type="text/css" href="MB.css"');
      slHTML.Add('<Style type="text/css"></style>');
      slHTML.Add('<title>Protokolldatei</title>');
      slHTML.Add('</head>');

      slHTML.Add('<body>');
      slHTML.Add('<img src= ".\Kopf1.bmp" width= "900" height= "150" align= "rigth" alt= "Titel" >');
      slHTML.Add('<h1 style="color:#FFFFFF; background-color:#000080; align= "right">Firma hartmann & uebach Nachrichtentechnik GmbH</h1>');
      slHTML.Add('<h1 style="color:#000080;">Objekt: '
                 +QryVorgabe.FieldByName('KUNDEOBJEKT').AsString+'</h1>');
      slHTML.Add('<table border="0" style="border-collapse:separate;"'+
                 'width="100%" style="'+
                 'border-left:5px solid #000080;border-right:5px solid #000080;'+
                 'border-top:5px solid #000080;border-bottom:5px solid #000080;>');
      slHTML.Add('<tr>');
      slHTML.Add('<th align="left">Protokolldatei vom '+DateTimeToStr(Now)+'</th>');
      slHTML.Add('<th align="left">ID</th>');
      slHTML.Add('<th align="left">LfdNr</th>');
      slHTML.Add('<th align="left">Datum</th>');
      slHTML.Add('<th align="left">Uhrzeit</th>');
      slHTML.Add('<th align="left">Ereignis</th>');
      slHTML.Add('<th align="left">Teilnehmer</th>');
      slHTML.Add('<th align="left">Bereich</th>');
      slHTML.Add('<tr>');
      for i := 0 to QryHTML.RecordCount -1 do
        begin
          slHTML.Add('<tr class="' + QryHTML.FieldByName('Ereignis').AsString + '">');
          slHTML.Add('<td>');
          slHTML.Add(IntToStr(QryHTML.FieldByName('ID').AsInteger));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(IntToStr(QryHTML.FieldByName('LfdNr').AsInteger));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(DateToStr(QryHTML.FieldByName('Datum').AsDateTime));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(TimeToStr(QryHTML.FieldByName('Uhrzeit').AsDateTime));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Ereignis').AsString);
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Teilnehmer').AsString);
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Bereich').AsString);
          slHTML.Add('</td>');
          slHTML.Add('</tr>');
          QryHTML.Next;
        end;
      slHTML.Add('</table>');
      slHTML.Add('</body>');
      slHTML.Add('</html>');
    except //Ende try Block Exceptionbehandlung Erstellung HTML
      ShowMessage('HTML Dokument konnte nicht erstellt werden');
    end;  //Ende try Block end Erstellen HTML
    try   //Start try Block Speichern
      FileName := SaveHTML(slHTML);
    except //Ende try Block Exceptionbehandlung Speichern
      ShowMessage('Datei konnte nicht gespeichert werden');
    end;  //Ende try Block end Speichern
    try   //Start try Block Datei Öffnen
      if AnzeigenCheckBox.Checked then
        ShellExecute(Application.Handle, 'open', PAnsiChar(FileName), nil, nil, SW_ShowNormal);
    except //Ende try Block Exceptionbehandlung Öffnen
      ShowMessage('Datei konnte nicht geöffnet werden');
    end;  //Ende try Block end Öffnen
    try   //Start try Block Datei EMail versenden
      if VersendenCheckBox.Checked then
        SendMail(FileName);
    except //Ende try Block Exceptionbehandlung EMail versenden
      ShowMessage('Datei konnte nicht als E-Mail versendet werden');
    end;  //Ende try Block end EMail versenden
    try   //Start try Block Datei Drucken
      if DruckenCheckBox.Checked then
        ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE);
    except //Ende try Block Exceptionbehandlung Drucken
      ShowMessage('Datei konnte nicht gedruckt werden');
    end;  //Ende try Block end Drucken
  finally //Ende try Block TStringlist über finally wieder freigeben
    slHTML.Free;
  end;    //Ende try Block finally
end;
Danke schon mal und Gruß

Jens

sx2008 8. Jan 2010 06:44

Re: Exception richtig behandeln
 
Folgender Code hat gleich drei Fehler:
Delphi-Quellcode:
try   //Start try Block Datei EMail versenden
  if VersendenCheckBox.Checked then
      SendMail(FileName);
except //Ende try Block Exceptionbehandlung EMail versenden
   ShowMessage('Datei konnte nicht als E-Mail versendet werden');
end;  //Ende try Block end EMail versenden
1.) Fehler
die ursprüngliche Exception-Meldung geht verloren.
Die Funktion SendMail() kann (wenn sie was taugt) wertvolle Hinweise gegeben, WESHALB die EMail nicht gesendet werden konnte.
Es wäre doch wirklich dumm, diese Information einfach so wegzuwerfen.

2.) Fehler
Verwendung von ShowMessage.
Wenn obiger Try..except Block innerhalb einer Schleife aufgerufen wird und es zum Fehler kommt,
dann viel Spass beim Wegklicken der Fehlermeldungen.
Oftmals bleibt nichts anderes übrig, als das Programm mit dem Taskmanager abzuschiesen.

3.) Fehler
Deine Kommentare sind nichts anderes als visuelles Störfeuer!
Es ist sinnlos und kontraproduktiv das Offensichtliche zu kommentieren.

Viel besser wäre:
Delphi-Quellcode:
try
  if VersendenCheckBox.Checked then
      SendMail(FileName);
except
  on E:Exception do
  begin
     Exception.Message := 'Datei konnte nicht als E-Mail versendet werden'#13#10+
       Exception.Message;
     raise;
  end;
end;

Jens Hartmann 8. Jan 2010 14:46

Re: Exception richtig behandeln
 
Zitat:

Zitat von sx2008
Folgender Code hat gleich drei Fehler:

Ich habe das mal geändert. Wäre das jetzt so OK. Hier jetzt mal mit den Funktionen "SendMail()" und "SaveHTML()"...
Delphi-Quellcode:
{HTML-Datei für MB-Serie erstellen}
procedure THTMLExportForm.HTMLErzeugenMBSerie;
Var
  slHTML : TStringList;
  i : integer;
  mrResult: Integer;
  FileName : String;
begin
  try
    try
      slHTML := TStringList.Create;

      slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"');
      slHTML.Add('<html>');

      slHTML.Add('<head>');
      slHTML.Add('<link rel="stylesheet" type="text/css" href="MB.css"');
      slHTML.Add('<Style type="text/css"></style>');
      slHTML.Add('<title>Protokolldatei</title>');
      slHTML.Add('</head>');

      slHTML.Add('<body>');
      slHTML.Add('<img src= ".\Kopf1.bmp" width= "900" height= "150" align= "rigth" alt= "Titel" >');
      slHTML.Add('<h1 style="color:#FFFFFF; background-color:#000080; align= "right">Firma hartmann & uebach Nachrichtentechnik GmbH</h1>');
      slHTML.Add('<h1 style="color:#000080;">Objekt: '
                 +QryVorgabe.FieldByName('KUNDEOBJEKT').AsString+'</h1>');
      slHTML.Add('<table border="0" style="border-collapse:separate;"'+
                 'width="100%" style="'+
                 'border-left:5px solid #000080;border-right:5px solid #000080;'+
                 'border-top:5px solid #000080;border-bottom:5px solid #000080;>');
      slHTML.Add('<tr>');
      slHTML.Add('<th align="left">Protokolldatei vom '+DateTimeToStr(Now)+'</th>');
      slHTML.Add('<th align="left">ID</th>');
      slHTML.Add('<th align="left">LfdNr</th>');
      slHTML.Add('<th align="left">Datum</th>');
      slHTML.Add('<th align="left">Uhrzeit</th>');
      slHTML.Add('<th align="left">Ereignis</th>');
      slHTML.Add('<th align="left">Teilnehmer</th>');
      slHTML.Add('<th align="left">Bereich</th>');
      slHTML.Add('<tr>');
      for i := 0 to QryHTML.RecordCount -1 do
        begin
          slHTML.Add('<tr class="' + QryHTML.FieldByName('Ereignis').AsString + '">');
          slHTML.Add('<td>');
          slHTML.Add(IntToStr(QryHTML.FieldByName('ID').AsInteger));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(IntToStr(QryHTML.FieldByName('LfdNr').AsInteger));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(DateToStr(QryHTML.FieldByName('Datum').AsDateTime));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(TimeToStr(QryHTML.FieldByName('Uhrzeit').AsDateTime));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Ereignis').AsString);
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Teilnehmer').AsString);
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Bereich').AsString);
          slHTML.Add('</td>');
          slHTML.Add('</tr>');
          QryHTML.Next;
        end;
      slHTML.Add('</table>');
      slHTML.Add('</body>');
      slHTML.Add('</html>');
    except
      on e : Exception do begin
        TForm1.Servicememo.Lines.Add(e.Message);
      raise;
      end;
    end;

    try
      FileName := SaveHTML(slHTML);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht gespeichert werden'#13#10+e.Message;
      raise;
      end;
    end;

    try
      if AnzeigenCheckBox.Checked then
        ShellExecute(Application.Handle, 'open', PAnsiChar(FileName), nil, nil, SW_ShowNormal);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht geöffnet werden'#13#10+e.Message;
      raise;
      end;
    end;

    try
      if VersendenCheckBox.Checked then
        SendMail(FileName);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht als E-Mail versendet werden'#13#10+e.Message;
      raise;
      end;
    end;

    try
      if DruckenCheckBox.Checked then
        ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht gedruckt werden'#13#10+e.Message;
      raise;
      end;
    end;

  finally
    slHTML.Free;
  end;
end;

{HTML in Datei speichern}
function THTMLExportForm.SaveHTML(HTMLFile : TStringlist):string;
begin
  if SaveDialog1.Execute then
    HTMLFile.SaveToFile(SaveDialog1.FileName);
    Result := SaveDialog1.FileName;
end;

{HTML-Datei als E-Mail versenden}
procedure THTMLExportForm.SendMail(HTMLFileName : String);
var
  Attachment : TStringList;
  i : integer;
begin
  try
    QryVorgabe.Close;
    QryVorgabe.SQL.Text := 'SELECT * FROM VORGABE';
    QryVorgabe.Open;
  except
    on e : Exception do
      begin
        e.Message := 'Datenbank konnte nicht geöffnet werden'#13#10+e.Message;
      raise;
    end;
  end;

  try
    Attachment := TStringList.Create;
    Attachment.Add(HTMLFileName);
    Attachment.Add('.\Kopf1.bmp');
      with mesgMessage do begin
        Clear;
        From.Text := QryVorgabe.FieldByName('EIGENE_E_MAIL').AsString;
        Recipients.Add.Text := AnEMailEdit.Text;
        Subject := BetreffEdit.Text;
        Body.Assign(EMailMemo.Lines);
          if FileExists(HTMLFileName) then
            begin
              if assigned(Attachment) then
                for i := 0 to Attachment.Count - 1 do
                  TIdAttachmentFile.Create(MessageParts, Attachment.Strings[i]);
            end
      end;

      with smtpSendMail do begin
        Username := QryVorgabe.FieldByName('BENUTZERNAME_E_MAIL').AsString;
        Password := QryVorgabe.FieldByName('PASSWORT_E_MAIL').AsString;
        Host := QryVorgabe.FieldByName('SMTP_SERVER').AsString;
        Connect;
      try
        Send(mesgMessage);
      finally
        Disconnect;
      end;
    end;
    showmessage('Mail wurde erfolgreich an folgende Adressen versendet.'+sLineBreak+sLineBreak+
                    'An:  '+AnEMailEdit.Text);
  finally
    Attachment.Free;
  end;
  QryVorgabe.Close;
end;
Kann ich dann eigendlcih auch einfach einen
Delphi-Quellcode:
try..except
Block für die gesamten Anweisung nehmen und das ganze dann so machen...

Delphi-Quellcode:
{HTML-Datei für MB-Serie erstellen}
procedure THTMLExportForm.HTMLErzeugenMBSerie;
Var
  slHTML : TStringList;
  i : integer;
  mrResult: Integer;
  FileName : String;
begin
  try
    try
      slHTML := TStringList.Create;

      slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"');
      slHTML.Add('<html>');
      ....
      ....
      if VersendenCheckBox.Checked then
        SendMail(FileName);
      ....
      ....
      if DruckenCheckBox.Checked then
        ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE);
    except
      on e : Exception do begin
        Memo1.Lines.Add := 'Fehler beim erstellen der Datei';
        Memo1.Lines.Add := 'Fehler aufgetreten: '+e.Message;
      if FehlerCheckBox.Cheched then
        raise; //Wenn CheckBox Fehleranzeigen aktiv, wird der Fehler angezeigt, ansonsten nur Eintrag im Memo
      end;
    end;

  finally
    slHTML.Free;
  end;
end;
Das müsste doch so auch gehen...

Gruß Jens

Luckie 8. Jan 2010 14:49

Re: Exception richtig behandeln
 
Zerleg deine Methode HTMLErzeugenMBSerie in mehrere einzelne. Schon die try-except-Blöcke zeigen, dass dies besser wäre. Dann kommst du auch mit den try-except-Blöcken nicht durcheinander.

Jens Hartmann 8. Jan 2010 15:03

Re: Exception richtig behandeln
 
Zitat:

Zitat von Luckie
Zerleg deine Methode HTMLErzeugenMBSerie in mehrere einzelne. Schon die try-except-Blöcke zeigen, dass dies besser wäre. Dann kommst du auch mit den try-except-Blöcken nicht durcheinander.

Aber was soll ich da noch zerlegen. Eigendlich habe ich die doch schon komplett Zerlegt.
Der Aufbau ist ja folgendermaßen..

Delphi-Quellcode:
Button.Click;
  //HTMLErzeugen wird aufgerufen

  //HTMLErzeugen erstellt die Datei aus einer Datenbank
 
  //und ruft anschließend die Funktionen

  //Drucken

  //Speichern

  //Senden

  //Öffnen

  //hintereinander auf.
Hinter diesen einzelnen Funktionen, zumindstend hinter Save und EMail sind ja schon Funktionen hinter verborgen. und Öffnen und Drucken sind ja nur ShellExecute Anweisungen.



Delphi-Quellcode:
{HTML-Datei für MB-Serie erstellen} 
procedure THTMLExportForm.HTMLErzeugenMBSerie;
Var
  slHTML : TStringList;
  i : integer;
  mrResult: Integer;
  FileName : String;
begin
  try
    try
      slHTML := TStringList.Create;

      slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"');
      slHTML.Add('<html>');

      slHTML.Add('<head>');
      slHTML.Add('<link rel="stylesheet" type="text/css" href="MB.css"');
      slHTML.Add('<Style type="text/css"></style>');
      slHTML.Add('<title>Protokolldatei</title>');
      slHTML.Add('</head>');

      slHTML.Add('<body>');
      slHTML.Add('<img src= ".\Kopf1.bmp" width= "900" height= "150" align= "rigth" alt= "Titel" >');
      slHTML.Add('<h1 style="color:#FFFFFF; background-color:#000080; align= "right">Firma hartmann & uebach Nachrichtentechnik GmbH</h1>');
      slHTML.Add('<h1 style="color:#000080;">Objekt: '
                 +QryVorgabe.FieldByName('KUNDEOBJEKT').AsString+'</h1>');
      slHTML.Add('<table border="0" style="border-collapse:separate;"'+ 
                 'width="100%" style="'+ 
                 'border-left:5px solid #000080;border-right:5px solid #000080;'+ 
                 'border-top:5px solid #000080;border-bottom:5px solid #000080;>');
      slHTML.Add('<tr>');
      slHTML.Add('<th align="left">Protokolldatei vom '+DateTimeToStr(Now)+'</th>');
      slHTML.Add('<th align="left">ID</th>');
      slHTML.Add('<th align="left">LfdNr</th>');
      slHTML.Add('<th align="left">Datum</th>');
      slHTML.Add('<th align="left">Uhrzeit</th>');
      slHTML.Add('<th align="left">Ereignis</th>');
      slHTML.Add('<th align="left">Teilnehmer</th>');
      slHTML.Add('<th align="left">Bereich</th>');
      slHTML.Add('<tr>');
      for i := 0 to QryHTML.RecordCount -1 do
        begin
          slHTML.Add('<tr class="' + QryHTML.FieldByName('Ereignis').AsString + '">');
          slHTML.Add('<td>');
          slHTML.Add(IntToStr(QryHTML.FieldByName('ID').AsInteger));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(IntToStr(QryHTML.FieldByName('LfdNr').AsInteger));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(DateToStr(QryHTML.FieldByName('Datum').AsDateTime));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(TimeToStr(QryHTML.FieldByName('Uhrzeit').AsDateTime));
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Ereignis').AsString);
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Teilnehmer').AsString);
          slHTML.Add('</td>');
          slHTML.Add('<td>');
          slHTML.Add(QryHTML.FieldByName('Bereich').AsString);
          slHTML.Add('</td>');
          slHTML.Add('</tr>');
          QryHTML.Next;
        end;
      slHTML.Add('</table>');
      slHTML.Add('</body>');
      slHTML.Add('</html>');
    except
      on e : Exception do begin
        TForm1.Servicememo.Lines.Add(e.Message);
      raise;
      end;
    end;

    try
      FileName := SaveHTML(slHTML);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht gespeichert werden'#13#10+e.Message;
      raise;
      end;
    end;

    try
      if AnzeigenCheckBox.Checked then
        ShellExecute(Application.Handle, 'open', PAnsiChar(FileName), nil, nil, SW_ShowNormal);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht geöffnet werden'#13#10+e.Message;
      raise;
      end;
    end;

    try
      if VersendenCheckBox.Checked then
        SendMail(FileName);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht als E-Mail versendet werden'#13#10+e.Message;
      raise;
      end;
    end;

    try
      if DruckenCheckBox.Checked then
        ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE);
    except
      on e : Exception do begin
        e.Message := 'Datei konnte nicht gedruckt werden'#13#10+e.Message;
      raise;
      end;
    end;

  finally
    slHTML.Free;
  end;
end;

Luckie 8. Jan 2010 15:12

Re: Exception richtig behandeln
 
So wie du das machst führst du die Strukturierteausnahmebehandlung ad absurdum. Normalerweise geht es so:
Delphi-Quellcode:
try
  Anweisung;
  Anweisung;
  Anweisung;
  Anweisung;
  Anweisung;
  Anweisung;
except
  Fehlerbehandlung;
end;
Lösung für dich: Deklarier dir eigene Exceptions, die in den Unterfunktionen geworfen werden:
ESaveError, ELoadError, ESendMailError, ...
Und dann:

Delphi-Quellcode:
try
  FileName := SaveHTML(slHTML);
  SendMail(FileName);
  ...;
except
  on E: ESaveError do
    ...;
  on E: EOpenError do
    ...;
end;
ShellExecute wirft übrigens keine Exceptions, da es eine Windows API-Funktion ist. ShellExecute liefert einen Fehlercode zurück.

Luckie 8. Jan 2010 15:27

Re: Exception richtig behandeln
 
Code-Beispiel:
Delphi-Quellcode:
program Project3;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  EDoSomething = class(Exception)

  end;

  EDoSomeMore = class(Exception)

  end;

procedure DoSomething;
begin
  raise EDoSomething.Create('Fehler in DoSomething');
end;

procedure DoSomeMore;
begin
  raise EDoSomeMore.Create('Fehler in DoSomeMore');
end;

begin
  try
    DoSomething;
    DoSomeMore;
  except
    on E: EDoSomething do
      Writeln(E.Message);
    on E: EDoSomeMore do
      Writeln(E.Message);
        // alle anderen Exceptions
    on E: Exception do
      Writeln(E.Message);
  end;
  Readln;
end.

Jens Hartmann 8. Jan 2010 15:52

Re: Exception richtig behandeln
 
Hallo Michael,

das mit den einzelnen Exception Behandlungen habe ich verstanden. Gute Sache, da wäre ich nie darauf gekommen das so zu machen. Vorallem kann ich ja auch so die einzelnen Behandlungen eventuell noch in USER-Verständliche Sprache in denn jeweiligen Exception übersetzen.

Allerdings, verstehe ich eine Sache nicht so ganz.

Was machen die letzten Zeilen :gruebel:
Delphi-Quellcode:
    on E: Exception do
      Writeln(E.Message);
  end;
  Readln;
end.
Zitat:

Zitat von Luckie
ShellExecute wirft übrigens keine Exceptions, da es eine Windows API-Funktion ist. ShellExecute liefert einen Fehlercode zurück.

Und wie werden solche Sachen behandelt. Macht das die Windows API schon allein.

Ansonsten danke, coole Idee. Werde das nach dem umsetzen aufjedenfall nochmal hier einstellen.

Gruß Jens

Luckie 8. Jan 2010 15:57

Re: Exception richtig behandeln
 
Steh doch im Kommentar: Sie fängt alle anderen Exceptions ab, die auftreten können. Können keine auftreten, kann das weggelassen werden.

Manche Exceptions musst du nicht neu definieren. Du kannst auch welche nehmen, die schon definiert sind un der SysUtils.pas.

Mit meiner Lösung wirst du die ganzen Exception Blöcke los und die Exceptions werden da geworfen, wo sie auch auftreten.

Jens Hartmann 8. Jan 2010 16:03

Re: Exception richtig behandeln
 
Sorry,

ich versteh eigendlich nur den Sinn von

Delphi-Quellcode:
  end;
  Readln;
end.
Gruß Jens

Luckie 8. Jan 2010 16:08

Re: Exception richtig behandeln
 
Ach so. Das Readln wartet auf eine Eingabe. Dann geht die Konsole nicht gleich zu, wenn man das Programm aus dem Explorer startet. Ist nur da, damit man noch die Ausgabe sieht.


Zitat:

Zitat von Jens Hartmann
Zitat:

Zitat von Luckie
ShellExecute wirft übrigens keine Exceptions, da es eine Windows API-Funktion ist. ShellExecute liefert einen Fehlercode zurück.

Und wie werden solche Sachen behandelt. Macht das die Windows API schon allein.

Den Rückgabewert abfragen. Ich würde das auch in eine Methode kapseln, den Rückgabewert mit if-Abfragen und im Fehlerfall eine Exception werfen mit dem entsprechen Fehlertext: http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx

Jens Hartmann 8. Jan 2010 16:18

Re: Exception richtig behandeln
 
Danke Michael, :thumb:

jetzt kann ich Arbeiten. Ich habe das jetzt verstanden. :idea:

Zitat:

Zitat von Luckie
Dann geht die Konsole nicht gleich zu

Sorry, hatte nicht gesehen, das es eine Konsolen Anwendung war. Sonst wäre mir das klar gewesen.

Gruß Jens

Luckie 8. Jan 2010 16:23

Re: Exception richtig behandeln
 
Natürlich kannst du die eigenen Exception-Klassen jetzt noch mit eigenen Methoden ergänzen -- ganz nach deinem Bedürfnissen.


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