views:

173

answers:

2

I'm writing a control that should be able to display any list of data. What I wanted to do, was to mimic the for-in construct in that I check for a public GetEnumerator function that contain a Current property and a MoveNext method.

I've determined the following:

  1. I can check the existance of a method by simply calling MethodAddress on my object. If I get the address, the method exists.
  2. I can use RTTI to check the return type of the method.
  3. I can use RTTI to check for the property and to read it.

In-between though, I am missing little bits of info:

  1. How do I call the method, given its address? Do I just write a definition (like I would for imports), cast the address and call it?
  2. Checking the return type of the method requires calling GetTypeData with its PTypeInfo. I get the PTypeInfo by calling TypeInfo on a type. So how do I get a PTypeInfo for a given method, given only its address?
+1  A: 

At first, note that RTTI is only available for published properties and methods.

To call the method retrieved by MethodAdress, just do:

TMyMethod = procedure (Self : TObject; const Param : String);
...
var
  MyMethod : TMyMethod;
...
MyMethod := Obj.MethodAdress ('MethodName');
if Assigned (MyMethod) then
  MyMethod (Obj, 'Hallo');

Concerning your second question, this might help:

Link

Smasher
Cool, I'll give this a bash. I saw that MethodAddress gives back a Pointer and assumed that would be a code-only pointer. So what, is it just assignment-compatible with TMethod since the data pointer is available (Obj in your example)?
Cobus Kruger
Sorry, I missed something. Edited the answer.
Smasher
+2  A: 
  1. To call the method, you take the returned address and put it into the Code pointer of a TMethod. Put the object into the Data pointer, and then cast it to a method pointer with the right signature.
  2. To analyze the signature of a function, you need some pretty complicated RTTI. See http://hallvards.blogspot.com/2006/05/hack-10-getting-parameters-of.html for the details. But note the caveat towards the bottom:

Note that this only works if the instance (or one of its components) also has a published property that points to the published method. The good news is that this is the case for most existing published methods – such as the event handlers on a TForm instance. The bad news is that this would not be the case for any published methods we would like to call dynamically at runtime (and thus would not be assigned to any events).

So what you're trying to do may not be possible under the current RTTI model. But Delphi 2010 is supposed to have an expanded RTTI system that will enable you to do stuff like that a lot more easily, and it's due out RSN. (There used to be a release countdown on Embarcadero's site that was counting down towards midnight tonight. They've taken it down, though, so I'm not sure if that's still the official release date or not.)

Mason Wheeler
Yeah, your answer in point 1 is the variant on Smasher's answer that I got working (before he edited it). And you're absolutely right - I'm out of luck until Delphi 2010 comes out. Sadly, that is guaranteed to be too late for me.I'm accepting your answer, but I think I'm going to use a workaround involving anonymous methods. If I get it working, I'll show it here.
Cobus Kruger