Class method as winAPI callback

Is it possible to set the winAPI message callback function as a class method. If so, how is this best implemented? I wonder if this is possible.

Sorry for the short question, I hope you can provide useful answers.

Thank you in advance:).

+3
source share
4 answers

You cannot use non- static member functions for C callbacks.

However, typically C-callbacks have a user data pointer that is redirected to the callback. You can learn this to do what you want using the static member functions:

 // Beware, brain-compiled code ahead! typedef void (*callback)(int blah, void* user_data); void some_func(callback cb, void* user_data); class my_class { public: // ... void call_some_func() { some_func(&callback_,this); } private: void callback(int blah) { std::cout << blah << '\n'; } static void callback_(int blah, void* user_data) { my_class* that = static_cast<my_class*>(user_data); that->callback(blah); } }; 
+7
source

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*), ""); // or assert() 

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.

+2
source

Provided that it has the correct signature and the correct calling convention, you can pass static class methods as callback functions for various Win32 APIs. You cannot use non-static methods, since they expect one more implicit parameter ( this pointer), which Win32 APi cannot provide them.

+1
source

You can set the corresponding static member function of the class as a callback function from the Windows API.

0
source

All Articles