Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

non-member function pointer as a callback in API to member function

I'm using an API that requires me to pass a function pointer as a callback. I'm trying to use this API from my class in C++ but I'm getting compilation errors.

The API definition is:

typedef void (__stdcall *STREAM_CALLBACK)(void *userdata);

__declspec(dllimport) int __stdcall set_stream_callback(
    STREAM_CALLBACK streamCB, void *userdata);

One example file, provided by the third party, is:

void __stdcall streamCB(void *userdata)
{
  // callback implementation
}

int main(int argc, const char argv[])
{
  int mid = 0;
  set_stream_callback(streamCB, &mid);
}

And that works fine. However when I try to use that in a class, I have an error:

error C3867: 'MyClass::streamCB': function call missing argument list; use '&MyClass::streamCB' to create a pointer to member

The suggestion to use

&MyClass::streamCB

doesn't work. I understood that the set_stream_callback only accepts a non-member function.

The problem is very similar to How can I pass a class member function as a callback? in which Johannes makes a concise suggestion, however I do not understand it very well. Could anyone expand a bit, if I am correct that it is relevant to this question?

I have tried:

void __stdcall MyClass::streamCB(void *userdata)
{
  // callback implementation
}

static void MyClass::Callback( void * other_arg, void * this_pointer ) {
    MyClass * self = static_cast<ri::IsiDevice*>(this_pointer);
    self->streamCB( other_arg );
}

//and in the constructor
int mid = 0;
set_stream_callback(&MyClass::Callback, &mid);

But

error C2664: 'set_stream_callback' : cannot convert parameter 1 from 'void (__cdecl *)(void *,void *)' to 'STREAM_CALLBACK'

How do I get around this?


Edit1: Also, I want to use userdata inside the streamCB callback.

like image 695
Hugues Fontenelle Avatar asked Dec 03 '25 12:12

Hugues Fontenelle


1 Answers

The idea of calling a member function from a callback taking only non-member functions is to create a wrapper for you member function. The wrapper obtains an object from somewhere and then calls the member function. If the callback is reasonably well designed it will allow you to pass in some "user data" which you'd use to identify your object. You, unfortunately, left out any details about your class so I'm assuming it looks something like this:

class MyClass {
public:
    void streamCB() {
         // whatever
    }
    // other members, constructors, private data, etc.
};

With this, you can set up your callback like so:

void streamCBWrapper(void* userData) {
    static_cast<MyClass*>(userData)->streamCB()
}

int main() {
    MyClass object;
   set_stream_callback(&streamCBWrapper, &object);
   // ...
}

There are various games you can play with how to create the streamCBWrapper function (e.g., you can make it a static member of your class) but all come down to the same: you need to restore your object from the user data and call the member function on this object.

like image 65
Dietmar Kühl Avatar answered Dec 06 '25 02:12

Dietmar Kühl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!