Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Unrealistischster Fehler aller Zeiten. (https://www.delphipraxis.net/37572-unrealistischster-fehler-aller-zeiten.html)

Sascha L 7. Jan 2005 13:23


Unrealistischster Fehler aller Zeiten.
 
Hallo,

ich habe folgenden Code (er ist erstmal nur zum Testen, daher ist er noch nicht mit try-Anweisungen, etc. optimiert worden):

Delphi-Quellcode:
procedure TForm1.MailsAbrufen;
var
//Integers
intIndex,i:integer;
begin
  try
  idPOP31.Connect;
  except
  MessageDlg('Es konnte keine Verbindung zum Postfach hergestellt werden. Bitte überprüfen Sie alle Einstellungen.',mtInformation,[mbOk],0);
  end;
  MailCount := idPOP31.CheckMessages;
  idPOP31.Retrieve(1,idMessage1);
 
  anhang_list := TStringList.Create;
  anhang_id_list := TStringList.Create;
  anhang_list_stream := TMemoryStream.Create;
  anhang_id_list_stream := TMemoryStream.Create;
 
  IBTable2.Last;
  ID2 := IBTable2.RecordCount;
  // Inhalt der Mail überprüfen
    if IdMessage1.MessageParts.Count <> 0 then begin
      for intIndex := 0 to (IdMessage1.MessageParts.Count-1) do begin
        if idMEssage1.MessageParts.Items[intIndex] is TIdText then begin
        mailBody := TidText(IdMessage1.MessageParts.Items[intIndex]).Body.Text;
        end
        else if idMEssage1.MessageParts.Items[intIndex] is TIdAttachmentFile then begin
        attFileName := (idMEssage1.MessageParts.Items[intIndex] as tIdAttachmentFile).Filename;
        TidAttachmentFile(idMessage1.MessageParts.Items[intIndex]).SaveToFile(path+'\tmp\'+attFileName);
        ID2 := ID2+1;
        anhang_id_list.Add(IntToStr(ID2));
        anhang_list.Add(attFileName);
        end;
      end;
    end
    else if IdMessage1.MessageParts.Count = 0 then begin
    MailBody := idMessage1.Body.Text;
    end;
     if anhang_list.Text <> '' then begin
     anhang_list.SaveToStream(anhang_list_stream);
     anhang_id_list.SaveToStream(anhang_id_list_stream);
     end;
  id1 := IBTable1.RecordCount+1;
  mailHeader := idMessage1.Headers.Text;
  mailSubject := idMessage1.Subject;
  mailDate := idMessage1.Date;
  mailFromName := idMessage1.From.Name;
  mailFromMail := idMessage1.From.Address;
  // Mails in die Datenbank speichern
  Mails2DB;
  // Alles wieder freigeben
  FreeAndNil(anhang_list);
  FreeAndNil(anhang_id_list);
  FreeAndNil(anhang_list_stream);
  FreeAndNil(anhang_id_list_stream);
  // Verbindung zum Server trennen
  idPOP31.Disconnect;
end;
//------------------------------------------------------------------------------
procedure TForm1.Mails2DB;
var
i:integer;
begin
  try
  // 1. Tabelle
  IBTable1.Insert;
  IBTable1.FieldByName('Message').AsString := mailBody;
  IBTable1.FieldByName('MSGID').AsInteger := id1;
  IBTable1.FieldByName('Header').AsString := mailHeader;
  IBTable1.FieldByName('Subject').AsString := mailSubject;
  IBTable1.FieldByName('Date').AsString := FormatDateTime('ddd, dd.mm.yyyy hh:mm', mailDate);
  IBTable1.FieldByName('FromName').AsString := mailFromName;
  IBTable1.FieldByName('FromMail').AsString := mailFromMail;
    if anhang_list.Text <> '' then begin
    anhang_list_stream.Position := 0;
    anhang_id_list_stream.Position := 0;
    Pic2DB.StoreStreamInDB(TBlobField(IBTable1.FieldByName('Anhang')),anhang_list_stream);
    Pic2DB.StoreStreamInDB(TBlobField(IBTable1.FieldByName('AID')),anhang_id_list_stream);
    IBTable1.FieldByName('AttIcon').AsInteger := 1;
    end;
  IBTable1.Post;
  // 2. Tabelle
   if anhang_list.count <> 0 then begin
    for i:=0 to anhang_list.Count-1 do begin
    IBTAble2.Insert;
    Pic2DB.StoreFileInDB(TBlobField(IBTable2.FieldByName('FILE')),path+'\tmp\'+anhang_list.Strings[i]);
    IBTable2.FieldByName('ID').AsInteger := StrToInt(anhang_id_list.Strings[i]);
    IBTable2.Post;
    end;
    end;
  // Ende
    mailsaved := true;
  except
    mailsaved := false;
  end;
end;
Das merkwürdige ist folgendes:

anhang_id_list ist leer. Das kann aber nicht. Wenn ich "Mails2DB" weglasse und an der Stelle den Inhalt von anhang_id_list in ein Memo lade, dann stehen dort 2 Zahlen (bei meiner Testmail), alle anderen Variablen sind auch ausgefüllt und die Schleife beim Anhang durchläuft er auch, da die Dateien im TMP-Ordner angelegt werden. Wenn ich aber die Prozedur "Mails2DB" verwende, sind anhang_id_list und anhang_id_list_stream wieder leer.

Ich versteh es einfach nicht und ein debuggen hat auch nichts gebracht.

Viele Grüße
Sascha

Sascha L 7. Jan 2005 15:12

Re: Unrealistischster Fehler aller Zeiten.
 
wenn die Werte von anhang_id_list und anhang_id_list_stream in 2 neue Variablen schreibe und diese dann in die DB schreiben lasse, geht es komischerweise.

Das ist doch völlig unlogisch!

Selbst bei der Prozedur "Mails2DB" hat er der Inhalt von anhang_id_list_stream, aber bei der if-Schleife ist der Stream leer. Wenn ich aber in der Prozedur vor der if-Schleife den Inhalt des Streams in einen anderen Stream schreibe, dann geht es und wenn ich dann den neuen Stream angebe, schreibt er auch etwas in die DB.

Ist das ein Bug des Compilers??

S - tefano 7. Jan 2005 15:31

Re: Unrealistischster Fehler aller Zeiten.
 
Das kann schlichtweg daran liegen, wie die Indys entwickelt sind.
Wenn ich in meinem FTPClient mit idFTP mir ein Verzeichnislisting geben lasse, geht das nur ein Mal und danach ist es wieder leer. Muss ich also auch auslagern...
"Damals" bei der ioresult-Variable war das auch so. Einmal auslesen, danach wieder auf 0.
Also würd ich sagen: It's not a bug, it's a feature ;-)

Sascha L 7. Jan 2005 16:22

Re: Unrealistischster Fehler aller Zeiten.
 
nein, TMemoryStream ist nicht von Indy und hat daher nichts damit zu tun. Wenn eine Variable vom Typ Tmemorystream einen Wert hat, dann hat sie ihn.

Außerdem, wie eben erwähnt, ist der Inhalt ja bis zu if-Schleife vorhanden. Erst dann ist er wieder weg.

SirThornberry 7. Jan 2005 16:38

Re: Unrealistischster Fehler aller Zeiten.
 
Irgendwo ist das ganze fürn Ar***.
Hier mal der erste teil deines Quelltextes.
Delphi-Quellcode:
procedure TForm1.MailsAbrufen;
var
//Integers
intIndex,i:integer;
begin
  try
  idPOP31.Connect;
  except
  MessageDlg('Es konnte keine Verbindung zum Postfach hergestellt werden. Bitte überprüfen Sie alle Einstellungen.',mtInformation,[mbOk],0);
  end;
  MailCount := idPOP31.CheckMessages;
  idPOP31.Retrieve(1,idMessage1);
[...]
Wenn also das Connect fehl schlägt kommt eine Meldung und anschließend wird trotzdem versucht die nachrichten abzurufen :roteyes: Wie soll das gehen? Wenn keine Verbindung hergestellt werden kann so können auch keine Nachrichten abgerufen werden.

[OT]
Laut Delphistandard heißt es auch nicht
Delphi-Quellcode:
for [...] do begin
  //Anweisungen
end;

if [...] then begin
  //Anweisungen
end;
sondern
Delphi-Quellcode:
for [...] do
begin
  //Anweisungen
end;

if [...] then
begin
  //Anweisungen
end;
So sieht man wenigstens auf anhieb wo das end dazu gehört (denn zu einem "for" oder "if" gehört nicht zwingend ein "end" und es ist nicht grad schön zu lesen wenn ich immer erst das ende der zeile suchen muss (eventuell sogar scrollen) um zu wissen ob ein "begin" zur anweisung gehört oder ob es eine einzilge Anweisung ist
[/OT]

wo liegt eigentlich der Sinn von
Delphi-Quellcode:
if IdMessage1.MessageParts.Count <> 0 then //<==
begin
  for intIndex := 0 to (IdMessage1.MessageParts.Count-1) do
  begin
    if idMEssage1.MessageParts.Items[intIndex] is TIdText then
    begin //bei Einzelanweisungen ist "begin end" überflüssig
      mailBody := TidText(IdMessage1.MessageParts.Items[intIndex]).Body.Text;
    end
    else if idMEssage1.MessageParts.Items[intIndex] is TIdAttachmentFile then
    begin
      attFileName := (idMEssage1.MessageParts.Items[intIndex] as tIdAttachmentFile).Filename;
      TidAttachmentFile(idMessage1.MessageParts.Items[intIndex]).SaveToFile(path+'\tmp\'+attFileName);
      ID2 := ID2+1;
      anhang_id_list.Add(IntToStr(ID2));
      anhang_list.Add(attFileName);
    end;
  end;
end
else if IdMessage1.MessageParts.Count = 0 then //<==
begin //bei Einzelanweisungen ist "begin end" überflüssig
  MailBody := idMessage1.Body.Text;
end;
Wenn do oben auf ungleich 0 prüfst musst du unten kein "else if gleich 0" machen, da reicht auch ein einfaches else (sorry das ich den source bei dem beispiel mal bissl anders formatiert hab, aber sonst sieht man überhaupt ni durch was wozu gehört)

Sascha L 7. Jan 2005 17:05

Re: Unrealistischster Fehler aller Zeiten.
 
ich habe doch gesagt, dass ich das nur zum testen auf die schnelle gemacht habe und die feinoptimierung noch kommt.

für mich ist "if ... then begin" identisch mit

"if ... then
begin"

Diese Dinge haben nichts mit dem Fehler zu tun, ebenso die Sache mit "else" ;)

SirThornberry 7. Jan 2005 17:11

Re: Unrealistischster Fehler aller Zeiten.
 
ist schon klar das dies nix mit dem Fehler zu tun hat, es ist eben nur aufwendig wenn man erst deinen source kopieren muss und ordentlich einrücken weil
Delphi-Quellcode:
        else if idMEssage1.MessageParts.Items[intIndex] is TIdAttachmentFile then begin
        attFileName := (idMEssage1.MessageParts.Items[intIndex] as tIdAttachmentFile).Filename;
        TidAttachmentFile(idMessage1.MessageParts.Items[intIndex]).SaveToFile(path+'\tmp\'+attFileName);
        ID2 := ID2+1;
        anhang_id_list.Add(IntToStr(ID2));
        anhang_list.Add(attFileName);
        end;
gar keine Einrückung hat (eigentlich wir das zwischen begin und end eingerückt).

Zum Fehler. Woher weißt du das in dem Stream nix drin steht? Durch den Debugger?
Wenn du vor
Delphi-Quellcode:
Pic2DB.StoreStreamInDB(TBlobField(IBTable1.FieldByName('AID')),anhang_id_list_stream);
ein
Delphi-Quellcode:
anhang_id_list_stream.SaveToFile(YourFilename);
einfügst ist die datei dann auch leer? Wenn nicht würde ich einfach drauf tippen das deine "Pic2DB" einen fehler hat oder der cast "TBlobFiled(IBTable1.FiledByName('AID'))" fehl schlägt.

Sascha L 8. Jan 2005 11:25

Re: Unrealistischster Fehler aller Zeiten.
 
Der Fehler: Listenindex überschreibt das Maximum von (0).

der Fehler passiert hier:

Delphi-Quellcode:
if anhang_list.count <> 0 then begin
    for i:=0 to anhang_list.Count-1 do begin
    IBTAble2.Insert;
    Pic2DB.StoreFileInDB(TBlobField(IBTable2.FieldByName('FILE')),path+'\tmp\'+anhang_list.Strings[i]);
    IBTable2.FieldByName('ID').AsInteger := StrToInt(anhang_id_list.Strings[i]);
    IBTable2.Post;
    end;
    end;
Vor der if-Schleife ist der Stream noch voll, weil ich Ihn testweise in ein Memo geladen habe. In der if-Schleife ist er leer. Ebenfalls mit einem Memo getestet.

An der Pic2DB-Komponente liegt es nicht, weil sie sonst einwandfrei funktioniert und das merkwürdige ist ja, dass ich nun vor der if-schleife einen 2. Stream erstelle und den Inhalt von anhang_id_list_stream dort hineinlade und diesen dann bei Pic2DB angebe. So klappt es merkwürdigerweise. Aber das ist doch unlogisch oder nicht? Ein Stream kann sich doch nicht, ohne Grund, innerhalb einer if-Schleife leeren.

Gruß
Sascha

EDIT:

Ich habe nun auch noch festellen dürfen (komischerweise klappte es die ganze Zeit), dass mein Programm hier abstürzt:

FreeAndNil(anhang_id_list_stream);

Erstellt wurde der Stream ja... d.h. er muss irgendwo vernichtet werden. Aber warum?? Ich habe nirgendswo stehen, dass er den Stream vernichten soll, außer an der einen Stelle, aber da wurde er komischerweise schon vorher vernichtet.


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