From fafdaa522ff2a3888dfceb0ab56911c4f8cdf48d Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Wed, 21 Jan 2026 21:20:40 -0500 Subject: Allow patched package to be uninstalled. 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 --- src/burn/engine/msiengine.cpp | 52 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'src/burn/engine/msiengine.cpp') diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp index 86fb0d9d..a2a29bda 100644 --- a/src/burn/engine/msiengine.cpp +++ b/src/burn/engine/msiengine.cpp @@ -50,7 +50,9 @@ static void RegisterSourceDirectory( __in BURN_PACKAGE* pPackage, __in_z LPCWSTR wzCacheDirectory ); - +static BOOL PackageHasAppliedPatch( + __in BURN_PACKAGE* pPackage + ); // function definitions @@ -904,7 +906,9 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage( else if ((BOOTSTRAPPER_REQUEST_STATE_ABSENT == pPackage->requested || BOOTSTRAPPER_REQUEST_STATE_CACHE == pPackage->requested) && !pPackage->fPermanent) // removing a package that should be removed. { - execute = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED == pPackage->currentState ? BOOTSTRAPPER_ACTION_STATE_NONE : BOOTSTRAPPER_ACTION_STATE_UNINSTALL; + BOOL fPackageHasAppliedPatch = PackageHasAppliedPatch(pPackage); + + execute = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED == pPackage->currentState && !fPackageHasAppliedPatch ? BOOTSTRAPPER_ACTION_STATE_NONE : BOOTSTRAPPER_ACTION_STATE_UNINSTALL; } else if (BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested) { @@ -2265,6 +2269,7 @@ LExit: ReleaseStr(sczMspPath); ReleaseStr(sczCachedDirectory); ReleaseStr(sczPatches); + return hr; } @@ -2289,6 +2294,47 @@ static void RegisterSourceDirectory( LExit: ReleaseStr(sczMsiDirectory); +} + +static BOOL PackageHasAppliedPatch( + __in BURN_PACKAGE* pPackage +) +{ + HRESULT hr = S_OK; + BOOL fPatched = FALSE; + UINT er = ERROR_SUCCESS; + DWORD iPatch = 0; + WCHAR wzPatchCode[MAX_GUID_CHARS + 1] = {}; + WCHAR wzTransforms[MAX_PATH] = {}; + DWORD cchTransforms = countof(wzTransforms); + WCHAR wzPatchState[2] = {}; + DWORD cchPatchState = countof(wzPatchState); + + for (;;) + { + er = ::MsiEnumPatchesW(pPackage->Msi.sczProductCode, iPatch, wzPatchCode, wzTransforms, &cchTransforms); + + if (ERROR_NO_MORE_ITEMS == er) + { + ExitFunction(); + } + ExitOnWin32Error(er, hr, "Failed to enumerate patches for package %ls, product code %ls.", pPackage->sczId, pPackage->Msi.sczProductCode); + + er = ::MsiGetPatchInfoExW(wzPatchCode, pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED + , INSTALLPROPERTY_PATCHSTATE, wzPatchState, &cchPatchState); + ExitOnWin32Error(er, hr, "Failed to get patch info for patch %ls.", wzPatchCode); + + if ('1' == wzPatchState[0]) + { + fPatched = TRUE; + + ExitFunction(); + } + + ++iPatch; + } + +LExit: + return fPatched; - return; } -- cgit v1.2.3-55-g6feb