Save Nodes from a VirtualTree

I am trying to save the node data in a VirtualTree, so I can load the data back after the applications restarts. Saving the GroupName from the record is causing problems. This is with Delphi 2010 and the latest VST.

  // this is a record structure for the virtual treeview to hold the object
  PTVgrplst = ^RTVgrplst;
  RTVgrplst = record
    Index: Integer;
    GroupName: string;  
    LastArticle: Cardinal;  
    FirstArticle: Cardinal;
    AllowPost: boolean;
    ArticleCount: Cardinal;
  end;

...

procedure TFormMain.VTreeGroupsSaveNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PTVgrplst;
  Len: integer;
begin

  Data := VTreeGroups.GetNodeData(Node);

  Stream.write(Data.LastArticle, SizeOf(Data.LastArticle));
  Stream.write(Data.FirstArticle, SizeOf(Data.FirstArticle));
  Stream.write(Data.AllowPost, SizeOf(Data.AllowPost));
  Stream.write(Data.Index, SizeOf(Data.Index));

  len := Length(Data.GroupName);
  Stream.Write(Len, SizeOf(Len));
  Stream.Write(Data.GroupName, Len);  <<--
end;

If I add like 100 to the "Len" like so...
  Stream.Write(Data.GroupName, Len+100);

then I can see the GroupName string in the dat/textfile that I save the contents to... but if I dont then the groupname isnt saved to the file (cut off actually, not missing). When I log the data, GroupName is not "" and the length is correct too. But why isnt the stream saving it correctly?
LVL 4
LMuadDIbAsked:
Who is Participating?
 
LMuadDIbAuthor Commented:
I think I found the correct answer to my question, this seems to work correctly:
I need to test more



//My Code ->>

procedure TFormMain.VTreeGroupsLoadNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PTVgrplst;
  Len: integer;
begin
  Data := VTreeGroups.GetNodeData(Node);

  Stream.read(Data.LastArticle, SizeOf(Data.LastArticle));
  Stream.read(Data.FirstArticle, SizeOf(Data.FirstArticle));
  Stream.read(Data.AllowPost, SizeOf(Data.AllowPost));
  Stream.read(Data.Index, SizeOf(Data.Index));
  // Correct for Unicode string data
  Stream.read(Len, SizeOf(Integer));  // Read the string length
  SetLength(Data.GroupName, Len div SizeOf(Char));
  Stream.Read(Pointer(Data.GroupName)^, Len);  // <<-- Specify buffer size in bytes
end;

procedure TFormMain.VTreeGroupsSaveNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PTVgrplst;
  Len: integer;
begin
  Data := VTreeGroups.GetNodeData(Node);

  Stream.write(Data.LastArticle, SizeOf(Data.LastArticle));
  Stream.write(Data.FirstArticle, SizeOf(Data.FirstArticle));
  Stream.write(Data.AllowPost, SizeOf(Data.AllowPost));
  Stream.write(Data.Index, SizeOf(Data.Index));
  // Correct for Unicode string data
  Len := Length(Data.GroupName) * SizeOf(Char);
  Stream.Write(Len, SizeOf(integer));   // Write the string length
  Stream.Write(Pointer(Data.GroupName)^, Length(Data.GroupName) * SizeOf(Char)); // <<-- Specifcy buffer size in bytes
end;


//example code which help me fix my problem above
//Answer came from: http://edn.embarcadero.com/article/38693

var
   S: string;
   L: Integer;
   Stream: TStream;
   Temp: AnsiString;
 begin
   // Existing code - incorrect when string = UnicodeString
   Stream.Read(L, SizeOf(Integer));
   SetLength(S, L);
   Stream.Read(Pointer(S)^, L);
   
   // Correct for Unicode string data
   Stream.Read(L, SizeOf(Integer));
   SetLength(S, L);
   Stream.Read(Pointer(S)^, L * SizeOf(Char));  // <<-- Specify buffer size in bytes
   
   // Correct for Ansi string data
   Stream.Read(L, SizeOf(Integer));
   SetLength(Temp, L);              // <<-- Use temporary AnsiString
   Stream.Read(Pointer(Temp)^, L * SizeOf(AnsiChar));  // <<-- Specify buffer size in bytes
   S := Temp;                       // <<-- Widen string to Unicode
 end;

//...

var
   S: string;
   Stream: TStream;
   Temp: AnsiString;
 begin
   // Existing code - incorrect when string = UnicodeString
   Stream.Write(Pointer(S)^, Length(S));
   
   // Correct for Unciode data
   Stream.Write(Pointer(S)^, Length(S) * SizeOf(Char)); // <<-- Specifcy buffer size in bytes
   
   // Correct for Ansi data
   Temp := S;          // <<-- Use temporary AnsiString
   Stream.Write(Pointer(Temp)^, Length(Temp) * SizeOf(AnsiChar));// <<-- Specify buffer size in bytes
 end;

Open in new window

0
 
LMuadDIbAuthor Commented:
yes, the above code I found has worked fine
the problem was unicode and handling a string with the record

so I answered my own question.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.