![]() |
Access Violation 30 Sek. nach letzter Anweisung?
Hallo,
Ich habe einen Fehler in einem Programm, und zwar handelt es sich um eine Access Violation, an sich keine große Sache aber der Zeitpunkt an dem der Fehler auftritt schon :( Also hier ist der Code den ich zum einlesen einer durch Semikolons getrennten Datei benutze:
Delphi-Quellcode:
Also die Access Violation tritt auf nachdem der letzte Schritt dieser Anweisungsfolge durchgeführt wurde. Aber jetzt kommt der Haken, ersten ca 30-40 Sekunden nachdem
procedure THauptfenster.mOpenClick(Sender: TObject);
Var Dateiname : string; begin if Datenmodul.OpenDialog.Execute then begin Dateiname := Datenmodul.OpenDialog.Filename; if (Dateiname <> '') then begin if FileExists(Dateiname) then begin try ImportDatei := TStringlist.Create; Datenmodul.Dateilesen(Dateiname, ImportDatei); StatusBar.Panels[1].Text := ExtractFilename(Dateiname); StatusBar.Panels[1].Text := ' ' + Dateiname + ' ' + IntToStr(ImportDatei.Count) + ' Sätze'; Z_S_AEN:=0; Z_S_NEU:=0; application.ProcessMessages; screen.Cursor:=crhourglass; Datenmodul.Datenaufbereiten(ImportDatei, ';', StatusBar.Panels[1]); if StatusBar.Panels[1].enabled = false then StatusBar.Panels[1].enabled:= true; StatusBar.Panels[0].Text := ''; screen.Cursor:=crdefault; statusbar.Panels[1].text:= 'neu - geändert (S / R / A / B / P ) ' + inttostr(Z_S_NEU) + '-' + inttostr(Z_S_AEN) + '/ '; except showmessage ('Fehler ????'); end; end; end; end; end;
Delphi-Quellcode:
ausgeführt wurde, ich bin wirklich am verzweifeln :wall:
statusbar.Panels[1].text:= 'neu - geändert (S / R / A / B / P ) '
+ inttostr(Z_S_NEU) + '-' + inttostr(Z_S_AEN) + '/ '; Habe mir die Nummern Notiert welche mir ausgegeben wurden als die Fehlermeldung auftrat: Access Violation at 0x11d6e54e at Adress 0x0337a391 vielleicht kann ja jemand was damit anfangen oder mir erklären was ich damit anfangen könnte ;) Sorry das der Code so verunstaltet ist, wird automatisch hier eingerückt :( Schonmal danke für eure Antworten. mfg Alex |
Re: Access Violation 30 Sek. nach letzter Anweisung?
-Du gibst die Stringliste nicht mehr frei
-
Delphi-Quellcode:
ist so überflüssig, da ja sofort wieder überschreiben wird
StatusBar.Panels[1].Text := ExtractFilename(Dateiname);
-Was macht Datenaufbereiten()? |
Re: Access Violation 30 Sek. nach letzter Anweisung?
Also hab die StringList freigegeben, hat aber nichts genützt.
Datenaufbereiten:
Delphi-Quellcode:
dazu noch Datentrennen:
procedure Datenaufbereiten(ParamListe : TStringlist; ParamTrenner : string; ParamPanel : TVisiStatusPanel);
var Zaehler : Integer; Feldliste : TStringlist; Datenliste : TStringlist; AktFeld : Integer; begin (* Erzeugung einer Stringlist fuer die Speicherung der Feldangaben *) Feldliste := TStringlist.Create; (* Erzeugung einer Stringlist fuer die Zwischenspeicherung der Dateninhalte einer Textzeile *) Datenliste := TStringlist.Create; (* Schliessen der temporaeren Tabelle *) DataModule1.TempDaten.Active := false; (* Wenn die uebergebene Liste, die alle Textzeilen der Textdatei enthaelt, existiert, dann... *) if ParamListe <> nil then begin (* Wenn die uebergebene Liste auch wirklich Zeilen hat, dann... *) if ParamListe.Count > 0 then begin (* ... wird als erstes die Datenstruktur der temporaeren Tabelle aufgebaut. Dazu *) (* werden die Feldbeschreibungen (FieldDefs) zunaechst geloescht. *) DataModule1.TempDaten.FieldDefs.Clear; (* Die erste Zeile (ACHTUNG: Indexwert 0) wird in ihre Bestandteile (Feldanga-) *) (* aufgespalten. Der Feldtrenner wird dabei an die Prozedur DatenTrennen durch- *) (* gereicht. *) DatenTrennen(ParamListe.Strings[0], ParamTrenner, FeldListe); (* Der Einfachheit halber, werden in der temporaeren Tabelle nur Felder vom Da- *) (* tentyp String und einer Dimension von 30 Zeichen angelegt. Mittels FOR- *) (* Schleife wird die Feldliste vom ersten bis zum letzten Eintrag abgearbeitet. *) (* Wiederum ist zu beachten, dass der Index mit 0 und nicht mit 1 beginnt. *) for Zaehler := 0 to Feldliste.Count - 1 do begin (* With-Konstrukt vereinfacht die Angabe von Eigenschaften. *) with DataModule1.TempDaten Do begin (* Mit der Methode IndexOf wird geprueft, ob in den FieldDefs schon ein *) (* Feld mit dem aktuellen Feldnamen existiert. Ein Feldname darf nicht *) (* doppelt vergeben werden. Wenn die Moeglichkeit besteht, dass ein Feld *) (* mehrfach benoetigt wird, muesste in einem Else-Zweig ein Ersatzkon- *) (* strukt gebildet werden, das evtl. mit einem laufenden Zaehler zur Un- *) (* scheidung der Felder beitraegt. In diesem Beispiel wird darauf jedoch *) (* verzichtet. *) if FieldDefs.IndexOf(AnsiUpperCase(Feldliste.Strings[Zaehler])) < 0 then FieldDefs.Add(AnsiUpperCase(Feldliste.Strings[Zaehler]), ftString, 30, False); end; end; (* Die Tabelle Land, die fuer die Demonstration eines Lookup-Feldes in der Tabelle *) (* TempDaten benoetigt wird, muss vor der eigentlichen Tabelle geoeffnet werden. *) DataModule1.Land.Active := true; (* Oeffnen der temporaeren Tabelle namens TempDaten. Ueber einen Editor ist ein *) (* Lookup- und ein CalcField angelegt worden. *) DataModule1.TempDaten.Active := true; (* Die Datenzeilen aus der uebergebenen Stringlist werden verarbeitet. Da die Da- *) (* ten ab der zweiten Zeile angenommen werden, ist als Startwert fuer die FOR- *) (* Schleife auf 1 zu setzen (entspricht dem 2. Element der Liste!). *) for Zaehler := 1 to ParamListe.Count - 1 do begin (* Die Prozedur DatenTrennen kann fuer die Datenzeilen auch verwendet werden, weil *) (* fuer die Funktionalitaet unerheblich ist, ob es sich um die erste Zeile mit der *) (* Feldbeschreibung handelt oder eine der nachfolgenden Datenzeilen. Alle Zeilen *) (* enthalten schliesslich einzelne Elemente, die mit einem Trennzeichen (z.B. Se- *) (* mikolon) voneinander getrennt sind. Uebergeben wird hier jedoch eine zweite *) (* Stringlist, die fuer die Zwischenspeicherung der Daten vorbehalten ist. *) DatenTrennen(ParamListe.Strings[Zaehler], ParamTrenner, Datenliste); (* Wenn die Anzahl der Feldbeschreibungen mit der Anzahl der gefundenen Daten- *) (* elemente uebereinstimmt, ist die Wahrscheinlichkeit gross, dass die Struktur in *) (* Ordnung ist. Bei einer Abweichung muss sind entweder zu viele oder zu wenige *) (* Informationen in der Datenzeile. Ursache kann eine "missbraeuchliche" Nutzung *) (* des Trennzeichens sein. Das kann vor allem bei einem Komma als Trennzeichen *) (* auftreten sofern bei Gleitkommazahlen auch ein Komma uebergeben wird. *) if Feldliste.Count = Datenliste.Count then begin (* Datensatz in der temporaeren Tabelle anfuegen und in den Editiermodus schalten. *) (* Die Append-Methode sorgt fuer beides, so dass die Edit-Methode nicht aufgerufen *) (* wird. *) DataModule1.TempDaten.Append; (* Mit einer FOR-Schleife koennen alle Felder durchlaufen werden *) For AktFeld := 0 to Datenliste.Count - 1 do begin with DataModule1.TempDaten Do begin (* Fieldbyname-Methode zum Ansprechen eines Datenfeldes mit dem in der *) (* Stringlist gespeicherten Feldnamen. Da die Reihenfolge der Feld- und *) (* Datenzeile identisch sein soll, kann die Zuordnung des Inhalts ein- *) (* fach ueber den Index erfolgen. *) Fieldbyname(Feldliste.Strings[AktFeld]).Asstring := Datenliste.Strings[AktFeld]; end; end; (* Nach der Zuweisung aller Daten kann der Datensatz gespeichert werden. Dieses *) (* geschieht mit der Post-Methode der Tabelle. *) DataModule1.TempDaten.Post; end; (* Pruefung, ob ein Statusbar-Panel uebergeben wurde. Soll der Fortschritt nicht *) (* angezeigt werden, reicht es aus, der Prozedur anstelle des Objekts den Wert NIL *) (* mitzugeben also z.B. Datenaufbereiten(Datenliste; ';', nil). *) if ParamPanel <> nil then begin (* Panel sichtbar machen *) ParamPanel.Enabled := true; (* GaugeAttrs nutzbar, wenn das Panel vom Typ skGauge ist. Die Eigenschaft Po- *) (* sition gibt den Wert an, den der Fortschrittsbalken erhalten soll. In diesem *) (* Fall wird eine prozentuale Darstellung gewaehlt. Die mathematische Funktion *) (* DIV wird zur Division genutzt, weil so ein ganzzahliger Wert ermittelt wird, *) (* wie es von der Eigenschaft verlangt wird. Diese Funktion wird gerne gemein- *) (* sam mit der Funktion MOD gelehrt. Sie fuehrt ebenfalls eine Division durch, *) (* gibt dann aber den ganzzahligen Rest zurueck. *) (* Beispiele: *) (* 5 / 2 = 2.5, 5 DIV 2 = 2, 5 MOD 2 = 1 *) (* 10 / 2 = 5 , 10 DIV 2 = 5, 10 MOD 2 = 0 *) ParamPanel.GaugeAttrs.Position := Zaehler * 100 div (ParamListe.Count - 1); (* Mit ProcessMessages wird eine Windows-Message abgesendet, deren Konsequenz *) (* ein Refresh der Anwendung ist. *) Application.ProcessMessages; end; end; (* Panel unsichtbar machen *) if ParamPanel <> nil then ParamPanel.Enabled := false; end; end; (* den Speicher der Stringlisten wieder freigeben und die Objekte eliminieren *) FreeAndNil(Datenliste); FreeAndNil(FeldListe); end;
Delphi-Quellcode:
Hoffe das hilft dir weiter, ich kann einfach keinen Fehler finden da die Prozeduren auch in anderen Programmen zum Einsatz kommen glaube ich auch nicht das hier der Fehler liegt.
procedure Datentrennen(ParamZeile, ParamTrenner : string; Var ParamListe : TStringlist);
var TrennPos : integer; StartPos : integer; Zaehler : integer; MyMsg : string; begin (* Uebergebene TStringlist wird geleert *) ParamListe.Clear; (* Ausgangswert fuer die Suche des Trennzeichens innerhalb der Zeichenkette. Die Funktion *) (* PosEx (Unit StrUtils) unterstuetzt im Gegensatz zur Funktion Pos die Suche einer *) (* Zeichenfolge ab einer definierten Position. Zunaechst soll ab der 1. Stelle gesucht *) (* werden. *) StartPos := 1; (* TrennPos nimmt den Rueckgabewert von PosEx áuf und stellt die Position der gesuchten *) (* Zeichenkette dar. *) TrennPos := PosEx(ParamTrenner, ParamZeile, StartPos); (* Sofern ein Trennzeichen gefunden wurde... *) while (TrennPos > 0) do begin (* ... wird mit der Funktion Copy ab dem Ausgangswert bis zum Trennzeichen eine Zeichen- *) (* kette herauskopiert und der Stringlist angefuegt. *) Paramliste.Add (COPY(ParamZeile, StartPos, TrennPos - StartPos)); (* Um zu pruefen, ob ein weiteres Trennzeichen in der Zeichenkette vorkommt, wird der *) (* Ausgangswert erhoeht. Dabei wird zu der Position des zuletzt gefundenen Trennzeichens *) (* der Wert 1 addiert. *) StartPos := TrennPos + 1; TrennPos := PosEx(ParamTrenner, ParamZeile, StartPos); end; (* Zeichenkette fuer die Ausgabe der Stringlist wird mit einem Leerstring initialisiert *) MyMsg := ''; (* In die Zeichenkette werden alle Elemente der Stringlist eingefuegt. Fuer eine uebersicht- *) (* liche Darstellung wird nach jedem Element jeweils ein Zeilenumbruch (englisch Carriage *) (* Return [CR]) angefuegt, der im ASCII-Zeichensatz mit dem Wert 13 definiert ist. *) for Zaehler := 0 to ParamListe.Count -1 do begin MyMsg := MyMsg + ParamListe.Strings[Zaehler] + #13; end; (* Ausgabe der Stringlist in einer Messagebox *) //showmessage(MyMsg); end; mfg Alex |
Re: Access Violation 30 Sek. nach letzter Anweisung?
/offtopic
Du weisst schon, dass man mit // eine ganze Zeile auskommentieren kann? Man muss dafür nicht das hässliche (* ... *) nehmen. |
Re: Access Violation 30 Sek. nach letzter Anweisung?
Der Code geht ja in den Kommentaren unter. :shock: Man sollte so wenig wie möglich kommentieren, aber so viel wie nötig.
Und so ein Kommentar:
Delphi-Quellcode:
ist überflüssig. dass die Feldbschreibunge gelöscht werden, sieht man doch an der Codezeile selber.
(* ... wird als erstes die Datenstruktur der temporaeren Tabelle aufgebaut. Dazu *)
(* werden die Feldbeschreibungen (FieldDefs) zunaechst geloescht. *) DataModule1.TempDaten.FieldDefs.Clear; Auch der ist überflüssig:
Delphi-Quellcode:
Das der Index bei null anfängt sollte bekannt sein. Der Rest wird durch die sehr aussagekräftigen Bezeichner selbstkommentierend.
(* Die erste Zeile (ACHTUNG: Indexwert 0) wird in ihre Bestandteile (Feldanga-) *)
(* aufgespalten. Der Feldtrenner wird dabei an die Prozedur DatenTrennen durch- *) (* gereicht. *) DatenTrennen(ParamListe.Strings[0], ParamTrenner, FeldListe); Was ich sagen will, zu viele und zu lange Kommentare stören eher beim Lesen des Codes, als dass sie zu dessen Verständnis beitragen. Was anderes wäre folgerndes:
Delphi-Quellcode:
Da wäre ein Kommentar sinnvoll, warum du erst beim zweiten Eintrag anfängst, weil der erste eventuell irgendwelche anderen Daten enthält, die du hier nicht brauchst oder so. Sprich, wenn man etwas ungewöhnliches oder schwer nachzuvollziehendes macht, sind Kommentare angebracht, die hauptsächlich das Warum erklären, das wie sieht man ja am Code.
DatenTrennen(ParamListe.Strings[1], ParamTrenner, FeldListe);
|
Re: Access Violation 30 Sek. nach letzter Anweisung?
Ich hab das nicht auskommentiert weil ich das nicht programmiert hab ;) aber kanns gerne rauseditieren wen ihr wollt.
mfg Alex |
Re: Access Violation 30 Sek. nach letzter Anweisung?
Man könnte auch gleich Stringlisten-Methoden verwenden
|
Re: Access Violation 30 Sek. nach letzter Anweisung?
Das war nur eine allgemeine Anmerkung zu dem Programmierstil. Lass es so.
|
Re: Access Violation 30 Sek. nach letzter Anweisung?
/kleiner push
Kann mir niemand weiterhelfen? :( //Edit: Hat sich erledigt, hing mit dem zu oft gefüllten und erneut geöffnetem Query zusammen. mfg Alex |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04: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