Search code examples
windowsclasswindow

Is there a way to set minimum size without WM_GETMINMAXINFO?


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.


Solution

  • 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...