问题
So, I'm using the FMOD api and it really is a C api.
Not that that's bad or anything. Its just it doesn't interface well with C++ code.
For example, using
FMOD_Channel_SetCallback( channel, callbackFunc ) ;
It wants a C-style function for callbackFunc
, but I want to pass it a member function of a class.
I ended up using the Win32 trick for this, making the member function static. It then works as a callback into FMOD.
Now I have to hack apart my code to make some of the members static, just to account for FMOD's C-ness.
I wonder if its possible in FMOD or if there's a work around to link up the callback to a specific C++ object's instance member function (not a static function). It would be much smoother.
回答1:
You cannot directly pass a member function. A member function has the implicit parameter this
and C functions don't.
You'll need to create a trampoline (not sure the signature of the callback, so just doing something random here).
extern "C" int fmod_callback( ... args ...)
{
return object->member();
}
One issue is where does that object pointer come from. Hopefully, fmod gives you a generic context value that will be provided to you when your callback is made (you can then pass in the object pointer).
If not, you'll just need to make it a global to access it.
回答2:
I guess it supposed to work like this:
You can assign some user data to channel by calling FMOD_Channel_SetUserData
. This user data should be a pointer to your C++ object that handles events.
Then you should write C-style callback that extracts that object by calling FMOD_Channel_GetUserData
and then calls your C++ instance method on that object.
回答3:
There is a non-portable, and pretty hackish solution that has the advantage of at least being thread-safe, which the "trampoline" methods are not.
You can generate the actual function machine code on the fly. The basic idea is that you have a template for your call-back function that takes an object pointer and a member-function pointer and gives you a block of heap memory that you can pass to the library as a C call-back function, that will, when called, turn around and call the member function on that object.
It's messy, and you'll have to provide an implementation for any new platform (any time the calling convention changes), but it works, is thread-safe. (Of course you'll also have to watch out for DEP). The other thread-safe solution is to resort to thread-local storage (assuming that you know the call-back will happen on the same thread as the call you made).
See http://www.codeproject.com/KB/cpp/GenericThunks.aspx for an example of how you could go about generating thunks.
回答4:
Using only a function pointer (and no additional separate object pointer) for a C callback is a broken design, in my humble opinion.
If the function were, instead, FMOD_Channel_SetCallback(channel, callbackFunc, callbackObj)
, then your static method just takes an instance of the object, then calls callbackObj->func()
(which obviously can be non-static).
回答5:
you need to use a trampoline and store the pointer to the object you want to get the member function called on in a global or static variable, i.e.
Object *x;
void callback_trampoline() { x->foobar(); }
...
FMOD_Channel_SetCallback(CHANNEL, callback_trampoline);
来源:https://stackoverflow.com/questions/2420346/c-api-function-callbacks-into-c-member-function-code