I decided to create and use windows using a base class like this:
class Window
{
private:
static LRESULT WINAPI WindowProc(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam);
protected:
virtual LRESULT onMessageNameGoesHere(/*parameters*/)
{
// Default handling
};
public:
// Other functions
};
So all windows are inherited from this class. This is WindowProc
.
LRESULT WINAPI Window::WindowProc(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam)
{
Window *window = (Window*)GetWindowLongPtr(_hWnd, GWLP_USERDATA);
switch (_uMsg)
{
case WM_SOMEMESSAGE:
return window->onMessageNameGoesHere();
case WM_NCCREATE:
SetWindowLongPtr(_hWnd, GWLP_USERDATA, LONG(LPCREATESTRUCT(_lParam)->lpCreateParams));
return true;
case WM_GETMINMAXINFO:
return window->onGetMinMaxInfo((LPMINMAXINFO)_lParam);
default:
return DefWindowProc(_hWnd, _uMsg, _wParam, _lParam);
}
}
WM_NCCREATE
stores a pointer to the class associated to the window in GWLP_USERDATA
. The problem is that WM_GETMINMAXINFO
is received before WM_NCCREATE
does, making it crash. (Yes, I know I need some code to avoid that)
So is there a way to set the minimum and maximum window size without WM_GETMINMAXINFO
or maybe make that message be sent before WM_NCCREATE
does?
Feel free to ask for more detail or for some more explanation.
I believe the answer is "no". This is one of the many places where the Windows OOP model has an impedance mismatch with that of C++.
The only solution I can think of is to use RAII to save/restore the context pointer in thread-local storage (make sure to save what was already there to avoid reentrancy isues) and to retrieve it as soon as your message handler is called. On Windows XP you can try __declspec(thread)
or explicitly do this via TlsAlloc
/TlsSetValue
; on Windows Vista or later you might want to use FlsAlloc
/FlsSetValue
although I'm not sure if fibers can mess with things here...