Link to home
Start Free TrialLog in
Avatar of ScottCannon
ScottCannonFlag for United States of America

asked on

Delphi XE and VirtualStringTree 4.8.7 - Saving and loading data

I'm having a problem saving and loading the nodes of the VirtualStringTree.  

Please explain where the problem is and how to fix it.

type
  PNodeData = ^TNodeData;
  TNodeData = record
    Caption: String;
    Filename: String;
    Description: String;
    FileDateTime: TDateTime;
    ImageIndex: Byte;
    ID: Integer;
  end;

procedure MainForm.TreeSaveNode (Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PNodeData;
  Len: integer;
begin
  Data := Tree.GetNodeData(Node);

  Len := Length(Trim(Data^.Caption));
  Stream.write(Len, SizeOf(Len));
  Stream.write(Data^.Caption, Len * SizeOf(Char));

  Len := Length(Trim(Data^.Filename));
  Stream.write(Len, SizeOf(Len));
  Stream.write(Data^.Filename, Len * SizeOf(Char));

  Len := Length(Trim(Data^.Description));
  Stream.write(Len, SizeOf(Len));
  Stream.write(Data^.Description, Len * SizeOf(Char));

  Stream.write(Data^.FileDateTime, SizeOf(Data^.FileDateTime));
  Stream.Write(Data^.ImageIndex, SizeOf(Data^.ImageIndex));
  Stream.Write(Data^.ID, SizeOf(Data^.ID));
end;


procedure MainForm.TreeLoadNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PNodeData;
  Len: integer;
begin
  Data := Tree.GetNodeData(Node);

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data^.Caption, Len);
  Stream.Read(Data^.Caption, Len * SizeOf(Char));

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data^.Filename, Len);
  Stream.Read(Data^.Filename, Len * SizeOf(Char));

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data^.Description, Len);
  Stream.Read(Data^.Description, Len * SizeOf(Char));

  Stream.Read(Data^.FileDateTime, SizeOf(Data^.FileDateTime));
  Stream.Read(Data^.ImageIndex, SizeOf(Data^.ImageIndex));
  Stream.Read(Data^.ID, SizeOf(Data^.ID));
end;
Avatar of Ephraim Wangoya
Ephraim Wangoya
Flag of United States of America image


You are storing the wrong sizes, and also using TRIM when getting length but not when saving
Cast as  Untyped pointer as well
procedure MainForm.TreeSaveNode (Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PNodeData;
  Len: integer;
begin
  Data := Tree.GetNodeData(Node);

  Len := Length(Data^.Caption);
  Stream.write(Len, SizeOf(Len));
  Stream.write(Pointer(Data^.Caption)^, Len);

  Len := Length(Data^.Filename);
  Stream.write(Len, SizeOf(Len));
  Stream.write(Pointer(Data^.Filename)^, Len);

  Len := Length(Data^.Description);
  Stream.write(Len, SizeOf(Len));
  Stream.write(Pointer(Data^.Description)^, Len);

  Stream.write(Data^.FileDateTime, SizeOf(Data^.FileDateTime));
  Stream.Write(Data^.ImageIndex, SizeOf(Data^.ImageIndex));
  Stream.Write(Data^.ID, SizeOf(Data^.ID));
end;

var
  Data: PNodeData;
  Len: integer;
begin
  Data := Tree.GetNodeData(Node);

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data^.Caption, Len);
  Stream.Read(Pointer(Data^.Caption)^, Len);

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data^.Filename, Len);
  Stream.Read(Pointer(Data^.Filename)^, Len);

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data^.Description, Len);
  Stream.Read(Pointer(Data^.Description)^, Len);

  Stream.Read(Data^.FileDateTime, SizeOf(Data^.FileDateTime));
  Stream.Read(Data^.ImageIndex, SizeOf(Data^.ImageIndex));
  Stream.Read(Data^.ID, SizeOf(Data^.ID));

Open in new window

Avatar of ScottCannon

ASKER

I emplemented your changes and it still has the following issue.

I have this code assigned to the tree OnChange event.

  if not Assigned(Node) then
    Exit;
  Data := Tree.GetNodeData(Node);
  Filename.Text := Data^.Filename;
  Description.Text := Data^.Description;
  ID.Text := IntToStr(Data^.ID);

Moving between nodes, the data is displayed correctly.
If I save the tree and open it, I don't receive any errors but when I change nodes the first half of the data displayed is correct and the second half is wrong.  (i.e. GeneralPurpose.pdf in the Filename becomes GeneralPuDivision).

Sorry for not replying sooner. I'll take a look at this again later today or tomorrow morning
Any idea what might be causing the corruption of the stings?  I've inspected the data prior to saving it to the stream and it is valid.  Inspecting is as it is being read from the stream it is corrupted.

This still does not tell me if it is corrupted when it is written out or when it is read in.

I'm currently debugging it, I created random 50 records and seems I always get the correct results.
I'm yet to try with different length strings, I'll definietly find the offending code, and I can also suggest a more robust way saving the data.

Any suggestions on a better way of saving the data would be appreciated.

Ok, I found the problem, I just could not recreate until I switched to Delphi 2010
You have to Typecast the strings as PChar. Also, use the Sender parameter from the method signature


procedure TMainForm.TreeLoadNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PNodeData;
  Len: Integer;
begin
  Data := Sender.GetNodeData(Node);

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data.Caption, Len);
  Stream.Read(PChar(Data.Caption)^, Len * SizeOf(Char) );

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data.Filename, Len);
  Stream.Read(PChar(Data.Filename)^, Len * SizeOf(Char));

  Stream.Read(Len, SizeOf(Len));
  SetLength(Data.Description, Len);
  Stream.Read(PChar(Data.Description)^, Len * SizeOf(Char));

  Stream.Read(Data.FileDateTime, SizeOf(Data.FileDateTime));
  Stream.Read(Data.ImageIndex, SizeOf(Data.ImageIndex));
  Stream.Read(Data.ID, SizeOf(Data.ID));

end;

procedure TMainForm.TreeSaveNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PNodeData;
  Len: integer;
begin
  Data := Sender.GetNodeData(Node);

  Len := Length(Data.Caption);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data.Caption)^, Len * SizeOf(Char));

  Len := Length(Data^.Filename);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data.Filename)^, Len * SizeOf(Char));

  Len := Length(Data^.Description);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data.Description)^, Len * SizeOf(Char));

  Stream.write(Data.FileDateTime, SizeOf(Data.FileDateTime));
  Stream.Write(Data.ImageIndex, SizeOf(Data.ImageIndex));
  Stream.Write(Data.ID, SizeOf(Data.ID));

end;

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Ephraim Wangoya
Ephraim Wangoya
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
This works perfectly.  Thanks for the great work!

You mentioned that you would suggest a more robust way of saving the data... any more thought on doing so and maybe an example?