Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to deallocate oneself on WM_NCDESTROY?

Tags:

c++

winapi

Consider the following code snippet:

// MyWindow.h
struct MyWindow
{
    LRESULT CALLBACK myWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    static LRESULT CALLBACK myWindowProcWrapper(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
extern MyWindow *windowPtr; // windowPtr is initialized on startup using raw new

// MyWindow.cpp
MyWindow *windowPtr = 0;

LRESULT CALLBACK MyWindow::myWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_NCDESTROY:
        delete windowPtr;
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK MyWindow::myWindowProcWrapper(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    return windowPtr->myWindowProc(hwnd, msg, wParam, lParam);
}

The question is whether the given code snippet is safe as written.

Basically, MyWindow is the class for a window created with the WinAPI. I need to do some final cleanup when the window is destroyed.

Notice that the instance of MyWindow, windowPtr, is created using a raw new. I have to delete the instance somewhere in a member function, so I delete the reference to the object itself from within a member function.

The code relies on the assumption that WM_NCDESTROY is the last message ever received by that window.

So the questions are as follows:

  • Is it safe to assume that WM_NCDESTROY is always the last message a window receives and to perform final cleanup there?
  • Is the listed code safe? If not, under what conditions could it break?

Remark: I'm only interested in whether the code is technically safe, not if it is good practice to use a raw new and/or global variables. I have some good reasons for this implementation.

like image 220
SampleTime Avatar asked Oct 15 '25 13:10

SampleTime


1 Answers

It is not explicitly documented, that WM_NCDESTROY is the final message a window receives. If you read in between the lines, you can deduce this information, though.

The documentation for WM_NCDESTROY contains the following remark:

This message frees any memory internally allocated for the window.

Window Features: Window Destruction outlines the consequences of this:

When a window is destroyed, the system [...] removes any internal data associated with the window. This invalidates the window handle, which can no longer be used by the application.

Putting those together, destroying a window invalidates its window handle. Once the WM_NCDESTROY message handler has run to completion, the window handle is no longer valid. An invalid window handle no longer receives any messages.

Your implementation is thus safe.

It is doubtful that any of these rules will change in the future (with so many applications relying on WM_NCDESTROY being the final message), but if you want to be prepared, you might want to consider placing a windowPtr = nullptr; statement following delete windowPtr;. Doing so ensures, that your application fails in a predictable way, in case it receives a message after the MyWindow instance has been disposed.

like image 198
IInspectable Avatar answered Oct 17 '25 02:10

IInspectable



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!