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.

  1. 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)); } 
  2. 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:

  1. 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*);     // ... 
  2. pass instance pointer createwindowexw:

        m_hwnd = createwindowex( /* ... */,                              static_cast<lpvoid>(this) );     // setwindowlongptrw called message handler } 
  3. 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

Popular posts from this blog

css - Which browser returns the correct result for getBoundingClientRect of an SVG element? -

gcc - Calling fftR4() in c from assembly -

Function that returns a formatted array in VBA -