-2
uses RTTI;

type TMyRecord = packed record
  name : String[20];
  age  : Integer;
end;

type TMasterCtrl = packed record
  MyRecord: ^TMyRecord;  // Error can be avoided by changing to `MyRecord: Pointer;`
end;

procedure RTTIDump(Instance, ATypeInfo: Pointer; Memo: TStrings; NameWidth, FieldTypeWidth, ValueWidth: Integer; PaddingChar: Char);
var
  rType: TRTTIType;
  fields: TArray<TRttiField>;
  i: Integer;
begin
  rType := TRTTIContext.Create.GetType(ATypeInfo);
  Memo.Add(rType.ToString);
  fields := rType.GetFields;
  for i := 0 to High(fields) do
    Memo.Add(Format('%s: %s :: %s', [
      fields[i].Name.PadRight(NameWidth, PaddingChar),
      fields[i].FieldType.ToString.PadRight(FieldTypeWidth, PaddingChar),
      fields[i].GetValue(Instance).ToString.PadRight(FieldTypeWidth, PaddingChar) ]));
end;

procedure TForm3.Button2Click(Sender: TObject);
var
  myRecord    : TMyRecord;
  MasterCtrl: TMasterCtrl;
begin
myRecord.name := 'Fred Bloggs';
myRecord.age  := 23;

MasterCtrl.MyRecord := @myRecord;

RTTIDump(Addr(MasterCtrl), TypeInfo(TMasterCtrl), Memo1.Lines, 18, 18, 0, ' ');
end;

How to fix the access violation this code will create, still using pointer to record?

wittrup
  • 1,535
  • 1
  • 13
  • 23

2 Answers2

4

You need to use a proper type declaration for your pointer.

type
  PMyRecord =^TMyRecord;
  TMyRecord = packed record
  name : String[20];
  age  : Integer;
end;

type TMasterCtrl = packed record
  MyRecord: PMyRecord;  
end;
LU RD
  • 34,438
  • 5
  • 88
  • 296
1

As LU RD said, you have to declare a proper pointer type for TMyRecord to get the correct RTTI generated for the TMasterCtrl.MyRecord field, otherwise the field[s].FieldType property crashes because there is no type information to retreive.

type
  PMyRecord = ^TMyRecord; // <-- here
  TMyRecord = packed record
    name : String[20];
    age  : Integer;
  end;

  TMasterCtrl = packed record
    MyRecord: PMyRecord;  
  end;

That being said, there are two other problems with your code:

  1. fields[i].GetValue(@Instance)

    Instance already contains the address of the TMasterCtrl instance. By using @, you are passing the wrong address to GetValue(). You need to drop the @:

     fields[i].GetValue(Instance)
    
  2. do not call rType.Free. TRttiContext owns it and will free it for you.

Community
  • 1
  • 1
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770