From 4bb788e294025c158a08aa2b9e06c3c0807995bc Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Wed, 25 Feb 2026 19:43:09 -0500 Subject: [PATCH] Handle scope of configurable-scope BundlePackages. Fixes https://github.com/wixtoolset/issues/issues/9233 --- src/burn/engine/apply.cpp | 4 +-- src/burn/engine/bundlepackageengine.cpp | 24 +++++++++++-- src/burn/engine/bundlepackageengine.h | 2 ++ src/burn/engine/elevation.cpp | 4 +-- src/test/burn/TestBA/TestBA.cs | 2 +- ...PuomBundlePackage.wixproj => Bundle.props} | 4 ++- .../PuomBundlePackage/Bundle.wxs | 11 ++++-- .../PuomBundlePackageTestBA.wixproj | 7 ++++ .../ConfigurableScopeTests.cs | 34 +++++++++++++++++++ 9 files changed, 81 insertions(+), 11 deletions(-) rename src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/{PuomBundlePackage.wixproj => Bundle.props} (66%) create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackageTestBA.wixproj diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 68aded718..b7a54246d 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp @@ -2761,7 +2761,7 @@ static HRESULT ExecuteRelatedBundle( } else { - hrExecute = BundlePackageEngineExecuteRelatedBundle(pExecuteAction, pContext->pCache, &pEngineState->variables, fRollback, GenericExecuteMessageHandler, pContext, pRestart); + hrExecute = BundlePackageEngineExecuteRelatedBundle(pExecuteAction, pContext->pCache, &pEngineState->variables, fRollback, FALSE/*fPerMachine*/, GenericExecuteMessageHandler, pContext, pRestart); ExitOnFailure(hrExecute, "Failed to configure per-user related bundle."); } @@ -2888,7 +2888,7 @@ static HRESULT ExecuteBundlePackage( } else { - hrExecute = BundlePackageEngineExecutePackage(pExecuteAction, pContext->pCache, &pEngineState->variables, fRollback, SUCCEEDED(pExecuteAction->bundlePackage.pPackage->hrCacheResult), GenericExecuteMessageHandler, pContext, pRestart); + hrExecute = BundlePackageEngineExecutePackage(pExecuteAction, pContext->pCache, &pEngineState->variables, fRollback, SUCCEEDED(pExecuteAction->bundlePackage.pPackage->hrCacheResult), pEngineState->registration.fPerMachine, GenericExecuteMessageHandler, pContext, pRestart); ExitOnFailure(hrExecute, "Failed to configure per-user BUNDLE package."); } diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 7ada5f6a1..ac884830c 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp @@ -25,6 +25,7 @@ static HRESULT ExecuteBundle( __in BOOTSTRAPPER_RELATION_TYPE relationType, __in BURN_PACKAGE* pPackage, __in BOOL fPseudoPackage, + __in BOOL fPerMachine, __in_z_opt LPCWSTR wzParent, __in_z_opt LPCWSTR wzIgnoreDependencies, __in_z_opt LPCWSTR wzAncestors, @@ -51,7 +52,7 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml( BOOL fFoundXml = FALSE; LPWSTR scz = NULL; - // @DetectCondition + // @BundleCode hr = XmlGetAttributeEx(pixnBundlePackage, L"BundleCode", &pPackage->Bundle.sczBundleCode); ExitOnRequiredXmlQueryFailure(hr, "Failed to get @BundleCode."); @@ -91,6 +92,10 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml( hr = XmlGetYesNoAttribute(pixnBundlePackage, L"Win64", &pPackage->Bundle.fWin64); ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Win64."); + // @Scope + hr = PackageParseScopeFromXml(pixnBundlePackage, &pPackage->scope); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Scope."); + hr = BundlePackageEngineParseRelatedCodes(pixnBundlePackage, &pPackage->Bundle.rgsczDetectCodes, &pPackage->Bundle.cDetectCodes, &pPackage->Bundle.rgsczUpgradeCodes, &pPackage->Bundle.cUpgradeCodes, &pPackage->Bundle.rgsczAddonCodes, &pPackage->Bundle.cAddonCodes, &pPackage->Bundle.rgsczPatchCodes, &pPackage->Bundle.cPatchCodes); ExitOnFailure(hr, "Failed to parse related codes."); @@ -608,6 +613,7 @@ extern "C" HRESULT BundlePackageEngineExecutePackage( __in BURN_VARIABLES* pVariables, __in BOOL fRollback, __in BOOL fCacheAvailable, + __in BOOL fPerMachine, __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart @@ -621,7 +627,7 @@ extern "C" HRESULT BundlePackageEngineExecutePackage( BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage; - return ExecuteBundle(pCache, pVariables, fRollback, fCacheAvailable, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, FALSE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); + return ExecuteBundle(pCache, pVariables, fRollback, fCacheAvailable, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, FALSE, fPerMachine, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); } extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( @@ -629,6 +635,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( __in BURN_CACHE* pCache, __in BURN_VARIABLES* pVariables, __in BOOL fRollback, + __in BOOL fPerMachine, __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart @@ -643,7 +650,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); BURN_PACKAGE* pPackage = &pRelatedBundle->package; - return ExecuteBundle(pCache, pVariables, fRollback, TRUE, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, TRUE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); + return ExecuteBundle(pCache, pVariables, fRollback, TRUE, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, TRUE, fPerMachine, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); } extern "C" void BundlePackageEngineUpdateInstallRegistrationState( @@ -742,6 +749,7 @@ static HRESULT ExecuteBundle( __in BOOTSTRAPPER_RELATION_TYPE relationType, __in BURN_PACKAGE* pPackage, __in BOOL fPseudoPackage, + __in BOOL fPerMachine, __in_z_opt LPCWSTR wzParent, __in_z_opt LPCWSTR wzIgnoreDependencies, __in_z_opt LPCWSTR wzAncestors, @@ -987,6 +995,16 @@ static HRESULT ExecuteBundle( hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczBaseCommand, NULL); ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); + // Configurable-scope bundle packages get the scope of the parent bundle. + // Note that the command-line switch takes effect only if the BA does a + // default plan. + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope + || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope) + { + hr = StrAllocConcat(&sczBaseCommand, fPerMachine ? L" -permachine" : L" -peruser", 0); + ExitOnFailure(hr, "Failed to append scope switch to the command line."); + } + // build user args if (sczUnformattedUserArgs && *sczUnformattedUserArgs) { diff --git a/src/burn/engine/bundlepackageengine.h b/src/burn/engine/bundlepackageengine.h index 60854a073..3912bfce2 100644 --- a/src/burn/engine/bundlepackageengine.h +++ b/src/burn/engine/bundlepackageengine.h @@ -54,6 +54,7 @@ HRESULT BundlePackageEngineExecutePackage( __in BURN_VARIABLES* pVariables, __in BOOL fRollback, __in BOOL fCacheAvailable, + __in BOOL fPerMachine, __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart @@ -63,6 +64,7 @@ HRESULT BundlePackageEngineExecuteRelatedBundle( __in BURN_CACHE* pCache, __in BURN_VARIABLES* pVariables, __in BOOL fRollback, + __in BOOL fPerMachine, __in PFN_GENERICMESSAGEHANDLER pfnGenericExecuteProgress, __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index 711ce4afe..b13a59162 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -2913,7 +2913,7 @@ static HRESULT OnExecuteRelatedBundle( } // Execute related bundle. - hr = BundlePackageEngineExecuteRelatedBundle(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, pRestart); + hr = BundlePackageEngineExecuteRelatedBundle(&executeAction, pCache, pVariables, static_cast(dwRollback), TRUE/*fPerMachine*/, GenericExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute related bundle."); LExit: @@ -3008,7 +3008,7 @@ static HRESULT OnExecuteBundlePackage( } // Execute BUNDLE package. - hr = BundlePackageEngineExecutePackage(&executeAction, pCache, pVariables, fRollback, fCacheAvailable, GenericExecuteMessageHandler, hPipe, pRestart); + hr = BundlePackageEngineExecutePackage(&executeAction, pCache, pVariables, fRollback, fCacheAvailable, TRUE/*fPerMachine*/, GenericExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute BUNDLE package."); LExit: diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs index abab863a6..31dbeb9d2 100644 --- a/src/test/burn/TestBA/TestBA.cs +++ b/src/test/burn/TestBA/TestBA.cs @@ -227,7 +227,7 @@ private void ShutdownUiThread(int? exitCode = null) protected override void OnDetectBegin(DetectBeginEventArgs args) { - this.Log("OnDetectBegin"); + this.Log($"OnDetectBegin: Cached={args.Cached}, RegistrationType={args.RegistrationType}, PackageCount={args.PackageCount}"); this.forceUpdateSource = this.ReadPackageAction(null, "ForceUpdateSource"); if (!String.IsNullOrEmpty(this.forceUpdateSource)) diff --git a/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackage.wixproj b/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.props similarity index 66% rename from src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackage.wixproj rename to src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.props index 55edd2829..37cc5bd54 100644 --- a/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackage.wixproj +++ b/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.props @@ -1,11 +1,13 @@ - + Bundle + + \ No newline at end of file diff --git a/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.wxs b/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.wxs index 8b585e182..de256ccfb 100644 --- a/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.wxs +++ b/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.wxs @@ -1,11 +1,18 @@  - + + + + + - + + + + diff --git a/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackageTestBA.wixproj b/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackageTestBA.wixproj new file mode 100644 index 000000000..30d850d42 --- /dev/null +++ b/src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackageTestBA.wixproj @@ -0,0 +1,7 @@ + + + TestBA + + + + \ No newline at end of file diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs index bb1381b39..049cefc3c 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs @@ -685,6 +685,40 @@ public void PM_PU_PUOM_Bundle_PU_Plan_Installs_PerUserMostly() pkg2.VerifyInstalled(false); } + [RuntimeFact] + public void ConfigurableScopeBundlePackage_Follows_PerUser_Scope() + { + var testBAController = this.CreateTestBAController(); + testBAController.SetBundleScope(BundleScope.PerUser); + + var bundle = this.CreateBundleInstaller("PuomBundlePackageTestBA"); + var log = bundle.Install(); + + bundle.VerifyRegisteredAndInPackageCache(plannedPerMachine: false); + + Assert.True(LogVerifier.MessageInLogFile(log, "Plan begin, 2 packages, action: Install, planned scope: PerUser")); + Assert.True(LogVerifier.MessageInLogFile(log, "Planned package: AllPuomBundleTestBA.exe, state: Absent, default requested: Present, ba requested: Present, execute: Install, rollback: Uninstall, scope: PerUser")); + + bundle.Uninstall(); + bundle.VerifyUnregisteredAndRemovedFromPackageCache(plannedPerMachine: false); + } + [RuntimeFact] + public void ConfigurableScopeBundlePackage_Follows_PerMachine_Scope() + { + var testBAController = this.CreateTestBAController(); + testBAController.SetBundleScope(BundleScope.PerMachine); + + var bundle = this.CreateBundleInstaller("PuomBundlePackageTestBA"); + var log = bundle.Install(); + + bundle.VerifyRegisteredAndInPackageCache(plannedPerMachine: true); + + Assert.True(LogVerifier.MessageInLogFile(log, "Plan begin, 2 packages, action: Install, planned scope: PerMachine")); + Assert.True(LogVerifier.MessageInLogFile(log, "Planned package: AllPuomBundleTestBA.exe, state: Absent, default requested: Present, ba requested: Present, execute: Install, rollback: Uninstall, scope: PerMachine")); + + bundle.Uninstall(); + bundle.VerifyUnregisteredAndRemovedFromPackageCache(plannedPerMachine: true); + } } }