0

I have written a c++ dll, which allows me to register a callback function from the main application. This is the according code in the dll:

extern "C"   {
typedef void(__stdcall* callbackRead_t)(UCHAR* Buffer, ULONG* BufferSize);
static callbackRead_t s_user_functionRead = nullptr; // variable used to store the user function address

__declspec(dllexport) void public_readfunc_taking_callback(callbackRead_t evHnd)
{
    s_user_functionRead = evHnd; // save the callback address for funcA.
}
}

In the main application I register the callback like this:

typedef void(__stdcall *TeventReadHS)(unsigned char* Buffer, unsigned long* BufferSize);
typedef void(__stdcall *eventReadHS)(TeventReadHS eveHnd);

void __stdcall ReadHSCallBack(unsigned char* Buffer, unsigned long* NumRead){
//do something
}

void __stdcall RegisterReadBack(void){
   eventReadHS valr;
   HINSTANCE handleHSC;

   handleHSC=LoadLibrary(L"HSC.dll");
   if (!handleHSC){
     //Error handling here
       }     
   valr=(eventReadHS)GetProcAddress(handleHSC,"public_readfunc_taking_callback");
   if(valr!=NULL){
       valr(&ReadHSCallBack);
       }
}

That works without a problem. But Now I want ReadHSCallBack to be a member of a class, Form1. So I changed that to the following:

class TForm1: public TForm
{
 //a lot of other stuff here
 public:
  __fastcall TForm1(TComponent* Owner);
 void __fastcall TForm1::RegisterReadBack(void);
  void __stdcall TForm1::ReadHSCallBack(unsigned char* Buffer, unsigned long* NumRead);
 };

RegisterReadback also gets a member of Form1:

void __fastcall TForm1::RegisterReadBack(void){
   eventReadHS valr;
   HINSTANCE handleHSC;

   handleHSC=LoadLibrary(L"HSC.dll");
   if (!handleHSC){
     //Error handling here
       }     
   valr=(eventReadHS)GetProcAddress(handleHSC,"public_readfunc_taking_callback");
   if(valr!=NULL){
       valr(&ReadHSCallBack);
       }
}

And here we go: it doesn't compile. The line causing the error is

 valr(&ReadHSCallBack);

Error statement is: [bcc32 Error] Main.cpp(11422): E2034 Conversion of 'void (__stdcall * (_closure )(unsigned char *,unsigned long *))(unsigned char *,unsigned long *)' to 'void (__stdcall *)(unsigned char *,unsigned long *)' not possible.

I don't have any clue how to deal with that __closure statement. I also tried valr(&this->ReadHSCallBack) that also doesn't help.

Bodo
  • 15
  • 5
  • You can use non-static member functions as callbacks because (a) they are not simple function pointers and (b) they need an object to be called on. – Richard Critten Apr 30 '21 at 11:57

1 Answers1

0

Rather than using function pointers, can you use std::function?

I do callbacks to class methods all the time, although I use lambdas for it. Here's one example:

typedef std::function<void(const char *)> CallbackFunction;

Here's a way of passing something that fits that signature:

vec.addArg("port", [&](const char *arg){ port = atoi(arg); }, "p", "Set listen port. Default is 9300.");

So far, this is cut & paste of actual code from the program I'm currently working on. The lambda can do anything, so I could do this:

vec.addArg("port", [=](const char *arg){ foo(arg); });

Note that I used = for this instead of &.

You can do the whole std::bind() thing, but I find that ugly and would rather pass a lambda.

Using C-style function pointers is very C-like, and C++ programmers should use modern methods. This means std::function and possibly lambdas.

Joseph Larson
  • 8,530
  • 1
  • 19
  • 36
  • Hi Joseph, unfortunately the IDE I use isn't modern... it even doesn't support std::function. According to this https://stackoverflow.com/a/7132549/9368347 it uses an pre c++98 standard. It is the Embarcadero C++Builder 10.1. Unfortunately I don't have additional updates, the new version already uses c++17. I wanted to get rid of the c++builder for so long that I hesitated to buy further updates. Are there any "classic" ways to do it? – Bodo Apr 30 '21 at 15:47
  • First, it isn't a matter of what your IDE supports. What does your compiler support? That being said, is there some reason you're tied to an ancient development environment? Are you coding for a really archaic platform? If so, then I'm not sure what to tell you. I would have switched IDEs a long time ago. – Joseph Larson May 01 '21 at 16:04