If you use MSVC and target x86-32 (not x86-64), you can use the __stdcall convention for the member function. (__cdecl works too)
With __stdcall this will be passed as the first parameter, so you can write
typedef void(__stdcall *callback_t)(void* arg); void set_callback(callback_t callback, void* callbackParameter); struct Foo { int x; void __stdcall someCallback() { this->x = 1; } };
but
Foo foo; set_callback((callback_t)&Foo::someCallback, this);
Will not work: you cannot directly point to a pointer to a pointer to a pointer according to the standard. You must use a workaround to do this:
First, assert that & Foo :: someCallback is the same size as void *
static_assert(sizeof(&Foo::someCallback) == sizeof(void*), "");
This statement may fail if there can be multiple inheritance, and someCallback virtual. To prohibit multiple inheritance, use the __single_inheritance keyword:
struct __single_inheritance Foo { };
Secondly, you should use & Foo :: someCallback for callback_t using
union { void(__stdcall Foo::*src)(); callback_t dst; } u = {&Foo::someCallback}; set_callback(u.dst, this);
or
void(__stdcall Foo::*temp)() = &Foo::someCallback; set_callback(*(callback_t*)&temp, this);
It only works if you can pass this one for the callback as the first parameter.
If you cannot, you can try dynamically creating callbacks in the assembly :) Allocate executable memory and write there
B9 XX XX XX XX mov ecx, <this> 68 XX XX XX XX push <function member address> C3 ret
This will be a callback that converts __stdcall to __thiscall.