c++ - How do I `std::bind` a non-static class member to a Win32 callback function `WNDPROC`? -
i'm trying bind non-static class member standard wndproc
function. know can making class member static. but, c++11 stl learner, i'm interested in doing using tools under <functional>
header.
my code follows.
class mainwindow { public: void create() { wndclassexw windowclass; windowclass.cbsize = sizeof(wndclassex); windowclass.style = m_classstyles; windowclass.lpfnwndproc = std::function<lresult(hwnd, uint, wparam, lparam)> ( std::bind(&mainwindow::windowproc, *this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); windowclass.cbclsextra = 0; windowclass.cbwndextra = 0; windowclass.hinstance = m_hinstance; windowclass.hicon = loadiconw(m_hinstance, makeintresourcew(idi_window)); windowclass.hcursor = loadcursor(null, idc_arrow); windowclass.hbrbackground = (hbrush) color_window; windowclass.lpszmenuname = makeintresourcew(idr_menu); windowclass.lpszclassname = m_classname.c_str(); windowclass.hiconsm = loadiconw(m_hinstance, makeintresourcew(idi_window_small)); registerclassexw(&windowclass); m_hwnd = createwindowex(/*_in_ dword*/ extendedstyles, /*_in_opt_ lpctstr*/ m_classname.c_str(), /*_in_opt_ lpctstr*/ m_windowtitle.c_str(), /*_in_ dword*/ m_styles, /*_in_ int*/ m_x, /*_in_ int*/ m_y, /*_in_ int*/ m_width, /*_in_ int*/ m_height, /*_in_opt_ hwnd*/ hwnd_desktop, /*_in_opt_ hmenu*/ null, /*_in_opt_ hinstance*/ windowclass.hinstance, /*_in_opt_ lpvoid*/ null); } private: lresult callback windowproc(_in_ hwnd hwnd, _in_ uint umsg, _in_ wparam wparam, _in_ lparam lparam) { return defwindowproc(hwnd, umsg, wparam, lparam); } };
when run is, gives error message:
error: no suitable conversion function "std::function<lresult(hwnd, uint, wparam, lparam)>" "wndproc".
while johnb explained details why not possible, here common solution problem trying solve: granting class instance access static class member.
the guiding principle solution instance pointer must stored in way accessible static class member. when dealing windows window memory place store information. requested space of window memory specified through wndclassexw::cbwndextra
while data access provided through setwindowlongptr
, getwindowlongptr
.
store instance pointer in window data area after construction:
void create() { wndclassexw windowclass; // ... // assign static windowproc windowclass.lpfnwndproc = &mainwindow::staticwindowproc; // reserve space store instance pointer windowclass.cbwndextra = sizeof(mainwindow*); // ... registerclassexw(&windowclass); m_hwnd = createwindowex( /* ... */ ); // store instance pointer setwindowlongptrw(m_hwnd, 0, reinterpret_cast<long_ptr>(this)); }
retrieve instance pointer static window procedure , call window procedure member function:
static lresult callback staticwindowproc( _in_ hwnd hwnd, _in_ uint umsg, _in_ wparam wparam, _in_ lparam lparam ) { // retrieve instance pointer mainwindow* pwnd = reinterpret_cast<mainwindow*>(getwindowlongptrw(hwnd, 0)); if ( pwnd != null ) // see note 1 below // call member function if instance available return pwnd->windowproc(hwnd, umsg, wparam, lparam); else // otherwise perform default message handling return defwindowproc(hwnd, umsg, wparam, lparam); }
the signature of class member
windowproc
same in code provided.
this 1 way implement desired behavior. remy lebeau suggested variation has benefit of getting messages routed through class member windowproc
:
allocate space in window data (same above):
void create() { wndclassexw windowclass; // ... // assign static windowproc windowclass.lpfnwndproc = &mainwindow::staticwindowproc; // reserve space store instance pointer windowclass.cbwndextra = sizeof(mainwindow*); // ...
pass instance pointer
createwindowexw
:m_hwnd = createwindowex( /* ... */, static_cast<lpvoid>(this) ); // setwindowlongptrw called message handler }
extract instance pointer , store in window data area when first message (
wm_nccreate
) sent window:static lresult callback staticwindowproc( _in_ hwnd hwnd, _in_ uint umsg, _in_ wparam wparam, _in_ lparam lparam ) { // store instance pointer while handling first message if ( umsg == wm_nccreate ) { createstruct* pcs = reinterpret_cast<createstruct*>(lparam); lpvoid pthis = pcs->lpcreateparams; setwindowlongptrw(hwnd, 0, reinterpret_cast<long_ptr>(pthis)); } // @ point instance pointer available mainwindow* pwnd = reinterpret_cast<mainwindow*>(getwindowlongptrw(hwnd, 0)); // see note 1a below return pwnd->windowproc(hwnd, umsg, wparam, lparam); }
note 1: instance pointer stored window data area after window has been created while lpfnwndproc
set prior creation. means staticwindowproc
called while instance pointer not yet available. consequence if
-statement inside staticwindowproc
required messages during creation (like wm_create
) handled.
note 1a: restrictions stated under note 1 not apply alternative implementation. instance pointer available going forward first message , class member windowproc
consequently called messages.
note 2: if want destroy c++ class instance when underlying hwnd
destroyed, wm_ncdestroy
place so; final message sent window.
Comments
Post a Comment