eventhandlerc++builder-10.1-berlin

Use a non-class member as an event handler


I'm writing a DLL wrapper to a C++Builder VCL class. This is an extremely simplified example of the problem:

typedef void __fastcall (__closure *TMyEvent)(int index);

class TMyClass {
  public:
    TMyEvent OnMyEvent;
};

void __fastcall myEventHandler(int index) { }

TMyClass myClass;
myClass.OnMyEvent = myEventHandler;

...and here is the problem:

Normally myEventHandler is defined inside another class, but here it is defined as a global function. When I try to assign myEventHandler to myClass.OnMyEvent I get an error

Cannot convert void(int) to TMyEvent

I reuse the TMyClass to generate different kind of wrappers and need the __closeure in the typedef so it works well with VCL form projects.

Is the __closure the problem? Can I use a global function as an event handler at all?


Solution

  • The __closure compiler extension is a special type of class method pointer that holds two pointers - a pointer to an object instance, and a pointer to the handler method. When the __closure is executed, the compiler passes the object pointer to the handler via its this parameter. As such, the handler MUST have a this parameter.

    If the handler is a non-static member of a class, the this pointer is handled implicitly by the compiler for you, eg:

    class TMyEvents {
    public:
        void __fastcall myEventHandler(int index) { }
    };
    
    TMyClass myClass;
    TMyEvents myEvents;
    myClass.OnMyEvent = myEvents.myEventHandler;
    

    If the handler is a standalone function, or is a static method of a class, then the this pointer must be provided in the parameter list explicitly. In this situation, you can use the TMethod1 struct to help you assign the handler to the event, eg:

    void __fastcall myEventHandler(void *Data, int index) { }
    
    TMethod m;
    m.Data = ...; // can be anything you want to pass to the 'Data' parameter
    m.Code = &myEventHandler;
    
    TMyClass myClass;
    myClass.OnMyEvent = reinterpret_cast<TMyEvent&>(m);
    

    1: this only works with __closure! Don't try to use it with other types of function pointers.