Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.5.3
-
None
Description
Please use the following code to reproduce. QMenu's native window is leaked after QApplication destruction. It can continue to receive windows messages and cause crashes in Qt window proc.
In the sample code, I send messages using API for simplicity. There can be other ways to cause the application to process messages. like OleUninitialize in QWindowsContext destructor or AMD audio driver or wacom tablet driver...
QApplication destructor call destroy(true, true) to release all windows. But hidden QMenu is not handled because it doesn't has WA_NativeWindow flag.
#include <QtWidgets/QApplication> #include <QtWidgets/QMenu> #include <QtWidgets/QWidget> #include <QtCore/QTimer> #include <Windows.h> HWND leakedWindow = 0; class WidgetWithMenu : public QWidget { public: WidgetWithMenu(QWidget* parent) : QWidget(parent) {} void showEvent(QShowEvent* e) override { QTimer::singleShot(100, this, [&]() { m_pMenu = new QMenu(this); m_pMenu->popup(QPoint(0, 0)); QTimer::singleShot(100, this, [&]() { leakedWindow = (HWND)m_pMenu->internalWinId(); m_pMenu->hide(); window()->close(); // QMenu's window is a transient child of toplevel window. But QMenu has no // WA_NativeWindow flag. When QApplication destructor call toplevel window // destroy(true, true), QMenu is skipped and leak. }); }); } private: QMenu* m_pMenu = nullptr; }; int main(int argc, char** argv) { { QApplication app(argc, argv); QWidget* tlw = new QWidget(); tlw->resize(640, 480); tlw->setStyleSheet("QWidget { background-color: red; }"); QWidget* child = new WidgetWithMenu(tlw); child->setGeometry(0, 0, 100, 100); child->setStyleSheet("QWidget { background-color: yellow; }"); tlw->show(); app.exec(); } // Qt window proc can still receive messages and crash. SendMessage(leakedWindow, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("ThemeChanged")); return 0; }