Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   EAccessViolation beim Schreiben von Daten in Datei oder Stream (https://www.delphipraxis.net/186096-eaccessviolation-beim-schreiben-von-daten-datei-oder-stream.html)

DualCoreCpu 3. Aug 2015 09:48

EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Hallo,

ich weiß nicht mehr weiter. Ich versucher einen Record mit Stringdaten in einen TFileStream zu schreiben. Leider wird nichs geschrieben.

Hier der Quellcode:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, FileServer, StdCtrls;

type
  TTestRec = record
    Feld1: String;
    Feld2: String;
    Feld3: String;
  end;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    btnOk: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure FormDestroy(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
    procedure Edit2Change(Sender: TObject);
    procedure Edit3Change(Sender: TObject);
    procedure btnOkClick(Sender: TObject);
  private
    { Private declarations }
    FStream: TFileStream;
    FFileWriter: TWriter;
    FTestFields: TTestRec;
  public
    { Public declarations }
    procedure CreateWnd;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnOkClick(Sender: TObject);
begin
  FFileWriter.WriteString(FTestFields.Feld1);
  FFileWriter.WriteString(FTestFields.Feld2);
  FFileWriter.WriteString(FTestFields.Feld3);
end;

procedure TForm1.CreateWnd;
begin
  FStream := TFileStream.Create('Testfile.def', fmCreate);
  FFileWriter := TWriter.Create(FStream,1024);
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
  FTestFields.Feld1 := Edit1.Text;
end;

procedure TForm1.Edit2Change(Sender: TObject);
begin
  FTestFields.Feld2 := Edit2.Text;
end;

procedure TForm1.Edit3Change(Sender: TObject);
begin
  FTestFields.Feld3 := Edit3.Text;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FFileWriter.Free;
end;

end.
Vorher hatte ich es mit dem Typ File versucht, hatte aber auch keinen Erfolg. Auch mit TFileStream funktioniert es nicht. Bei letzterem hatte ich exta Shortstrings folgender Form verwendet:

Delphi-Quellcode:
type
  TMyTestRec = record
    Feld1: String[30];
    Feld2: String[255];
    Feld3: String[20];
  end;
Auch die Klammerung des Records mit {$H-}{$H+} führt nicht zum Erfolg.

Habe soeben mal getestet, ob ich bei gestartetem Programm eine Dati in mein Projektverzeichnis kopiren kann. Dies funktioniert, weshalb ich nicht an fehlende Schreibrechte glauben kann. Wo aber liegt dann die Ursache für mein Problem?

mkinzler 3. Aug 2015 09:54

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Hast Du es mal mit der Angabe des kompletten Pfades probiert? Schreibrechte vorhanden?

Union 3. Aug 2015 09:57

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Und wer ruft CreateWnd auf? Override ist Dein Freund ;)

baumina 3. Aug 2015 09:58

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Ich sehe auch kein FormCreate, welches CreateWnd aufrufen würde.

Union 3. Aug 2015 10:01

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Du brauchst kein FormCreate. Das macht der TReader. Es ist zwar gefährlich das so zu tun, weil die Komponenten evtl. noch nicht vollständig initialisiert sind, aber in dem speziellen Fall funktioniert das.

baumina 3. Aug 2015 10:05

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Aber wenn doch CreateWnd nirgends aufgerufen wird, wie lautet denn dann der Dateiname?

Sir Rufo 3. Aug 2015 10:09

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Debugger nehmen, Haltepunkt auf die Zeile, wo der FileStream erzeugt wird und im Debug-Mode starten.

Hält der Debugger jetzt dort an?

Nein -> Dann sorg dafür, dass die Methode auch aufgerufen wird.

So einfach kann einfach sein.

Union 3. Aug 2015 10:11

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Zitat:

Zitat von Sir Rufo (Beitrag 1310757)
So einfach kann einfach sein.

Wenn einfach einfach einfach ist ;)

DualCoreCpu 3. Aug 2015 10:42

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Danke für die Antwort!

Komplette Pfadangabe hilft leider nicht.

