I'm trying to create my own class object and use it to store various data types for my application, this all works fine when using Published Properties, I can stream these to disk and back with no problems. But I need to stream some dynamic Arrays of integer types as well.
type
TArrayOfInteger = array of integer;
TSetting = class(TComponent)
private
fIntVal: integer;
fIntArr: TArrayOfInteger;
procedure ReadIntArr(Reader: TReader);
procedure WriteIntArr(Writer: TWriter);
protected
procedure DefineProperties(Filer: TFiler); override;
published
property intval: integer read fIntVal write fIntVal;
property intArr: TArrayOfInteger read fIntArr write fIntArr;
end;
{ TSetting }
procedure TSetting.DefineProperties(Filer: TFiler);
begin
inherited;
Filer.DefineProperty('intArr', ReadIntArr, WriteIntArr, true);
end;
procedure TSetting.ReadIntArr(Reader: TReader);
var
i: integer;
lvVal:Integer;
begin
i:=low(fintArr);
Reader.ReadListBegin;
{j := Reader.ReadInteger();
setlength(fIntArr, j);
for i := 0 to j - 1 do
begin
fIntArr[i] := Reader.ReadInteger();
end;}
while not Reader.EndOfList do begin
fIntArr[i]:=Reader.ReadInteger;
Inc(i);
end;
Reader.ReadListEnd;
end;
procedure TSetting.WriteIntArr(Writer: TWriter);
var
i: integer;
begin
Writer.WriteListBegin;
//Writer.WriteInteger(integer(Length(fIntArr)));
for i := Low(fIntArr) to High(fIntArr) do
begin
Writer.WriteInteger(fIntArr[i]);
end;
Writer.WriteListEnd;
end;
function ClassToStr(pvClass:TComponent):ansiString;
var
inStream, outStream: TMemoryStream;
begin
inStream := TMemoryStream.Create;
outStream := TMemoryStream.Create;
try
inStream.WriteComponentRes(pvClass.ClassName, pvClass);
//inStream.WriteComponent(pvClass);
inStream.Position := 0;
ObjectResourceToText(inStream, outStream);
// ObjectBinaryToText(inStream,outStream);
outStream.Position := 0;
SetLength(Result,outStream.Size+1);
FillChar(result[1],outStream.Size+1,0);
outStream.ReadBuffer(result[1],outStream.Size);
finally
FreeAndNil(inStream);
FreeAndNil(outStream);
end;
end;
function StrToClass(pvStr:AnsiString;pvComponent:TComponent):tcomponent;
var
inStream, outStream: TMemoryStream;
begin
inStream := TMemoryStream.Create;
outStream := TMemoryStream.Create;
try
if (pvStr<>'') then
inStream.WriteBuffer(pvStr[1],length(pvStr));
inStream.Position:=0;
ObjectTextToResource(inStream, outStream);
// ObjectTextToBinary(inStream,outStream);
outStream.Position:=0;
result:=outStream.ReadComponentRes(pvComponent); //*****Exception Fired*****
//result:=outStream.ReadComponent(pvComponent);
finally
FreeAndNil(inStream);
FreeAndNil(outStream);
end;
end;
=============
//test
procedure TForm1.btn5Click(Sender: TObject);
var
lvObj,lv1: TSetting;
lvStr:String;
lvArr:TArrayOfInteger;
begin
lvObj := TSetting.Create(nil);
try
lvObj.intval := 12345;
setlength(lvArr, 3);
lvArr[0] := 222;
lvArr[1] := 333;
lvArr[2] := 444;
lvObj.intArr:=lvArr;
lvStr:=ClassToStr(lvObj);
RegisterClass(TSetting);
lvObj.intval:=1;
lv1:=TSetting( StrToClass(lvStr,lvObj));
if (lv1.intval>0) then
mmo1.Text:=lvStr;
finally
FreeAndNil(lvObj);
end;
// WriteComponentResFile(ExtractFilePath(ParamStr(0))+ 'd.res',self);
end;
//First chance exception at $77925B68. Exception class EReadError with message 'Property does not exist'. Process Project1.exe (23512)
//First chance exception at $77925B68. Exception class EReadError with message 'Error reading TSetting.: Property does not exist'. Process Project1.exe (23512)
result:=outStream.ReadComponentRes(pvComponent); //*****Exception Fired*****
You are not allocating the array when reading it. You could do that like so:
procedure TSetting.ReadIntArr(Reader: TReader);
begin
fIntArr := nil;
Reader.ReadListBegin;
while not Reader.EndOfList do begin
SetLength(fIntArr, Length(fIntArr) + 1);
fIntArr[high(fIntArr)] := Reader.ReadInteger;
end;
Reader.ReadListEnd;
end;
The other change that you need to make is to move intArr
to be a public property. You cannot have it published, and also define a property with the same name in DefineProperties
.
I am somewhat dubious of your use of AnsiString
. I would have expected UTF-8 encoded bytes in case of non-ASCII characters. Perhaps you should be using a string stream with the appropriate encoding specified.
Personally I am rather sceptical of using form streaming in this way. I would prefer to use a standard format such as JSON.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments