Search code examples
delphidelphi-xe5

Need to get event parameters along with their respective types separately at run time in Delphi


I am using Delphi XE5.

I have am storing property and event names of provided Delphi VCL component using below code in an excel file.

procedure TForm1.Button1Click(Sender: TObject);
var
  PropInfo: PPropInfo;
  MyPTypeInfo : PTypeInfo;
  MyPPropList : PPropList;

  Count, I : Integer;
  PropOrEvent, PropValue : String;
  FileName : String;
begin
  FileName := 'C:\MyFile_Delphi.xlsx';
  ListBox1.Items.Clear;
  GetPropList(Button1,  MyPPropList);

  try
    Count := GetPropList(Button1,  MyPPropList);
    for I := 0 to Count - 1 do
    begin
      PropInfo := MyPPropList^[I];
      if PropInfo^.PropType^.Kind in tkMethods then
        PropOrEvent := 'Event'
      else
        PropOrEvent := 'Property';
      PropValue := VarToStr(GetPropValue(Button1, PropInfo^.Name));

      ListBox1.Items.Add(PropOrEvent + ' - ' + PropInfo^.Name);

    end;
  finally
    ListBox1.Items.SaveToFile(FileName);
    FreeMem(MyPPropList);
  end;
end;

But with this I also need every event parameter names along with their respective type like:

procedure TForm1.FormConstrainedResize(Sender: TObject; var MinWidth, MinHeight,
  MaxWidth, MaxHeight: Integer);
begin

end;

When I get this event name then at the same time, I need to get the result as :

Sender: TObject
MinWidth: Integer
MinHeight: Integer 
MaxWidth: Integer 
MaxHeight: Integer 

May be via running one more loop for this.

How to get this ?

Thanks in advance.


Solution

  • What you are asking for can be done with RTTI. Both old-style RTTI via the System.TypInfo unit, and newer-style Extended RTTI via the System.Rtti unit, contain enough information to do this.

    For example, using old-style RTTI:

    uses
      System.TypeInfo;
    
    procedure TForm1.Button1Click(Sender: TObject);
    type
      PPPTypeInfo := ^PPTypeInfo;
    var
      PropInfo: PPropInfo;
      MyPTypeInfo, MyParamPTypeInfo : PTypeInfo;
      MyPTypeData: PTypeData;
      MyPPropList : PPropList;    
      Count, I : Integer;
      J: Byte;
      PropOrEvent, PropValue : String;
      FileName : String;
      Ptr: PByte;
      ParamName: String;
      TypeName: String;
    begin
      FileName := 'C:\MyFile_Delphi.xlsx';
      ListBox1.Items.Clear;
    
      Count := GetPropList(Button1, MyPPropList);
      try
        for I := 0 to Count - 1 do
        begin
          PropInfo := MyPPropList^[I];
          if PropInfo^.PropType^.Kind in tkMethods then
            PropOrEvent := 'Event'
          else
            PropOrEvent := 'Property';
    
          ListBox1.Items.Add(PropOrEvent + ' - ' + PropInfo^.Name);
    
          //...
    
          if PropInfo^.PropType^.Kind in tkMethods then
          begin
            MyPTypeData := GetTypeData(PropInfo^.PropType^);
            {
            tkMethod: (
              MethodKind: TMethodKind; // only mkFunction or mkProcedure
              ParamCount: Byte;
              ParamList: array[1..ParamCount] of
                record
                  Flags: TParamFlags;
                  ParamName: ShortString;
                  TypeName: ShortString;
                end;
              ResultType: ShortString; // only if MethodKind = mkFunction
              ResultTypeRef: PPTypeInfo; // only if MethodKind = mkFunction
              CC: TCallConv;
              ParamTypeRefs: array[1..ParamCount] of PPTypeInfo;
              MethSig: PProcedureSignature;
              MethAttrData: TAttrData);
            }
            Ptr := PByte(@MyPTypeData^.ParamList);
            if MyPTypeData^.ParamCount > 0 then
            begin
              for J := 0 to MyPTypeData^.ParamCount-1 do
              begin
                Inc(Ptr, SizeOf(TParamFlags));
                ParamName := PShortString(Ptr)^;
                Inc(Ptr, 1 + Integer(Ptr^));
                TypeName := PShortString(Ptr)^;
                Inc(Ptr, 1 + Integer(Ptr^));
                // use ParamName and TypeName as needed...
              end;
            end;
            if MyPTypeData^.MethodKind = mkFunction then
            begin
              Inc(Ptr, 1 + Integer(Ptr^));
              Inc(Ptr, SizeOf(PPTypeInfo));
            end;
            Inc(Ptr, SizeOf(TCallConv));
            if MyPTypeData^.ParamCount > 0 then
            begin
              for J := 0 to MyPTypeData^.ParamCount-1 do
              begin
                MyParamPTypeInfo := PPPTypeInfo(Ptr)^;
                // use MyParamPTypeInfo as needed...
                Inc(Ptr, SizeOf(PPTypeInfo));
              end;
            end;
          end;
        end;
      finally
        FreeMem(MyPPropList);
      end;
    
      ListBox1.Items.SaveToFile(FileName);
    end;
    

    Using Extended RTTI:

    uses
      System.TypInfo, System.Rtti;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Ctx: TRttiContext;
      MyProp: TRttiProperty;
      MyParam: TRttiParameter;
      PropOrEvent, PropValue : String;
      FileName : String;
    begin
      FileName := 'C:\MyFile_Delphi.xlsx';
      ListBox1.Items.Clear;
    
      for MyProp in Ctx.GetType(Button1.ClassType).GetProperties do
      begin
        if MyProp.PropertyType.TypeKind in tkMethods then
          PropOrEvent := 'Event'
        else
          PropOrEvent := 'Property';
    
        ListBox1.Items.Add(PropOrEvent + ' - ' + MyProp.Name);
    
        //...
    
        if MyProp.PropertyType.TypeKind in tkMethods then
        begin
          for MyParam in (MyProp.PropertyType as TRttiMethodType).GetParameters do
          begin
            // use MyParam.Name and MyParam.ParamType as needed...
          end;
        end;
      end;
    
      ListBox1.Items.SaveToFile(FileName);
    end;