RAD Studio |  |

How to Handle Delphi Anonymous Methods in C++
See Also
Collapse All

This topic describes some programming issues that you might encounter when dealing with anonymous methods, one of Delphi's newest features.

Under the cover, Delphi implements anonymous methods types (also known as method references) via an interface that implements an Invoke(...) method. So a method that takes a method reference parameter in Delphi is exposed to C++ as a method that takes an interface. Here's an example:

Copy Code

    interface

    type

      TRefProc = reference to function (I, J: Integer): Integer;

      TTestClass = class
        public
          function TakeRefProc(RefProc: TRefProc; I, J: Integer): Integer;
      end;

The following is the .hpp file generated for the above:

Copy Code

    __interface TRefProc;
    typedef System::DelphiInterface <TRefProc> _di_TrefProc;

    __interface TRefProc  : public System::IInterface
    {
    public:
     virtual int __fastcall Invoke(int I, int J) = 0 ;
    };

    class PASCALIMPLEMENTATION TTestClass : public System::TObject
    {
    public:
     int __fastcall TakeRefProc(_di_TRefProc RefProc, int I, int J);
    };

C++ code that seeks to specify a function or member function as a method reference parameter has to wrap the latter behind an interface that exposes an Invoke() method. A C++ template can be used to encapsulated such an interface. The following C++ code shows an example of a template that can be used to pass C++ methods or member functions as method references to Delphi.

Copy Code

    enum _DummyType{};      // Parameter used as default

    template <typename INTF,                       // Interface with Invoke
                    typename F,                            // Function type
                    typename R,                           // Return type
                    typename P1 = _DummyType,  // Param #1
                    typename P2 = _DummyType,  // Param #2
                    typename P3 = _DummyType,  // Param #3
                    typename P4 = _DummyType,  // Param #4
                    typename P5 = _DummyType> // Param #5
    class TMethodRef : public TInterfacedObject, public INTF

    {
    private:
      F callback;
    public:
      TMethodRef(F _callback) : callback(_callback) {}

      HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject)
      { return TInterfacedObject::QueryInterface (riid, ppvObject); }
      ULONG STDMETHODCALLTYPE AddRef()
      { return TInterfacedObject::_AddRef(); }
      ULONG STDMETHODCALLTYPE Release()
      { return TInterfacedObject::_Release(); }

    R __fastcall Invoke(P1 p1)
      {
        return callback(p1);
      }
      R __fastcall Invoke(P1 p1, P2 p2)
      {
        return callback(p1, p2);
      }
      R __fastcall Invoke(P1 p1, P2 p2, P3 p3)
      {
        return callback(p1, p2, p3);
      }
      R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4)
      {
        return callback(p1, p2, p3, p4);
      }
      R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
      {
        return callback(p1, p2, p3, p4, p5);
      }
    };

The following code shows how to use the template shown above to pass a C++ routine as a method reference.

Copy Code

    // C++ function we want to pass as a method reference.
    int multiplyCallback(int i, int j)
    {
      return i*j;
    }

    void UseRefProcFlat()
    {
      std::auto_ptr<TTestClass> cls(new TTestClass());
      _di_TRefProc proc = new TMethodRef<TRefProc, int (*)(int, int), int, int, int>(multiplyCallback);
      int i = cls->TakeRefProc(proc, 10, 20);
      assert(i == 200);
    }

You can also use the template to pass a member function as a method reference. The following code illustrates this:

Copy Code

    class TMyClass {
    public:
      int add(int i, int j) {
        return i+j;
      }
    };
    typedef int (__closure *TClosure)(int, int);

    void UseRefProcMember()
    {
      TMyClass myClass;

      std::auto_ptr<TTestClass> cls(new TTestClass());
      _di_TRefProc proc = new TMethodRef<TRefProc, TClosure, int, int, int>(&myClass.add);

      int i = cls->TakeRefProc(proc, 10, 20);
      assert(i == 30);
    }

See Also

Handling Generics

Handling AnsiString Code Page Specification

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!