0

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.

LHLaurini
  • 1,737
  • 17
  • 31
  • @HansPassant It's not my machine. Just google it. `WM_GETMINMAXINFO` is the first message. Have a look at this: http://stackoverflow.com/questions/1741296/windows-api-what-is-the-first-message-a-window-is-guaranteed-to-receive and http://www.gamedev.net/topic/323415-first-win32-message-sent/ – LHLaurini Jul 13 '15 at 23:40

1 Answers1

1

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

user541686
  • 205,094
  • 128
  • 528
  • 886
  • Yes, sorry. I didn't get it when I first read but then later I did and then I deleted my comment. – LHLaurini Jul 14 '15 at 20:56
  • Well, my problem seems to have solved itseft. I've found that `WM_GETMINMAXINFO` is sent to the window multiple times. So the first time it's sent, I can check if the value is `NULL` and then ignore it. But if I ever need to handle a message that is only sent once, I'm gonna need to use this method. But please just explain this: what's the difference between using your method and using a `static` variable instead? I'll accept your answer if you answer this last question. – LHLaurini Jul 14 '15 at 21:24
  • 1
    @LHLaurini: Ah. I believe there is no other message that is sent earlier than `WM_NCCREATE`, so if you're fine with not handling `WM_GETMINMAXINFO` the first time, then you would never need to use this method. But the difference between using a plain static variable and a thread-local variable (which is also static) is that a static variable is not thread-safe, so if two threads try to create windows simultaneously (which is unusual, but you never know) then they will interfere with each other and your program will crash. – user541686 Jul 14 '15 at 22:33
  • Thanks. Didn't think about that. Well, that wouldn't be a problem for my program, but still a good practice. – LHLaurini Jul 14 '15 at 22:36