Forum > General

Lazarus RTTI

(1/1)

Imants:
How can I read/write published array and record propertyes.

I would like to create automatic property saving/loading. There are no problems with strings, integers, classes and interfaces, but I cant understand how to read/write arrays and record props.

//Small example how I think it would nead to work

TIntArray = array of Integer;

TTest = class
private
  TestArray: TIntArray;
  FName: String;
  FCount: Integer;
public
  procedure SaveAllProps;
  procedure LoadAllProps;
published
  property TestArray: TIntArray read FTestArray write FTestArray;
  property Name: String read FName write FName;
  property Count: Integer read FCount write FCount;
end;

Procedure TTest.SaveAllProps;
var
  lPropInfo: PPropInfo;
  lPropList: PPropList;
  i: Integer;
Begin
  for i := 0 to GetPropList(PTypeInfo(PropObject.ClassInfo), lPropList) - 1 do
  Begin
    lPropInfo := lPropList;
    case lPropInfo^.Kind of
      tkClass:
        WriteObjectProp(Self, PropInfo);//My created function works fine
      tkInterface:
        WriteInterfaceProp(Self, PropInfo);//My created function works fine
      tkRecord:
        WriteRecordProp(Self, PropInfo); // my function works only on Delphi :(
      tkDynArray, tkArray:
        WriteArrayProp(Self, PropInfo); // my function works only on delphi too :(
    else
      WriteVariant(GetPropValue(Self, String(PropInfo.Name)))
  end
end;

Marc:
IIRC in early versions of delphi record/array properties couldn't be published, so I wonder if FPC has implemented it.
What version of delphi did you test ?

Imants:
I used Delphi 2010 but I think it work on erlier versions too.

You could read records using this code

procedure ReadRecordProp(Reader: TReader; Instance: TObject; PropInfo: PPropInfo);
type
  TDummy = record
  end;

  TSetProc = Procedure(Value: TDummy) of object;
  TIndexedSetProc = Procedure(Index: Integer; Value: TDummy) of object;
var
  TypeData: PTypeData;
  P, Buffer: Pointer;
  M: TMethod;
  Setter: Longint;
  G: ISafeGuard;
begin
  // Iegūst record tipa izmēru
  TypeData := GetTypeData(PropInfo.PropType^);

  // Izveidojam buferi un piešķiram viņam atmiņu
  Buffer := GuardMemory(TypeData.RecSize, G);

  // Nolasam datus
  Reader.Read(Buffer^, TypeData.RecSize);

  Setter := Longint(PropInfo^.SetProc);
  if (Setter and $FF000000) = $FF000000 then
  begin // field - Getter is the field's offset in the instance data
    P := Pointer(Integer(Instance) + (Setter and $00FFFFFF));
    CopyMemory(P, Buffer, TypeData.RecSize);
  end
  else
  begin

    if (Setter and $FF000000) = $FE000000 then
      // virtual method - Getter is a signed 2 byte integer VMT offset
      M.Code := Pointer(PInteger(PInteger(Instance)^ + SmallInt(Setter))^)
    else
      // static method - Getter is the actual address
      M.Code := Pointer(Setter);

    M.Data := Instance;
    if PropInfo^.Index = Integer($80000000) then // no index
      TSetProc(M)(TDummy(Buffer^))
    else
      TIndexedSetProc(M)(PropInfo^.Index, TDummy(Buffer^))
  end;
end;

and read arrays using this code

procedure ReadArrayProp(Reader: Treader; Instance: TObject; PropInfo: PPropInfo);
var
  i, aSize: Integer;
  P: Pointer;
  ar: array of Variant;
  V: Variant;
begin
  aSize := ReadInteger;
  SetLength(ar, aSize);
  for i := Low(ar) to High(ar) do
    ar := Reader.ReadVariant;

  V := VarArrayOf(ar);

  DynArrayFromVariant(P, V, PropInfo^.PropType^);

  SetDynArrayProp(Instance, String(PropInfo.Name), P);
end;

I took these functions directly from my project so I doupth that they will compile seperatly and these functions was designed to read record and array propertyes from file and then set to object

Marc:
This is more a FPC issue.
Create a small compilable project showing this problem without using LCL and submit a bugreport in our bugtracker (project=FPC)

Navigation

[0] Message Index

Go to full version