Skip to content

fix: defer uninstall to next restart when DLL is locked on Windows#13

Closed
pabloinigoblasco wants to merge 2 commits into
developmentfrom
fix/windows-deferred-uninstall
Closed

fix: defer uninstall to next restart when DLL is locked on Windows#13
pabloinigoblasco wants to merge 2 commits into
developmentfrom
fix/windows-deferred-uninstall

Conversation

@pabloinigoblasco
Copy link
Copy Markdown
Collaborator

Summary

  • ExtensionManager: new signal uninstallPendingRestart, new public method applyPendingUninstalls(), private helper schedulePendingUninstall()
  • MarketplaceWindow: subscribes to uninstallPendingRestart and shows the appropriate "restart required" feedback to the user

Problem

On Windows, uninstalling a plugin while it is loaded by the host process causes QDir::removeRecursively() to fail silently: the extension was not removed from disk, but the error was reported and the operation stopped there, leaving the user with no actionable path forward.

Solution

Align the uninstall flow with the existing install staging pattern. When removeRecursively() fails on Windows, uninstall() now:

  1. Writes a .pj_pending_uninstall marker inside the extension directory
  2. Removes the extension from the in-memory registry immediately (so it no longer appears as installed)
  3. Emits the new uninstallPendingRestart(id) signal instead of an error

At the next application startup, applyPendingUninstalls() scans extensions_dir for directories carrying the marker and deletes them. If the directory still cannot be removed (unusual), it is silently skipped and retried on the following startup.

Test plan

  • Run ./build.sh --debug && ./test.sh — all tests pass
  • Verify new tests: ApplyPendingUninstallsRemovesMarkedDirectory, ApplyPendingUninstallsIgnoresUnmarkedDirectory, ApplyPendingUninstallsIsNoOpForEmptyDirectory
  • On Windows: install plugin, attempt uninstall while loaded, verify "Needs Restart" badge appears, restart app and verify directory is removed

On Windows, uninstalling a plugin while it is loaded by the host process
causes QDir::removeRecursively() to fail silently. This change aligns
the uninstall flow with the existing install staging pattern:

- ExtensionManager: new signal `uninstallPendingRestart`, new public
  method `applyPendingUninstalls()`, private helper `schedulePendingUninstall()`
- MarketplaceWindow: subscribes to `uninstallPendingRestart` and shows
  the appropriate "restart required" feedback to the user

When removeRecursively() fails on Windows, uninstall() now:
1. Writes a `.pj_pending_uninstall` marker inside the extension directory
2. Removes the extension from the in-memory registry immediately
3. Emits the new `uninstallPendingRestart(id)` signal instead of an error

At the next application startup, `applyPendingUninstalls()` scans
extensions_dir for directories carrying the marker and deletes them.
@pabloinigoblasco pabloinigoblasco force-pushed the fix/windows-deferred-uninstall branch from 86a0a5b to 7fc7657 Compare March 26, 2026 12:16
@pabloinigoblasco
Copy link
Copy Markdown
Collaborator Author

Superseded by #22, which is a unified reconstruction of the Windows marketplace adaptation work (staging for install/update/uninstall when DLLs are locked).

@pabloinigoblasco pabloinigoblasco deleted the fix/windows-deferred-uninstall branch May 4, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant