diff --git a/src/controller.cpp b/src/controller.cpp index 80bd009..6e88b67 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -165,6 +165,12 @@ RcxController::~RcxController() { m_refreshWatcher->cancel(); m_refreshWatcher->waitForFinished(); } + + m_snapshotProv.reset(); +} + +void RcxController::resetProvider() { + m_snapshotProv.reset(); } RcxEditor* RcxController::primaryEditor() const { diff --git a/src/controller.h b/src/controller.h index c0d543e..d9a5c57 100644 --- a/src/controller.h +++ b/src/controller.h @@ -127,6 +127,7 @@ public: void setEditorFont(const QString& fontName); void setRefreshInterval(int ms); void setCompactColumns(bool v); + void resetProvider(); // MCP bridge accessors void setSuppressRefresh(bool v) { m_suppressRefresh = v; } diff --git a/src/main.cpp b/src/main.cpp index 4f1ca7a..6e9f258 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -109,7 +109,7 @@ static LONG WINAPI crashHandler(EXCEPTION_POINTERS* ep) { SYSTEMTIME st; GetLocalTime(&st); wchar_t dumpPath[MAX_PATH]; - _snwprintf(dumpPath, MAX_PATH, + _snwprintf_s(dumpPath, MAX_PATH, L"%sreclass_crash_%04d%02d%02d_%02d%02d%02d.dmp", exePath, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); @@ -1391,6 +1391,28 @@ static void buildEmptyStruct(NodeTree& tree, const QString& classKeyword = QStri } } +MainWindow::~MainWindow() { + /* + * When MainWindow is destroyed: + * + * 1. ~MainWindow() runs (our code — plugin DLLs still loaded) + * 2. MainWindow member variables are destroyed (m_pluginManager — unloads plugin DLLs) + * 3. QObject::~QObject() runs — destroys child widgets (QMdiSubWindow → RcxController → ~RcxController()) + * + */ + + // Disconnect all subwindow destroyed signals before members are torn down, + // so the lambdas capturing 'this' never fire on a half-destroyed object. + for (auto it = m_tabs.begin(); it != m_tabs.end(); ++it) { + disconnect(it.key(), &QObject::destroyed, this, nullptr); + // Release providers now while plugin DLLs are still loaded; + // if deferred to Qt child cleanup the DLL code may already be unloaded. + it->doc->provider.reset(); + it->ctrl->resetProvider(); + } + m_tabs.clear(); +} + void MainWindow::newClass() { project_new(QStringLiteral("class")); } diff --git a/src/mainwindow.h b/src/mainwindow.h index b90b7ca..fb28e03 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -30,6 +30,7 @@ class MainWindow : public QMainWindow { friend class McpBridge; public: explicit MainWindow(QWidget* parent = nullptr); + ~MainWindow() override; private slots: void newClass();