Wie war das gleich noch mal mit dem Feststellen ob Schreibrechte, aus dem Programm heraus?

Wenn das Progaramm gestartet ist, kann ich zumindest Dateien in das Verzeichnis kopieren, in welchem das Programm liegt.

@baumina, @Union:

Ja, danke Euch, CreateWnd war das Problem.

Allerdings erhalte ich jetzt eine EFCreateError Exception, egal, ob ich CreateWnd in FormCreate aufrufe oder nicht.

Hieraus ergibt sich neben der Ursache meines Problems eine Verständnisfrage:

- Wie ist die Aurufreihenfolge?

Gewöhnlich wird ein Create Konstruktor zur Initilalisierung der Klasse aufgrufen, im Formular kommt noch FormCreate dazu.

Wann in dieser Reihenfolge wird CreateWnd aufgerufen? Danach oder zwischen Create und Formcreate?

Oder muss ich zwingend selber für den Aufruf sorgen.

Bei mir allerdings kommt die EFCreateError Exception, wenn ich das OVERRIDE dahinter schreibe. Ohne override funktioniert es jatzt. Was ein Workaround wäre, aber nun würd ich gerne wissen wie die korrekte Aufrufreihenfolge ist.

frankyboy1974 3. Aug 2015 11:17

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Hallo,

ich würde jetzt mal vermuten da fehlt ein inherited; in der Methode CreateWnd. Ich musste mich auch erst mal einlesen, ich habe das gefunden

'CreateWnd is called automatically when the control is first created or when the underlying screen object must be destroyed and recreated to reflect property changes. Override CreateWnd to pass additional initialization messages to the screen object when it is created. '.

Soweit ich mich erinnere, muss du wenn du eine Funktion überschreibst auch ein inherited aufrufen (Ich bin kein Delphi-Guru).:pale:

mfg

frank

baumina 3. Aug 2015 12:00

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Ich persönlich würde CreateWnd nicht benutzen. Im FormCreate das erstellen was man braucht und im FormDestroy alles wieder freigeben.

Captnemo 3. Aug 2015 13:33

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Die Frage die ich mir grad stelle: Wenn du FormCreate verwendet, wofür benötigst du jetzt noch CreateWnd?
Und angenommen das
Delphi-Quellcode:
  FStream := TFileStream.Create('Testfile.def', fmCreate);
   FFileWriter := TWriter.Create(FStream,1024);
steht jetzt im FormCreate, wo tritt denn die AccessViolation auf?

Darüberhinaus solltest du ggf. auch prüfen, ob den TFilestream.Create auch von Erfolg gekrönt ist, bevor du ihn an den TWriter weitergibst.

DualCoreCpu 3. Aug 2015 18:44

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Zitat:

Zitat von Captnemo (Beitrag 1310791)
Die Frage die ich mir grad stelle: Wenn du FormCreate verwendet, wofür benötigst du jetzt noch CreateWnd?
Und angenommen das
Delphi-Quellcode:
  FStream := TFileStream.Create('Testfile.def', fmCreate);
   FFileWriter := TWriter.Create(FStream,1024);
steht jetzt im FormCreate, wo tritt denn die AccessViolation auf?

Darüberhinaus solltest du ggf. auch prüfen, ob den TFilestream.Create auch von Erfolg gekrönt ist, bevor du ihn an den TWriter weitergibst.

Die Exception tritt auf, wenn ich schreiben will.

@baumina:

Schon richtig, aber ich habe noch ein anderes Problem. Ich will einen Optionsdialog bauen, der links so eine Baumstruktur hat, wie im aktuellen Lazarus der Projektoptionen-Dialog. Dabei will ich, wenn der Dialog erzeugt ist, die Baumstruktur abhängig von den aktuell gewünschten Einzustellenden Optionen unterschiedlich aufbauen. Dazu muss einerseits der Dialog vollständig erstellt sein, andererseits darf die Baumstruktur noch nicht fertig sein, weil ich dem Dialog gerne über eine Eigenschaft einen Parameter migeben will, der dann über den jeweiligen Aufbau der Baumstruktur entscheidet. Nach Formcreate ist der Dialog einsatzbereit. Wenn nun CreateWnd danach erst aufgerufen würde, wäre CreateWnd möglicherweise mein Freund. Allerdings natürlich nur, wenn CreateWnd nicht vor Show/ShowModal aufgerufen wird. Wenn doch, brauche ich CreateWnd eigentlich nicht und kann hier @bauminas Tipp beherzigen.

