As said in the comments you need to implement IStreamPersist. In order fordoing that you can use RTTI, to store and restore your properties. I've created an example for you:
First you need a class that can persist all your properties, and it's values.
unit PropertyPersistU;
interface
uses
System.Classes, System.RTTI;
type
TPropertyPersist = class(TComponent, IStreamPersist)
strict private
class var RttiContext: TRttiContext;
class function GetProperty(const aObject: TObject; const aPropertyName: string): TRttiProperty; overload; static;
public
procedure LoadFromStream(Stream: TStream);
procedure SaveToStream(Stream: TStream);
procedure SaveToFile(const FileName: string);
procedure LoadFromFile(const FileName: string);
end;
implementation
uses
System.SysUtils;
class function TPropertyPersist.GetProperty(const aObject: TObject; const aPropertyName: string): TRttiProperty;
begin
Result := RttiContext.GetType(aObject.ClassType).GetProperty(aPropertyName);
end;
procedure TPropertyPersist.LoadFromFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure TPropertyPersist.LoadFromStream(Stream: TStream);
var
Reader: TReader;
RttiProperty: TRttiProperty;
begin
Reader := TReader.Create(Stream, $FFF);
Stream.Position := 0;
Reader.ReadListBegin;
while not Reader.EndOfList do
begin
RttiProperty := GetProperty(Self, Reader.ReadString); // Get property from property name read from stream
RttiProperty.SetValue(Self, TValue.FromVariant(Reader.ReadVariant)); // Get the property value
end;
Reader.Free;
end;
procedure TPropertyPersist.SaveToFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
end;
procedure TPropertyPersist.SaveToStream(Stream: TStream);
var
RttiType: TRttiType;
RttiProperty: TRttiProperty;
Writer: TWriter;
begin
RttiType := RttiContext.GetType(Self.ClassType);
Writer := TWriter.Create(Stream, $FFF);
try
Writer.WriteListBegin;
for RttiProperty in RttiType.GetProperties do
if RttiProperty.IsWritable then
if TRttiInstanceType(RttiProperty.Parent).MetaclassType.InheritsFrom(TPropertyPersist) then // Only save components on TPropertyPersist decendans
begin
Writer.WriteString(RttiProperty.Name); // Write the property name
Writer.WriteVariant(RttiProperty.GetValue(Self).AsVariant); // Write the property value
end;
Writer.WriteListEnd;
finally
Writer.Free;
end;
end;
end.
EDIT
If you have an older version of Delphi without extended RTTI then you need this implementation of TPropertyPersist
unit PropertyPersistU;
interface
uses
Classes;
type
TPropertyPersist = class(TComponent, IStreamPersist)
public
procedure LoadFromStream(Stream: TStream);
procedure SaveToStream(Stream: TStream);
procedure SaveToFile(const FileName: string);
procedure LoadFromFile(const FileName: string);
end;
implementation
uses
TypInfo, Sysutils;
{ TPropertyPersist }
procedure TPropertyPersist.LoadFromFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure TPropertyPersist.LoadFromStream(Stream: TStream);
var
Reader: TReader;
PropName, PropValue: string;
begin
Reader := TReader.Create(Stream, $FFF);
Stream.Position := 0;
Reader.ReadListBegin;
while not Reader.EndOfList do
begin
PropName := Reader.ReadString;
PropValue := Reader.ReadString;
SetPropValue(Self, PropName, PropValue);
end;
FreeAndNil(Reader);
end;
procedure TPropertyPersist.SaveToFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
end;
procedure TPropertyPersist.SaveToStream(Stream: TStream);
var
PropName, PropValue: string;
cnt: Integer;
lPropInfo: PPropInfo;
lPropCount: Integer;
lPropList: PPropList;
lPropType: PPTypeInfo;
Writer: TWriter;
begin
lPropCount := GetPropList(PTypeInfo(ClassInfo), lPropList);
Writer := TWriter.Create(Stream, $FFF);
Stream.Size := 0;
Writer.WriteListBegin;
for cnt := 0 to lPropCount - 1 do
begin
lPropInfo := lPropList^[cnt];
lPropType := lPropInfo^.PropType;
if lPropInfo^.SetProc = nil then
continue;
if lPropType^.Kind = tkMethod then
continue;
PropName := lPropInfo.Name;
PropValue := GetPropValue(Self, PropName);
Writer.WriteString(PropName);
Writer.WriteString(PropValue);
end;
Writer.WriteListEnd;
FreeAndNil(Writer);
end;
end.
Then you need to call it.
First create a small dummy clasas with some properties on it:
{$M+}
type
TSettings = class(TPropertyPersist)
private
FPropertyString: string;
FPropertyDate: TDateTime;
FPropertyInt: Integer;
published
property PropertyInt: Integer read FPropertyInt write FPropertyInt;
property PropertyString: string read FPropertyString write FPropertyString;
property PropertyDate: TDateTime read FPropertyDate write FPropertyDate;
end;
The you need to call it.
procedure TForm1.FormCreate(Sender: TObject);
const
StringValue = 'Dummy';
begin
with TSettings.Create(self) do
try
PropertyInt := 1;
PropertyString := StringValue;
PropertyDate := Now;
SaveToFile('Settings.dmp');
finally
Free;
end;
with TSettings.Create(self) do
try
LoadFromFile('Settings.dmp');
Assert(PropertyString = StringValue); //Test that the property is correctly read
finally
Free;
end;
end;
Now you can save and load a the properties of a class to a stream.
Next step is to create a complete working example:
New project and then add a ClientDataset to the MainForm and a FromCreate event.
First DFM code for the ClientDataset:
object ClientDataSet1: TClientDataSet
Aggregates = <>
FieldDefs = <>
IndexDefs = <>
Params = <>
StoreDefs = True
Left = 312
Top = 176
object ClientDataSet1FORMDM_NAME: TStringField
FieldName = 'FORMDM_NAME'
Size = 31
end
object ClientDataSet1OBJ_NAME: TStringField
FieldName = 'OBJ_NAME'
Size = 40
end
object ClientDataSet1Object: TBlobField
FieldName = 'Object'
end
end
Then the complete code the unit:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, DBClient;
type
TForm1 = class(TForm)
ClientDataSet1: TClientDataSet;
ClientDataSet1FORMDM_NAME: TStringField;
ClientDataSet1OBJ_NAME: TStringField;
ClientDataSet1Object: TBlobField;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
PropertyPersistU;
type
TSettings = class(TPropertyPersist)
private
FPropertyString: string;
FPropertyDate: TDateTime;
FPropertyInt: Integer;
published
property PropertyInt: Integer read FPropertyInt write FPropertyInt;
property PropertyString: string read FPropertyString write FPropertyString;
property PropertyDate: TDateTime read FPropertyDate write FPropertyDate;
end;
procedure TForm1.FormCreate(Sender: TObject);
const
StringValue = 'Dummy';
var
Stream : TMemoryStream;
Settings : TSettings;
begin
ClientDataSet1.CreateDataSet;
Stream := TMemoryStream.Create;
Settings := TSettings.Create(self);
try
Settings.PropertyInt := 1;
Settings.PropertyString := StringValue;
Settings.PropertyDate := Now;
Settings.Name := 'ObjectName';
Settings.SaveToStream(Stream);
finally
Settings.Free;
end;
Stream.Position := 0;
ClientDataSet1.Append;
ClientDataSet1FORMDM_NAME.AsString := Form1.Name;
ClientDataSet1OBJ_NAME.AsString := 'ObjectName';
ClientDataSet1Object.LoadFromStream(Stream);
ClientDataSet1.Post;
Caption := 'ClientDataSet1.RecordCount = ' + IntToStr(ClientDataSet1.RecordCount);
Stream.Free;
Stream := TMemoryStream.Create;
Settings := TSettings.Create(self);
ClientDataSet1.First;
ClientDataSet1Object.SaveToStream(Stream);
try
Settings.LoadFromStream(Stream);
Assert(Settings.PropertyString = StringValue);
finally
Settings.Free;
end;
Stream.Free;
end;
end.
That's it.
Add some error handling to the TPropertyPersist class, but that I'll leave to you.
ReadFromBlobField1()does not match the declaration you have shown.IStreamPersistin yourTSaveComponentand you can simply assign the instance to the blob field. There is no need to have a specializedSaveToBlobFieldorReadFromBlobField