FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Fix MSI uninstall cleanup; preserve user data on MSI upgrades by caesay · Pull Request #1012 · velopack/velopack · GitHub

Fix MSI uninstall cleanup; preserve user data on MSI upgrades - #1012

Open
caesay wants to merge 2 commits into
developfrom
fix-msi-uninstall-cleanup
Open

Fix MSI uninstall cleanup; preserve user data on MSI upgrades#1012
caesay wants to merge 2 commits into
developfrom
fix-msi-uninstall-cleanup

Conversation

caesay commented Jul 20, 2026

Copy link
Copy Markdown
Member

Fixes #989, fixes #1004 (related: #1003).

Previously, a major MSI upgrade ran the old product's full cleanup action (REMOVE="ALL" is also set during RemoveExistingProducts), wiping the entire install dir including user files. And on uninstall, the cleanup action ran as SYSTEM on per-machine installs, so %LOCALAPPDATA% resolved to the SYSTEM profile and the per-user fallback dir (packages + Update.exe) was left behind.

Changes:

  • MSI upgrades no longer wipe user files or run the app uninstall hook. The cleanup detects UPGRADINGPRODUCTCODE and only purges the current payload dir (so files from prior in-app updates can't mix with the new payload); everything outside current survives, matching the documented update contract.
  • Uninstall now mirrors the Update.exe uninstall logic: force-stops processes running from the install dir, removes the install dir entirely, sweeps all shortcuts pointing into it (including user-created ones), and removes leftover MSI:{AppId} ARP registry keys.
  • A new impersonated custom action (UserCleanupDeferred) cleans the per-user state the SYSTEM-context action cannot reach on per-machine installs: shortcuts, the %LocalAppData%\{AppId} fallback dir, the velopack temp dir, and the HKCU ARP key. LocalAppDataFolder/TempFolder are now marshaled through CustomActionData instead of read from environment variables at runtime.

Note: installs already in the field carry the old MSI/DLL, so their first upgrade to a new MSI will still run the old (wiping) cleanup once; behavior is correct from then on.

Tests: new E2E test covering install → MSI upgrade (user data preserved, current purged, no uninstall hook) → uninstall (dir, ARP key, shortcuts, temp all removed); a static authoring test over the MSI tables (conditions, impersonation flags, sequencing); and the explicit elevated per-machine test now asserts the %LocalAppData% fallback dir is removed on uninstall (#989).

During a major upgrade the old product's cleanup action previously ran a
full uninstall cleanup, deleting the entire install dir including user
files. Now it only purges the 'current' payload dir (so the incoming MSI
lays down a clean payload) and the app uninstall hook no longer fires.

On a real uninstall, cleanup now mirrors the Update.exe uninstall logic:
it force-stops processes running from the install dir, removes the
install dir, sweeps any shortcuts pointing into it, and removes leftover
MSI:{AppId} ARP registry keys. A new impersonated custom action handles
the per-user state (shortcuts, %LocalAppData%\{AppId} fallback dir with
packages + Update.exe, velopack temp dir) which the non-impersonated
action could not reach when running as SYSTEM on per-machine installs -
previously it resolved %LOCALAPPDATA% to the SYSTEM profile, leaving the
fallback dir behind (#989, #1004).

codecov Bot commented Jul 20, 2026
edited
Loading

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.94118% with 48 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.20%. Comparing base (b300186) to head (4fef08b).
⚠️ Report is 2 commits behind head on develop.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/wix-dll/src/lib.rs 52.00% 48 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1012      +/-   ##
===========================================
+ Coverage    53.08%   53.20%   +0.12%     
===========================================
  Files          258      258              
  Lines        19396    19487      +91     
  Branches      1417     1417              
===========================================
+ Hits         10296    10368      +72     
- Misses        8623     8644      +21     
+ Partials       477      475       -2     
Flag Coverage Δ
nodejs 2.32% <ø> (-0.01%) ⬇️
rust 53.94% <52.94%> (+0.23%) ⬆️
vpk 35.28% <ø> (-0.08%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…rride

- RustAppId now carries {{AppId}} instead of {{AppTitle}}: the cleanup
  derives the %LocalAppData% fallback dir, velopack temp dir and
  MSI:{AppId} ARP key from it, so a custom --packTitle previously made
  uninstall miss the real fallback dir and delete a title-named dir
  instead. app_id is also validated to be a single path component.
- VELOPACK_INSTALLDIR only overrides INSTALLFOLDER on first install;
  on maintenance/uninstall the path handed to the elevated cleanup now
  always comes from the registered install state.
- Pin RemoveExistingProducts < InstallFiles in the authoring test (the
  upgrade-mode current/ purge depends on that ordering).
- Unit tests for the ARP key deletion (incl. foreign values/subkeys)
  and CustomActionData parsing; E2E now uses a distinct pack title and
  verifies a foreign ARP value is swept while an unrelated title-named
  dir survives.

Copy link
Copy Markdown

Question on the upgrade mechanism: UPGRADINGPRODUCTCODE being set here relies on WiX v7's implicit default major-upgrade behavior (no MajorUpgrade/Upgrade element is authored, but Package has UpgradeCode + Version). Since the purge-only-current/skip-uninstall-hook logic depends on RemoveExistingProducts running before InstallFiles, would it be worth authoring <MajorUpgrade> explicitly (pinning Schedule="afterInstallValidate") rather than relying on the implicit default, so that sequencing is guaranteed rather than incidental?

Also: the implicit default's downgrade-blocked message is WiX's own built-in English-only string, rather than going through the l18n crate like the rest of the installer's text. Worth localizing that too?

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants


Back | FazBrowse Home | New Git URL