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?
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).