Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Problem mit dpCollection, loadfromStream / assign (https://www.delphipraxis.net/132637-problem-mit-dpcollection-loadfromstream-assign.html)

JohannesK 16. Apr 2009 16:06


Problem mit dpCollection, loadfromStream / assign
 
Hallo, ich habe folgendes Problem bei der Verwendung der DpCollection:

savetostream funktioniert, bei loadfromstream kommt Fehlermeldung.

Die Klassen sind wir folgt definiert:
Delphi-Quellcode:
 type TChecklistItems = class(TCollection)  // Definition Typ TChecklistItems -

   private         // Beginn des privaten Bereichs
    bj, rw, knlevel: Integer;
    selected : boolean;
    icount : integer;
    parent : TComponent;
    iclass : TChecklistItem;
    tn : string;

    function liesParent: TComponent;
    procedure schreibParent(tx: TComponent);
    function liesListname: string;
    procedure schreibListname(tx: string);
    function LiesItemclass: TCollectionItemClass;
    function GetItem(w: integer): TChecklistItem;
    procedure SetItem(w: Integer; const Value: TChecklistItem);

   public            // Beginn des öffentlichen Bereichs
    property Items[X : Integer] : TChecklistItem read GetItem write SetItem; default;
    constructor create;
    procedure SaveToStream(Stream: TStream);
    procedure LoadFromStream(Stream: TStream);
    property itemlistname: string read lieslistname write schreiblistname;
    property ItemClass : TCollectionItemClass read LiesItemclass;
    function add: TChecklistItem;
  end;

   TCheckListDummy = class(TComponent)
   private
     FItems : TChecklistItems;
   public
     constructor Create(AOwner : TComponent); override;
     destructor Destroy; override;
     procedure Assign(Source: TPersistent); override;
   published
     property Items : TChecklistItems read FItems write FItems;
   end;

  procedure TChecklistItem.Assign(Source: TPersistent);
    begin
      If Source is TChecklistItem then
        begin
          tn:=TChecklistItem(Source).itemname;
          // FNumbers.Assign(TChecklistItem(Source).Numbers);
      end
        else
        inherited Assign(Source);
  end;
  procedure TChecklistItems.SaveToStream(Stream: TStream);
  var
  CheckListDummy : TCheckListDummy;
  begin
    CheckListDummy:=TCheckListDummy.Create(Nil);
    Try
      CheckListDummy.Items.Assign(self);
      Stream.WriteComponent(CheckListDummy);
    Finally
      CheckListDummy.Free;
    end;
  end;

  procedure TChecklistItems.LoadFromStream(Stream: TStream);
  var
    CheckListDummy : TCheckListDummy;
  begin
    CheckListDummy := TCheckListDummy.Create(Nil);
    Try
      Stream.ReadComponent(CheckListDummy);
      Assign(CheckListDummy.items);
    Finally
      CheckListDummy.Free;
      end;
  end;
Der Stream wird in ein Blob-Feld geschrieben bzw. von dort ausgelesen.
Beim Versuch ein loadfromstream zu nutzen kommt eine EAccessViolation, der gleiche Vorgang für die einzelitems funktioniert ebenfalls ohne Probleme.
Die originale Version der dpCollection funktioniert einwandfrei.

Was habe ich übersehen :cry: ?

oki 16. Apr 2009 21:25

Re: Problem mit dpCollection, loadfromStream / assign
 
hi,

ich kenn die dpCollection zwar nicht, aber folgende Fragen:

In welcher Zeile genau kommt die Fehlermeldung?
Welche Fehlermeldung kommt?

Dann fällt mir auf, dass du beim Assign die Items übergibst. In deiner Assign-Methode weist du aber Item zu. Entweder ich bring da jetzt was durcheinander oder da ist was falsch.

Gruß oki

JohannesK 16. Apr 2009 22:06

Re: Problem mit dpCollection, loadfromStream / assign
 
Die Fehlermeldung kommt in der Zeile
Delphi-Quellcode:
Assign(CheckListDummy.items);
Es ist eine Zugriffsverletzung (EAccessViolation).
Die dpcollection ist eine Sammlung von Routinen für Collection und deren Ablage in Streams.
Die von mir verwendeten Routinen sind praktisch 1:1 übernommen.

oki 17. Apr 2009 06:20

Re: Problem mit dpCollection, loadfromStream / assign
 
Welche Zugriffsverletzung? Auf einen Nil-Zeiger?
Dann stepp mal mit dem Debugger durch und schau genau an welcher Stelle die Fehlermeldung kommt. Entweder du musst auch Assign vererben (keine Ahnung ob) oder der gelesene Inhalt aus dem Stream ist nicht korrekt.

Mich würde auch mal interessieren wozu diese Methode gehört:
Delphi-Quellcode:
  procedure TChecklistItem.Assign(Source: TPersistent);
    begin
      If Source is TChecklistItem then
        begin
          tn:=TChecklistItem(Source).itemname;
          // FNumbers.Assign(TChecklistItem(Source).Numbers);
      end
        else
        inherited Assign(Source);
  end;
ich sehe bei dir nur die Klasse TChecklistItems, die Deklaration bezieht sich aber auf TChecklistItem.

Gruß oki

JohannesK 17. Apr 2009 07:52

Re: Problem mit dpCollection, loadfromStream / assign
 
1. Danke für den Hinweis, die Klasse TChecklistItem ist natürlich auch definiert, TChecklistItems ist die Collection dazu.

Delphi-Quellcode:
  type TChecklistItem = class(TcollectionItem)  // Definition Typ TChecklistItem ---
   private
   tn : string;
   function liesItemname: string; procedure schreibItemname(tx: string);
   
   public          
   constructor create(AOwner: TCollection); override;
   destructor Destroy; override;
   property itemname: string read liesItemname write schreibItemname;
   procedure Assign(Source: TPersistent); override;
   procedure SaveToStream(Stream: TStream);
   procedure ReadFromStream(Stream: TStream);

  end;

// TChecklistItem --------------------------------------------------------------

  constructor TChecklistItem.Create(AOwner: TCollection);
  begin
    inherited Create(AOwner);
  end;

  destructor TChecklistItem.Destroy;
  begin
    inherited Destroy;
  end;

  procedure TChecklistItem.SaveToStream(Stream: TStream);
  var
    CheckDummy : TCheckDummy;
  begin
    CheckDummy:=TCheckDummy.Create(Nil);
    Try
      CheckDummy.ItemTx := self.ItemTx;
      CheckDummy.tn := self.tn;
      stream.Position := stream.Size;
      Stream.WriteComponent(CheckDummy);
    Finally
    end;
  end;

  procedure TChecklistItem.ReadFromStream(Stream: TStream);
  var
    CheckDummy : TCheckDummy;
  begin
    CheckDummy:=TCheckDummy.Create(Nil);
    Try
      Stream.ReadComponent(CheckDummy);
      self.itemtext := CheckDummy.ItemTx;
      self.itemname := CheckDummy.tn;
    Finally
    end;
  end;

  procedure TChecklistItem.Assign(Source: TPersistent);
    begin
      If Source is TChecklistItem then
        begin
          tn:=TChecklistItem(Source).itemname;
         
      end
        else
        inherited Assign(Source);
  end;
Zur Klasse TChecklistItem gehört ebenso ein Dummy for das Streaming, TCheckdummy. Schreiben und Lesen in den Stream funktioniert ohne Probleme.

2. Der Fehler kommt direkt beim Aufruf der Assign-Methode, aber nur beim Lesen:

Delphi-Quellcode:
  procedure TChecklistItems.LoadFromStream(Stream: TStream);
  var
    CheckListDummy : TCheckListDummy;
  begin
    CheckListDummy := TCheckListDummy.Create(Nil);
    Try
      Stream.ReadComponent(CheckListDummy);
      Assign(CheckListDummy.items); // Hier kommt die Zugriffsverletzung
    Finally
      CheckListDummy.Free;
      end;
  end;
Gruss JK

sx2008 17. Apr 2009 09:12

Re: Problem mit dpCollection, loadfromStream / assign
 
Deine Assign-Methode ist nicht vollständig:
Delphi-Quellcode:
procedure TChecklistItem.Assign(Source: TPersistent);
begin
  If Source is TChecklistItem then
  begin
    // hier wird nur ein einziges Property kopiert
    tn:=TChecklistItem(Source).itemname;
    // alle Properties der Basisklasse TCollectionItem werden nicht kopiert
  end
  else
    inherited Assign(Source);
end;
Ich gehe mal davon aus, dass TCollectionItem.Assign() im Sourcecode der VCL existiert (bitte prüfen).
Also kannst du diese Methode aufrufen und danach (!) noch das kopieren was noch fehlt:
Delphi-Quellcode:
procedure TChecklistItem.Assign(Source: TPersistent);
begin
  inherited Assign(Source); // sollte (Source is TCollectionItem) nicht wahr sein, dann gibts 'ne Exception

  If Source is TChecklistItem then
  begin
    tn:=TChecklistItem(Source).tn;
  end;
end;
Die Struktur sieht jetzt etwas anderst aus, als man das von der Assign-Methode gewöhnt ist, aber das hat damit zu tun,
dass wir es uns sparen ALLE Properties zu kopieren.

JohannesK 17. Apr 2009 11:19

Re: Problem mit dpCollection, loadfromStream / assign
 
Wenn ich die Prozedur so anpasse bekomme ich auch wieder eine Exception: TChecklistItem kann nicht zu TChecklistItem zugewiesen werden.

oki 17. Apr 2009 11:57

Re: Problem mit dpCollection, loadfromStream / assign
 
imho wird dann die nicht überschriebene Methode Assign von TPersistent aufgerufen. Prüf mal deine Vererbung.

Gruß oki

oki 17. Apr 2009 11:59

Re: Problem mit dpCollection, loadfromStream / assign
 
Mal ne andere Frage. Warum gehst du nicht mit dem Debugger Zeile für Zeile durch? Dann siehst du doch wo genau der Fehler kommt und welche Mathode aufgerufen wird.

Gruß oki


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