需要在Delphi中分别在运行时获取事件参数及其各自的类型

时间:2016-02-26 09:11:51

标签: delphi delphi-xe5

我正在使用Delphi XE5。

我使用以下代码在excel文件中存储提供的Delphi VCL组件的属性和事件名称。

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;

但是有了这个,我还需要每个事件参数名称以及它们各自的类型,如:

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

end;

当我同时获得此事件名称时,我需要将结果显示为:

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

可以通过为此运行一个循环。

如何获得这个?

提前致谢。

1 个答案:

答案 0 :(得分:0)

您要求的是RTTI可以做到的。通过System.TypInfo单元的旧式RTTI和通过System.Rtti单元的新式扩展RTTI都包含足够的信息来执行此操作。

例如,使用旧式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;

使用扩展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;