notricky
notricky

Reputation: 179

Is it possible to get components' method value (means name)?

I need to get a name of a component (TButton), that is being assigned in design-time and is seen in Object Inspector (such as Button1Click at Button1.OnClick event on events tab).

I use now TypInfo unit to get method's information via PPropInfo and I get OnClick and TNotifyEvent strings as values, but I didn't get the Button1Click as string value.

How can I get it?

Upvotes: 1

Views: 1954

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595827

If the property and assigned method are both published, you can use this:

uses
  TypInfo;

function GetEventHandlerName(Obj: TObject; const EventName: String): String;
var
  m: TMethod;
begin
  m := GetMethodProp(Obj, EventName);
  if (m.Data <> nil) and (m.Code <> nil) then
    Result := TObject(m.Data).MethodName(m.Code)
  else
    Result := '';
end;

s := GetEventHandlerName(Button1, 'OnClick');

The TypInfo unit (where GetMethodProp() comes from) only supports published properties.

You have to specify the object that owns the method address because TObject.MethodName() iterates the object's VMT. And the method must be published because TObject.MethodName() (which exists to facilitate DFM streaming) iterates a portion of the VMT that is filled only with the addresses of published methods.

If you are using Delphi 2010 or later, you can use Extended RTTI instead, which does not have the published limitations:

uses
  Rtti;

function GetEventHandlerName(Obj: TObject; const EventName: String): String;
type
  PMethod = ^TMethod;
var
  ctx: TRttiContext;
  v: TValue;
  _type: TRttiType;
  m: TMethod;
  method: TRttiMethod;
  s: string;
begin
  Result := '';
  ctx := TRttiContext.Create;
  v := ctx.GetType(Obj.ClassType).GetProperty(EventName).GetValue(Obj);
  if (v.Kind = tkMethod) and (not v.IsEmpty) then
  begin
    // v.AsType<TMethod>() raises an EInvalidCast exception
    // and v.AsType<TNotifyEvent>() is not generic enough
    // to handle any kind of event. Basically, the Generic
    // parameter of AsType<T> must match the actual type
    // that the event is declared as.  You can use
    // TValue.GetReferenceToRawData() to get a pointer to
    // the underlying TMethod data...
    m := PMethod(v.GetReferenceToRawData())^;
    _type := ctx.GetType(TObject(m.Data).ClassType);
    for method in _type.GetMethods do
    begin
      if method.CodeAddress = m.Code then
      begin
        Result := method.Name;
        Exit;
      end;
    end;
  end;

s := GetEventHandlerName(Button1, 'OnClick');

Upvotes: 4

Sertac Akyuz
Sertac Akyuz

Reputation: 54792

string := MethodName(GetMethodProp(Button1, 'OnClick').Code);

Note that the method needs to be 'published'.

Upvotes: 6

Related Questions