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;
ScottCannonAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Ephraim WangoyaCommented:

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

0
ScottCannonAuthor Commented:
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).
0
Ephraim WangoyaCommented:

Sorry for not replying sooner. I'll take a look at this again later today or tomorrow morning
0
Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

ScottCannonAuthor Commented:
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.
0
Ephraim WangoyaCommented:

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.

0
ScottCannonAuthor Commented:
Any suggestions on a better way of saving the data would be appreciated.
0
Ephraim WangoyaCommented:

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

0
Ephraim WangoyaCommented:

Another way you could do this is to save to a TClientDataset. For me it would be much easier to scale a database than a binary file (In case you want to add more fields to your record object)

However the SaveToStream and SaveToFile methods of the TVirtualStringTree are pretty fast

Thanks for your patience
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ScottCannonAuthor Commented:
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?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.