diff options
| author | Bob Arnson <bob@firegiant.com> | 2026-01-21 21:20:40 -0500 |
|---|---|---|
| committer | Bob Arnson <github@bobs.org> | 2026-01-26 13:42:00 -0500 |
| commit | 49924eb413af6f316951fcc1a7deaf28b7fd6e19 (patch) | |
| tree | 1e88db96b839dbbac5a1f90b42bf178001656745 /src/burn | |
| parent | 8b9538acf39a353a34bcd0a624fd12155a818f55 (diff) | |
| download | wix-49924eb413af6f316951fcc1a7deaf28b7fd6e19.tar.gz wix-49924eb413af6f316951fcc1a7deaf28b7fd6e19.tar.bz2 wix-49924eb413af6f316951fcc1a7deaf28b7fd6e19.zip | |
Normally, a patched package is detected as superseded and therefore a
normal uninstall takes no action. This change looks for applied patches
and allows a normal uninstall to remove the package.
Fixes https://github.com/wixtoolset/issues/issues/6350
Diffstat (limited to 'src/burn')
| -rw-r--r-- | src/burn/engine/msiengine.cpp | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp index 86fb0d9d..48ec0c81 100644 --- a/src/burn/engine/msiengine.cpp +++ b/src/burn/engine/msiengine.cpp | |||
| @@ -50,7 +50,9 @@ static void RegisterSourceDirectory( | |||
| 50 | __in BURN_PACKAGE* pPackage, | 50 | __in BURN_PACKAGE* pPackage, |
| 51 | __in_z LPCWSTR wzCacheDirectory | 51 | __in_z LPCWSTR wzCacheDirectory |
| 52 | ); | 52 | ); |
| 53 | 53 | static BOOL PackageHasAppliedPatch( | |
| 54 | __in BURN_PACKAGE* pPackage | ||
| 55 | ); | ||
| 54 | 56 | ||
| 55 | // function definitions | 57 | // function definitions |
| 56 | 58 | ||
| @@ -904,7 +906,22 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage( | |||
| 904 | else if ((BOOTSTRAPPER_REQUEST_STATE_ABSENT == pPackage->requested || BOOTSTRAPPER_REQUEST_STATE_CACHE == pPackage->requested) && | 906 | else if ((BOOTSTRAPPER_REQUEST_STATE_ABSENT == pPackage->requested || BOOTSTRAPPER_REQUEST_STATE_CACHE == pPackage->requested) && |
| 905 | !pPackage->fPermanent) // removing a package that should be removed. | 907 | !pPackage->fPermanent) // removing a package that should be removed. |
| 906 | { | 908 | { |
| 907 | execute = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED == pPackage->currentState ? BOOTSTRAPPER_ACTION_STATE_NONE : BOOTSTRAPPER_ACTION_STATE_UNINSTALL; | 909 | if (BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED == pPackage->currentState) |
| 910 | { | ||
| 911 | // If the package is superseded, check to see if there's a patch installed. | ||
| 912 | // A minor upgrade patch could be (usually is) the cause of the | ||
| 913 | // supersedence. In that case, we should ignore the supersedence that would | ||
| 914 | // normally prevent the uninstall. There is a gap in this logic: If a minor | ||
| 915 | // upgrade package were installed without a bundle, then a small update patch | ||
| 916 | // (which by definition doesn't change the version number) were installed, | ||
| 917 | // this check would allow the uninstall. If the minor upgrade were installed | ||
| 918 | // by a bundle, dependencies would keep the package installed. | ||
| 919 | execute = PackageHasAppliedPatch(pPackage) ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE; | ||
| 920 | } | ||
| 921 | else | ||
| 922 | { | ||
| 923 | execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL; | ||
| 924 | } | ||
| 908 | } | 925 | } |
| 909 | else if (BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested) | 926 | else if (BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested) |
| 910 | { | 927 | { |
| @@ -2265,6 +2282,7 @@ LExit: | |||
| 2265 | ReleaseStr(sczMspPath); | 2282 | ReleaseStr(sczMspPath); |
| 2266 | ReleaseStr(sczCachedDirectory); | 2283 | ReleaseStr(sczCachedDirectory); |
| 2267 | ReleaseStr(sczPatches); | 2284 | ReleaseStr(sczPatches); |
| 2285 | |||
| 2268 | return hr; | 2286 | return hr; |
| 2269 | } | 2287 | } |
| 2270 | 2288 | ||
| @@ -2289,6 +2307,47 @@ static void RegisterSourceDirectory( | |||
| 2289 | 2307 | ||
| 2290 | LExit: | 2308 | LExit: |
| 2291 | ReleaseStr(sczMsiDirectory); | 2309 | ReleaseStr(sczMsiDirectory); |
| 2310 | } | ||
| 2311 | |||
| 2312 | static BOOL PackageHasAppliedPatch( | ||
| 2313 | __in BURN_PACKAGE* pPackage | ||
| 2314 | ) | ||
| 2315 | { | ||
| 2316 | HRESULT hr = S_OK; | ||
| 2317 | BOOL fPatched = FALSE; | ||
| 2318 | UINT er = ERROR_SUCCESS; | ||
| 2319 | DWORD iPatch = 0; | ||
| 2320 | WCHAR wzPatchCode[MAX_GUID_CHARS + 1] = {}; | ||
| 2321 | WCHAR wzTransforms[MAX_PATH] = {}; | ||
| 2322 | DWORD cchTransforms = countof(wzTransforms); | ||
| 2323 | WCHAR wzPatchState[2] = {}; | ||
| 2324 | DWORD cchPatchState = countof(wzPatchState); | ||
| 2325 | |||
| 2326 | for (;;) | ||
| 2327 | { | ||
| 2328 | er = ::MsiEnumPatchesW(pPackage->Msi.sczProductCode, iPatch, wzPatchCode, wzTransforms, &cchTransforms); | ||
| 2329 | |||
| 2330 | if (ERROR_NO_MORE_ITEMS == er) | ||
| 2331 | { | ||
| 2332 | ExitFunction(); | ||
| 2333 | } | ||
| 2334 | ExitOnWin32Error(er, hr, "Failed to enumerate patches for package %ls, product code %ls.", pPackage->sczId, pPackage->Msi.sczProductCode); | ||
| 2335 | |||
| 2336 | er = ::MsiGetPatchInfoExW(wzPatchCode, pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED | ||
| 2337 | , INSTALLPROPERTY_PATCHSTATE, wzPatchState, &cchPatchState); | ||
| 2338 | ExitOnWin32Error(er, hr, "Failed to get patch info for patch %ls.", wzPatchCode); | ||
| 2339 | |||
| 2340 | if ('1' == wzPatchState[0]) | ||
| 2341 | { | ||
| 2342 | fPatched = TRUE; | ||
| 2343 | |||
| 2344 | ExitFunction(); | ||
| 2345 | } | ||
| 2346 | |||
| 2347 | ++iPatch; | ||
| 2348 | } | ||
| 2349 | |||
| 2350 | LExit: | ||
| 2351 | return fPatched; | ||
| 2292 | 2352 | ||
| 2293 | return; | ||
| 2294 | } | 2353 | } |