Daher die alles entscheidende Frage: Wo wird CreateWnd aufgerufen?

Hallo,

@frankyboy1974:

Kann sein, das das inherited gefehlt hat.

Der folgende Code funktioniert wie er soll, unter Verwendung von CreateWnd:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, FileServer, StdCtrls;

type
  TTestRec = record
    Feld1: String;
    Feld2: String;
    Feld3: String;
  end;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    btnOk: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure FormDestroy(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
    procedure Edit2Change(Sender: TObject);
    procedure Edit3Change(Sender: TObject);
    procedure btnOkClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FStream: TFileStream;
    FFileWriter: TWriter;
    FTestFields: TTestRec;
  public
    { Public declarations }
    procedure CreateFileSystem;
    procedure CreateWnd; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnOkClick(Sender: TObject);
begin
  FFileWriter.WriteString(FTestFields.Feld1);
  FFileWriter.WriteString(FTestFields.Feld2);
  FFileWriter.WriteString(FTestFields.Feld3);
end;

procedure TForm1.CreateFileSystem;
var
  Directory: String;
begin
  Directory := GetCurrentDir;
  if Directory[Length(Directory)]<>'\' then Directory := Directory + '\';
  FStream := TFileStream.Create(Directory+'Testfile.def', fmCreate);
  FFileWriter := TWriter.Create(FStream,1024);
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
  FTestFields.Feld1 := Edit1.Text;
end;

procedure TForm1.Edit2Change(Sender: TObject);
begin
  FTestFields.Feld2 := Edit2.Text;
end;

procedure TForm1.Edit3Change(Sender: TObject);
begin
  FTestFields.Feld3 := Edit3.Text;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FFileWriter.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //CreateFileSystem;  //das war vorher mein CreateWnd ohne inherited
end;

procedure TForm1.CreateWnd;
begin
  inherited;
  CreateFileSystem; //jetzt wird CreateWnd korrekt aufgerufen.
end;

end.
Kann also sein, das ich das inherited vorher versehentlich gelöscht habe.

Nun aber noch die Frage, wann wird CreateWnd aufgerufen?:

- im Create - constructor (dann wohl in einem Vorfahren, vielleicht TWinControl)

[EDIT] --- Hab soeben mal im VCL Ouellcode nachgeschaut. In TWinControl.Create ist kein CreateWnd. ----

Weiß zufällig jemand, an welcher Stelle CreateWnd aufgerufen wird. In welcher Unit steht das?

Bitte nur wenn es zufällig jemand weiß. Ich besitze die VCL Quelltexte!

DualCoreCpu 3. Aug 2015 18:51

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Leider kann ich den vorigen Beitrag nicht mehr bearbeiten, deshalb hier:

Habe soeben den Aufruf von CreateWnd gefunden.

In TScrollingWinControl.Create.

Damit brauche ich für den geplanten Optionsdialog einen anderen Ansatz und kann ebenso gut Bauminas Rat beherzigen.

Danke für alle Eure Antworten. :cheers:

Sir Rufo 3. Aug 2015 22:35

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Wenn du den Debugger benutzt, dann brauchst du nicht suchen, sondern du findest die Stelle ganz automatisch.

Haltepunkt auf das
Delphi-Quellcode:
begin
und dann mit F7 in das inherited hineinsteppen. Schwupps bist du da ...

Union 4. Aug 2015 07:12

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Es fehlt allerdings noch das Exceptionhandling. Und für die Pfadnamen verwende doch besser die TPath und TDirectory records.

Rollo62 4. Aug 2015 08:08

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Ist es überhaupt empfelenswert TWriter für Records zu benutzen ?

Zitat:

Do not directly create writer objects. Writers are automatically created in stream object methods or in global routines that initiate the streaming process. These include:

The global routine ObjectTextToBinary procedure, which directly creates a writer.
The global WriteComponentResFile function, which creates a file stream that creates a writer.
The WriteDescendent method of TStream, which creates a writer object.
Das ist doch eigentlich für Component-Streaming gedacht, habe das zumindest nie für
andere Zwecke ausprobiert.

Rollo

DualCoreCpu 4. Aug 2015 10:39

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Zitat:

Zitat von Union (Beitrag 1310862)
Es fehlt allerdings noch das Exceptionhandling.

Ok, danke. Werd ich in der fertigen Version berücksichtigen.

Zitat:

Zitat von Union (Beitrag 1310862)
Und für die Pfadnamen verwende doch besser die TPath und TDirectory records.

TDirectory gibt e sin D7 auf jeden Fall, aber TPath???? Ab welcher Delph Version also gibt es Tpath? Neben Delphi 7 habe ich noch Turbo Delphi und Lazarus Portable Version 1.2.6 mit fpc Version 2.6.4.

Allerdings verstehe ich den Einwand nicht. Ich habe zum Erhalt des Directoties die Funktion GetCurrent Dir verwendet, weil mein Tesfile im Verzeichnis der Testanwendung liegt.

Klaus01 4. Aug 2015 10:47

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
GetCurrentDir
Returns the name of the current directory.

GetCurrentDir returns the fully qualified name of the current directory.

Es liefert also nicht zwangsläufig den Pfad Deiner Anwendung zurück.

ExtractFilePath(ParamStr(0)) wäre vielleicht sinnvoller.

Grüße
Klaus

Union 4. Aug 2015 10:50

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Sorry, ich konnte nirgendwo die verwendete Delphi Version sehen. Du solltest das aber trotzdem besser so machen (geht auch mit D7):
Delphi-Quellcode:
Directory := IncludeTrailingPathDelimiter(ExtractFilePath(Paramstr(0)));
Wie teilweise auch schon von Klaus vorgeschlagen.

p80286 4. Aug 2015 11:14

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Ich hab gerade mal in mein D7 geschaut:
Zitat:

Instanzen von TDirectory werden für Verzeichnisse in einem Dateisystem verwendet.

Unit

QFileCtrls

Beschreibung

Mithilfe eines TDirectory-Objekts können andere Komponenten mit einem Verzeichnis interagieren. Die andere Komponente (der Client) kann durch die TDirectory-Instanz Informationen zum Inhalt des Verzeichnisses verwalten und verschiedene Dateioperationen durchführen.

Der Client muss zur Kommunikation mit dem Verzeichnisobjekt die Schnittstelle IDirectoryClient implementieren.

Ein TDirectory-Objekt führt eine interne Liste der Dateien im Verzeichnis. Auf diese gefilterte Liste kann mit den Eigenschaften und Methoden des Objekts zugegriffen werden.

Die Klasse TDirectory kann direkt oder als Basisklasse für neue Verzeichnisobjekte verwendet werden. Sie enthält verschiedene virtuelle Methoden, die in abgeleiteten Klassen überschrieben werden können.
Scheint aber nicht für Windows gedacht zu sein?
oder hab ich da etwas falsch verstanden?

Gruß
K-H

mkinzler 4. Aug 2015 11:27

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Zitat:

Scheint aber nicht für Windows gedacht zu sein?
Unter anderem.

Das Unit-Präfix weist auf CLX hin

Luckie 4. Aug 2015 11:58

AW: EAccessViolation beim Schreiben von Daten in Datei oder Stream
 
Zitat:

Zitat von DualCoreCpu (Beitrag 1310897)
Zitat:

Zitat von Union (Beitrag 1310862)
Es fehlt allerdings noch das Exceptionhandling.

Ok, danke. Werd ich in der fertigen Version berücksichtigen.

Und warum nicht jetzt gleich zur Fehlersuche? :roll:


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