Jump to content
  • Advertisement
Sign in to follow this  
SyncViews

Calling class methods from C callback

This topic is 2636 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

A number of C interfaces use callback functions via a function pointer. e.g.
[source lange="cpp"]
void foo(int (*callback)(int a, int b, void *user), void *user, char c, int x)
[/source]

Many of these have soem kind of user parameter that the function takes, and gives to the callback function each time its called, which I can thus use to hold my object pointer, and a simple wrapper function
[source lange="cpp"]
void my_foo_callback(int a, int b, void *user)
{
((MyClass*)user)->foo_callback(a,b);
}
[/source]

However every now and then I come across an interface that doesnt provide such functionality.
[source lang="cpp"]
void bar(int (*callback)(int a, int b), char c, int x)
[/source]

Is there a way to still use class instances with these API's? Could I basically generate a wrapper function like below at runtime (idealy with standard C++ or at least avoiding things like the intel instruction set reference)?
[source lange="cpp"]
void my_generated_bar_callback_0005AF10(int a, int b)
{
((MyClass*)0x0005AF10)->bar_callback(a,b);
}
[/source]

Share this post


Link to post
Share on other sites
Advertisement
Member functions always have a hidden parameter that holds the this-pointer, so the calling convention is entirely different and incompatible to the free functions. If you have no means of actually obtaining a pointer to an object, you just cannot call a member function.

As you said, you can often pass the object as a user-parameter that you can cast to a pointer to the object. But if you have no such parameter, you still have other options. For example, you can use a global variable to hold the object, or a global pointer that points to the object, and then use the same idiom as before, but you use the global instead of the parameter. You can, however, basically only have one object active then. If your design allows for that limitation, then perhaps your object is just better of as a name space, or the callback is better of as a static function (because you only have one set of states you can use anyway) so you can use the function without an intermediate function.

Share this post


Link to post
Share on other sites

Is there a way to still use class instances with these API's? Could I basically generate a wrapper function like below at runtime (idealy with standard C++ or at least avoiding things like the intel instruction set reference)?
[source lange="cpp"]
void my_generated_bar_callback_0005AF10(int a, int b)
{
((MyClass*)0x0005AF10)->bar_callback(a,b);
}
[/source]


Yes, it can be done. I believe the usual term for this is a "dynamic thunk table." Basically the idea is you create a scratch space in memory that holds hand-generated machine code; for every possible this-pointer that you want to support callbacks on, you create a new thunk function in your scratch space. That function simply does exactly what your code suggests: injects a hard-coded this-pointer into the call and invokes the appropriate class member function.

I've done this before a few times and it is very tricky to get right, and is far from portable. There is not a way to do this in standard C++, nor is there a way to do it that can easily be supported by multiple compilers or OSes. The best I can do is link you to this (look for the callback-related stuff, everything connected to marshaling data you can ignore), which shows how to do it for 32-bit Windows using the Visual C++ compiler. Maybe that can get you started.

Honestly, though, if you're in the FB forum, you may not want to dive down this rabbit hole ;-)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!