2

First off, forgive me on the title. Not really sure how to ask this question:

I have an application that I need to convert to a console application (note the application runs fine as a VCL style windows app). The app uses a few 3rd party widgets that have callback functions. However, when I attempt to compile it, I get 'cannot convert ...' errors, like this:

Cannot convert 'void(Tobject *, TErrorEventParams *)' to 'TErrorEvent'

TErrorEvent is defined as:

typedef void __fastcall (__closure* TErrorEvent)(System::TObject* Sender, TErrorEventParams *e);

The line causing the error is:

handler->OnError = errorHandler;

The code for errorHandler is:

void __fastcall errorHandler(System::TObject* Sender, TErrorEventParams *e)
{
    memoLine = e->Description;
    updateLog();
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Brian P.
  • 206
  • 3
  • 14
  • Possible duplicate of [Use a non-class member as an event handler](https://stackoverflow.com/questions/43870540/use-a-non-class-member-as-an-event-handler) – Remy Lebeau Mar 16 '18 at 22:20
  • Possible duplicate of [Create TNotifyEvent in C++ for use at Application level](https://stackoverflow.com/questions/7193174/) – Remy Lebeau Mar 16 '18 at 22:21

2 Answers2

4

A __closure type is a pointer to a non-static class method. The compiler does not allow you to assign a standalone non-class function where a __closure is expected. It requires a pointer to a method of a class object. Karem's answer shows you one way to accomplish that.

However, there IS a way to use a non-class function, using the helper TMethod struct (which is how a __closure is implemented behind the scenes).

First, add an explicit 'this' parameter to your event handler:

void __fastcall errorHandler(void *This, TObject* Sender, TErrorEventParams *e)
{
    memoLine = e->Description;
    updateLog();
}

And then assign the event handler like this:

TMethod m;
m.Code = &errorHandler
m.Data = NULL; // any value you want to pass to the 'This' parameter...
handler->OnError = reinterpret_cast<TErrorEvent&>(m);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

Have a look at this documentation:

http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Closure

In short:

TErrorEvent is defined as a pointer to a class member function. So errorHandler has to be declared as a class member function.

The implementation could look somewhat like this:

class TMyClass
{
private:
    TMyHandler* handler;
    void __fastcall errorHandler(System::TObject* Sender, TErrorEventParams *e);
public:
    __fastcall TMyClass();
} my_dummy_class;

__fastcall TMyClass::MyClass()
{
    //handler has to be created
    handler->OnError = errorHandler; 
}

void __fastcall TMyClass::errorHandler(System::TObject* Sender, TErrorEventParams *e)
{
    memoLine = e->Description;
    updateLog();
}
Spektre
  • 49,595
  • 11
  • 110
  • 380
Kerem
  • 429
  • 5
  • 20
  • Yes that was what I had in mind. Btw. do not forget to declare at least one variable of the class type otherwise the code would be optimized out completely as unused (I added it to your code already) – Spektre Mar 17 '18 at 09:00
  • The answer about using TMethod is what I needed. I didn't make it clear that there was no class structure (I thought saying it was a console app would be enough). – Brian P. Mar 19 '18 at 14:36