在WM_NCDESTROY上释放自己的资源安全吗?

Sam*_*ime 2 c++ winapi

考虑以下代码片段:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

问题是给定的代码片段如所编写的那样是否安全。

基本上,MyWindow是使用WinAPI创建的窗口的类。当窗口被破坏时,我需要做一些最后的清理。

请注意,实例MyWindowwindowPtr被使用原始创建new。我必须在成员函数中的某处删除实例,因此我从成员函数中删除了对对象本身的引用。

该代码依赖于该WM_NCDESTROY窗口曾经接收到的最后一条消息的假设。

因此,问题如下:

  • 是否可以确定WM_NCDESTROY窗口始终是接收到的最后一条消息并在那里执行最终清除?
  • 列出的代码安全吗?如果没有,它在什么条件下会破裂?

备注:我只对代码在技术上是否安全感兴趣,而不是对使用原始的新变量和/或全局变量是否是一种好的做法,不感兴趣。我有一些很好的理由执行此操作。

IIn*_*ble 5

它没有明确记录,这WM_NCDESTROY是窗口收到的最后一条消息。但是,如果您在两行之间阅读,则可以推断出此信息。

WM_NCDESTROY的文档包含以下说明:

此消息释放为窗口内部分配的所有内存。

窗口功能:窗口破坏概述了这种情况的后果:

窗户被破坏时,系统会删除与窗户相关的所有内部数据。这会使窗口句柄无效,该窗口句柄不能再由应用程序使用。

将它们放在一起,破坏一个窗口会使它的窗口句柄失效。一旦WM_NCDESTROY消息处理程序已完成运行,窗口句柄不再有效。无效的窗口句柄不再接收任何消息。

因此,您的实施是安全的。

令人怀疑的是,这些规则中的任何WM_NCDESTROY一条将来是否会更改(有那么多应用程序依赖于最终消息),但是如果您要做好准备,则可能需要考虑在windowPtr = nullptr;后面放置一条语句delete windowPtr;。这样做可以确保您的应用程序以可预见的方式失败,以防在MyWindow实例被处置后收到消息。