Jump to content
Kryvich

How to obtain the value of a field of type TWndMethod via RTTI?

Recommended Posts

I can do it without RTTI, but get a compiler error when using RTTI:

procedure TForm1.Button1Click(Sender: TObject);
var
  ctx: TRttiContext;
  rt: TRttiType;
  fld: TRttiField;
  proc: TWndMethod;
begin
  proc := TabSet1.WindowProc; // Compiles and works OK without RTTI
  ctx := TRttiContext.Create;
  try
    rt := ctx.GetType(TControl);
    fld := rt.GetField('FWindowProc');
    ShowMessage(fld.GetValue(TabSet1).TypeInfo.Name); // 'TWndMethod'
    if fld.GetValue(TabSet1).IsType<TWndMethod> then    // True
      proc := fld.GetValue(TabSet1).AsType<TWndMethod>;
      // E2010 Incompatible types: 'procedure, untyped pointer or untyped parameter' and 'TWndMethod'
  finally
    ctx.Free;
  end;
end;

Any suggestions?

Share this post


Link to post

But will this be the right solution? These types have different sizes (tested for Win32):

  if SizeOf(Pointer) <> SizeOf(TWndMethod) then
    ShowMessage('No way.');  // 4 <> 8

I tried this:

var
  i64: UInt64;
...
    i64 := fld.GetValue(TabSet1).AsUInt64;
    proc := TWndMethod(i64);

But get Exception EInvalidCast 'Invalid class typecast' for GetValue.AsUInt64.

 

Update. I did it like this:

var
  p: Pointer;
...
    p := fld.GetValue(TabSet1).GetReferenceToRawData;
    proc := TWndMethod(p^);

Thanks @Lars Fosdal for the hint!

Edited by Kryvich
  • Like 1

Share this post


Link to post

Remember that a pointer-to-class-method, such as TWndMethod, is represented by the RTL's TMethod record, which contains 2 pointers - a pointer to an object instance, and a pointer to the method code.

 

TValue.AsUInt64 fails for a TWndMethod value because TValue supports only conversions that the compiler natively supports implicitly, and you can't implicitly assign a TMethod to a UInt64 and vice versa.  That also explains why the TValue.GetReferenceToRawData() approach works - it is just returning a raw pointer to the actual TControl.FWndMethod instance member, which is then dereferenced when being assigned to the local TWndMethod variable.  So, no conversion occurs.

 

Now, why TValue.AsType<TWndMethod> fails to compile, I don't know.  Sounds like a bug.

 

Share this post


Link to post
6 hours ago, Remy Lebeau said:

Now, why TValue.AsType<TWndMethod> fails to compile, I don't know.  Sounds like a bug.

It probably is lacking the `()` there which it sometimes needs when invoking a method that returns an invokable type.

  • Like 3

Share this post


Link to post

@Stefan Glienke Just checked your suggestion, brilliantly!

      proc := fld.GetValue(TabSet1).AsType<TWndMethod>();

No compiler errors.

  • Thanks 2

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×