A r t i c l e s
Navigation

Note: This site is
a bit older, personal views
may have changed.

M a i n P a g e

D i r e c t o r y

Procedure Bound To Method Without RTTI Hack


On the Regular Procedure Bound To Class Method page I showed how to bind a procedure to a class method, but it used RTTI tricks. The reason I was using RTTI tricks was because I couldn't figure out the syntax to get a pointer to a method or the method address. There is a way, and I found it, without using the RTTI.

(And who am I patronizing here? How many of you reading this article know about these hacks? You might be thinking.. what is the purpose, or this just academic nonsense? Well I have some dirty plans on how to use these tricks to get Synedit working as a plugin without actually using packages and without making procedural wrappers. Many synedit methods can be exported from a DLL directly using these tricks, for example.

I have a few delphi apps with TMemo's and TSynedit's in them.. and in order for people to build DLL plugins using fpc/delphi/c++/c cross, the components need to be connectable in a cross compiler compatible way. Procedural wrappers and API's work too.. but these tricks below allow us to take a shortcut and reduce the amount of wrapping needed. All we have to do is simply bind procedures to the classes. Yes, it is a bit of work, but less work than making full fledged wrappers and API's.)

program test36; {$mode objfpc} {$H+}

type 
  Tx = class
    procedure p;
    procedure test(i: integer);
  private
    s: string;
  end;

procedure Tx.p;
begin
  writeln('proc test 1');
  self.s:= 'hello ';
  self.s:= 'hello ' + s + s;
  writeln(self.s);
end;

procedure Tx.test(i: integer);
begin
  writeln('proc test 2');
  self.s:= 'hello ';
  self.s:= 'hello ' + s + s + ' see number: ';
  writeln(self.s, i);
end;

var 
  x: Tx;
  p: procedure(fakeself: pointer);  // normally we would need procedure OF OBJECT
                                    // the pointer acts as our object SELF

  // alternatively, we don't have to use ugly pointer.. use Tx
  test: procedure(fakeself: Tx; i: integer);  

begin
  x:= Tx.create;
  pointer(p):= @Tx.p;
  pointer(test):= @Tx.test; // @Tx.test is weird syntax, but no RTTI

  if assigned(p) then 
  begin
    p(pointer(x));  // call a regular procedure and not 'of object'? Magic.
    test(x, 600);   // again, we use regular procedure with hidden SELF param
  end else 
    writeln('unassigned');
  x.free;
  readln;
end.

So consider a DLL. With this system you can decide which methods you want to export.. you are in full control. You can hide methods that you don't want visible to the DLL by simply not giving people access to the method pointer (or the entire instance pointer).

Only problem is getting the address of PRIVATE methods, for example ones that link to an objects properties. Some tricks can be used to gain access to private methods, or you can even just make all methods public (yes, against OOP, but hey, we are adults not children). Since making methods public would mean patching lots of source units and making code less safe I'm studying other solutions.

About
This site is about programming and other things.
_ _ _