Search code examples
c++winapistaticvirtual

Calling virtual function from static function


CASE

My base class "Control" subclasses WinAPI button control:

hWndControl = CreateWindowEx
(
      0
    , L"BUTTON"
    , L"Button"
    , WS_VISIBLE | WS_CHILD | BS_OWNERDRAW | WS_EX_TRANSPARENT
    , wndRc.left
    , wndRc.top
    , wndRc.right
    , wndRc.bottom
    , hWndParent
    , 0
    , hInstance
    , 0
);

void* p_this{reinterpret_cast<void*>(this)}; // avoiding C-style cast    
SetWindowSubclass
(
      hWndControl
    , Control::ControlProc
    , 0
    , reinterpret_cast<DWORD_PTR>(p_this)
)

As far as I know this requires me to define the callback as static (which I do). Here is the callback sample for reference:

LRESULT CALLBACK Control::ControlProc
(
      HWND hWnd
    , UINT msg
    , WPARAM wParam
    , LPARAM lParam
    , UINT_PTR uIdSubclass
    , DWORD_PTR dwRefData
)
{
    //  RETRIEVE POINTER TO THIS CLASS OBJECT
    void* p_thisV{reinterpret_cast<void*>(dwRefData)}; // avoiding C-style cast
    Control* const p_this{reinterpret_cast<Control*>(p_thisV)};

    // PROCESS MESSAGES
    switch (msg)
    {
        //  DRAWING
        case MY_DRAWITEM: // custom message forwarding WM_DRAWITEM from main window
        {
            p_this->DrawControl();
        }
        break;

        ...
    }
    return DefSubclassProc(hWnd, msg, wParam, lParam);
}

As far as here everything works fine if I do the drawing in the callback function, or in member function defined in the base class referenced in callback.

But I plan to inherit this base class for multiple different controls with different looks while using the same callback. So I thought I would create virtual functions called in specific points of the callback, which I can override in derived class with custom behavior for each derived class like so:

//  Base class header
class Control
{
    ...
    protected:
    virtual void DrawControl();
    ...
};

//  Derived class header
class CalendarItem : public Control
{
    ...
    protected:
    void DrawControl();
    ...
};

//  Derived class cpp
void CalendarItem::DrawControl()
{
    std::unique_ptr<DrawBg> drawBg = std::unique_ptr<DrawBg>(new DrawBg(Control::hWndControl));
    //  this is the actual drawing mechanism, works, not relevant
}

PROBLEM

I get exception in the callback function on line: p_this->DrawControl();

Exception text: p_this->**** was 0x75004D.

Can you please tell me how to fix this solution to work, or whether something like this is even possible?


Solution

  • The correct solution was hinted at by RbMm - this pointer is on stack, we need heap pointer so that it stays in memory when the callback function runs (so current running function is already finished).

    The correct solution:

    Creating derived class object:

    // provide base class pointer stored on heap
    Derived* der = new Derived;
    der->CreateInDerived(&(*der), ...); // "&(*der)" gets base class ptr from derived ptr
    

    Derived class function:

    void Derived::CreateInDerived(Base* ptr, ...)
    {
        ptr->CreateInBase(ptr, ...);
    }
    

    Base class function:

    void Base::CreateInBase(Base* ptr, ...)
    {
        ...
        SetWindowSubclass
        (
              hWndControl
            , Control::ControlProc
            , 0
            , reinterpret_cast<DWORD_PTR>(ptr)
        )
        ...
    }
    

    Explanation:

    The problem was not at all in the clash of virtual and static function, but in life length of transferred pointer. The pointer address was turned into a number in the function A, so that it can be given to callback function B through DWORD parameter.

    When function B attempted to retrieve the pointer address back from the number, pointer defined in function A was alrady out of scope (and probably overwritten, since function A finished and released the memory).