From edccb203c421d2bd820062024088c6698424d9ee Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Wed, 4 Feb 2026 20:47:04 -0500 Subject: Support dual-purpose packages in Burn. Fixes https://github.com/wixtoolset/issues/issues/8958 --- .../BootstrapperCommand.cs | 7 + .../Engine.cs | 20 +- .../IBootstrapperCommand.cs | 5 + .../IBootstrapperEngine.cs | 27 +- .../IEngine.cs | 3 +- src/api/burn/balutil/BalBootstrapperEngine.cpp | 13 +- .../burn/balutil/inc/BootstrapperApplicationBase.h | 14 +- src/api/burn/balutil/inc/IBootstrapperEngine.h | 3 +- src/api/burn/inc/BootstrapperApplicationTypes.h | 11 + src/api/burn/inc/BootstrapperEngineTypes.h | 10 +- .../WixBundleHarvestedBundlePackageSymbol.cs | 19 +- .../Symbols/WixBundleHarvestedMsiPackageSymbol.cs | 8 + .../Symbols/WixBundlePackageSymbol.cs | 32 +- .../wix/WixToolset.Data/Symbols/WixBundleSymbol.cs | 56 +- src/burn/engine/apply.cpp | 2 +- src/burn/engine/baengine.cpp | 5 +- src/burn/engine/baengine.h | 1 + src/burn/engine/cache.cpp | 8 +- src/burn/engine/core.cpp | 42 +- src/burn/engine/core.h | 5 +- src/burn/engine/dependency.cpp | 72 ++- src/burn/engine/elevation.cpp | 43 +- src/burn/engine/engine.cpp | 7 +- src/burn/engine/engine.mc | 29 +- src/burn/engine/engine.vcxproj | 17 +- src/burn/engine/externalengine.cpp | 6 +- src/burn/engine/externalengine.h | 5 +- src/burn/engine/logging.cpp | 36 ++ src/burn/engine/logging.h | 7 + src/burn/engine/msiengine.cpp | 49 +- src/burn/engine/msiengine.h | 2 + src/burn/engine/mspengine.cpp | 4 +- src/burn/engine/package.cpp | 48 +- src/burn/engine/package.h | 7 +- src/burn/engine/plan.cpp | 73 ++- src/burn/engine/plan.h | 12 + src/burn/engine/registration.cpp | 287 ++++++---- src/burn/engine/registration.h | 11 +- src/burn/engine/relatedbundle.cpp | 4 +- src/burn/engine/uithread.cpp | 2 +- src/burn/engine/variable.cpp | 2 + src/burn/test/BurnUnitTest/ApprovedExeTest.cpp | 8 +- src/burn/test/BurnUnitTest/BurnTestException.h | 14 +- src/burn/test/BurnUnitTest/BurnTestFixture.h | 8 +- src/burn/test/BurnUnitTest/BurnUnitTest.h | 8 +- src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj | 19 +- .../test/BurnUnitTest/BurnUnitTest.vcxproj.filters | 18 +- src/burn/test/BurnUnitTest/CacheTest.cpp | 10 +- src/burn/test/BurnUnitTest/ElevationTest.cpp | 8 +- src/burn/test/BurnUnitTest/EmbeddedTest.cpp | 8 +- src/burn/test/BurnUnitTest/ExitCodeTest.cpp | 12 +- src/burn/test/BurnUnitTest/LoggingTest.cpp | 8 +- src/burn/test/BurnUnitTest/ManifestHelpers.cpp | 8 +- src/burn/test/BurnUnitTest/ManifestHelpers.h | 8 +- src/burn/test/BurnUnitTest/ManifestTest.cpp | 10 +- src/burn/test/BurnUnitTest/PlanTest.cpp | 393 +++++++++++-- src/burn/test/BurnUnitTest/RegistrationTest.cpp | 56 +- src/burn/test/BurnUnitTest/RelatedBundleTest.cpp | 14 +- src/burn/test/BurnUnitTest/SearchTest.cpp | 8 +- .../TestData/PlanTest/AllPmouBundle_manifest.xml | 46 ++ .../TestData/PlanTest/AllPuomBundle_manifest.xml | 46 ++ .../BasicFunctionality_BundleA_manifest.xml | 4 +- .../PlanTest/BundlePackage_Multiple_manifest.xml | 8 +- .../ExePackage_PerUserArpEntry_manifest.xml | 6 +- .../TestData/PlanTest/Failure_BundleD_manifest.xml | 6 +- .../PlanTest/MsiTransaction_BundleAv1_manifest.xml | 8 +- .../PlanTest/MsuPackageFixture_manifest.xml | 4 +- .../PlanTest/PerMachineBundle_manifest.xml | 33 ++ .../TestData/PlanTest/PerUserBundle_manifest.xml | 33 ++ .../TestData/PlanTest/PmPmouBundle_manifest.xml | 59 ++ .../TestData/PlanTest/PmPuPmouBundle_manifest.xml | 72 +++ .../TestData/PlanTest/PmPuPuomBundle_manifest.xml | 72 +++ .../TestData/PlanTest/PmPuomBundle_manifest.xml | 59 ++ .../TestData/PlanTest/PuPmouBundle_manifest.xml | 59 ++ .../TestData/PlanTest/PuPuomBundle_manifest.xml | 59 ++ .../PlanTest/PuomBundlePackage_manifest.xml | 26 + .../PlanTest/Slipstream_BundleA_manifest.xml | 8 +- .../Slipstream_BundleA_modified_manifest.xml | 6 +- src/burn/test/BurnUnitTest/VariableHelpers.cpp | 8 +- src/burn/test/BurnUnitTest/VariableHelpers.h | 8 +- src/burn/test/BurnUnitTest/VariableTest.cpp | 8 +- src/burn/test/BurnUnitTest/VariantTest.cpp | 8 +- .../WixInternalUIBootstrapperApplication.cpp | 5 +- .../stdbas/WixStandardBootstrapperApplication.cpp | 12 +- .../WixInternal.TestSupport.Native/NativeAssert.h | 15 +- src/libs/dutil/WixToolset.DUtil/inc/strutil.h | 4 +- src/libs/dutil/WixToolset.DUtil/strutil.cpp | 4 +- src/test/burn/TestBA/TestBA.cs | 12 +- .../MultipleBundlePackagesWithRemoteBundle.wxs | 2 +- .../AllPmouBundle/AllPmouBundleTestBA.wixproj | 7 + .../AllPmouBundle/AllPmouBundleWixStdBA.wixproj | 7 + .../AllPmouBundle/Bundle.props | 14 + .../AllPmouBundle/Bundle.wxs | 19 + .../AllPuomBundle/AllPuomBundleTestBA.wixproj | 7 + .../AllPuomBundle/AllPuomBundleWixStdBA.wixproj | 7 + .../AllPuomBundle/Bundle.props | 14 + .../AllPuomBundle/Bundle.wxs | 19 + .../PerMachineBundle/Bundle.wxs | 11 + .../PerMachineBundle/PerMachineBundle.wixproj | 11 + .../PerMachinePkg/PerMachinePkg.wixproj | 2 + .../PerMachinePkg/product.wxs | 6 + .../PerUserBundle/Bundle.wxs | 11 + .../PerUserBundle/PerUserBundle.wixproj | 11 + .../PerUserPkg/PerUserPkg.wixproj | 2 + .../ConfigurableScopeTests/PerUserPkg/product.wxs | 6 + .../PmPmouBundle/Bundle.props | 15 + .../ConfigurableScopeTests/PmPmouBundle/Bundle.wxs | 20 + .../PmPmouBundle/PmPmouBundleTestBA.wixproj | 7 + .../PmPuPmouBundle/Bundle.props | 17 + .../PmPuPmouBundle/Bundle.wxs | 21 + .../PmPuPmouBundle/PmPuPmouBundleTestBA.wixproj | 7 + .../PmPuPuomBundle/Bundle.props | 17 + .../PmPuPuomBundle/Bundle.wxs | 21 + .../PmPuPuomBundle/PmPuPuomBundleTestBA.wixproj | 7 + .../PmPuomBundle/Bundle.props | 15 + .../ConfigurableScopeTests/PmPuomBundle/Bundle.wxs | 20 + .../PmPuomBundle/PmPuomBundleTestBA.wixproj | 7 + .../PmouPkg1/PmouPkg1.wixproj | 2 + .../ConfigurableScopeTests/PmouPkg1/product.wxs | 6 + .../PmouPkg2/PmouPkg2.wixproj | 2 + .../ConfigurableScopeTests/PmouPkg2/product.wxs | 6 + .../PuPmouBundle/Bundle.props | 16 + .../ConfigurableScopeTests/PuPmouBundle/Bundle.wxs | 20 + .../PuPmouBundle/PuPmouBundleTestBA.wixproj | 7 + .../PuPuomBundle/Bundle.props | 16 + .../ConfigurableScopeTests/PuPuomBundle/Bundle.wxs | 20 + .../PuPuomBundle/PuPuomBundleTestBA.wixproj | 7 + .../PuomBundlePackage/Bundle.wxs | 11 + .../PuomBundlePackage/PuomBundlePackage.wixproj | 11 + .../PuomPkg1/PuomPkg1.wixproj | 2 + .../ConfigurableScopeTests/PuomPkg1/product.wxs | 6 + .../PuomPkg2/PuomPkg2.wixproj | 2 + .../ConfigurableScopeTests/PuomPkg2/product.wxs | 6 + src/test/burn/WixTestTools/ArpEntryVerifier.cs | 16 +- src/test/burn/WixTestTools/BundleInstaller.cs | 5 +- src/test/burn/WixTestTools/BundleRegistration.cs | 13 +- src/test/burn/WixTestTools/BundleVerifier.cs | 119 ++-- .../burn/WixTestTools/GenericArpRegistration.cs | 18 +- src/test/burn/WixTestTools/PackageVerifier.cs | 26 +- src/test/burn/WixTestTools/TestTool.cs | 14 +- src/test/burn/WixTestTools/WixTestContext.cs | 4 + src/test/burn/WixToolset.WixBA/WixBA.cs | 2 +- .../WixToolsetTest.BurnE2E/BundlePackageTests.cs | 2 +- .../ConfigurableScopeTests.cs | 631 +++++++++++++++++++++ .../OptionalUpdateRegistrationTests.cs | 4 +- .../Utilities/TestBAController.cs | 5 + src/test/burn/WixToolsetTest.BurnE2E/runtests.cmd | 4 +- src/test/sandbox/TestSandbox.wsb | 17 +- .../WixToolset.Core.Burn/Bind/BindBundleCommand.cs | 27 +- ...CreateBootstrapperApplicationManifestCommand.cs | 2 +- .../Bundles/CreateBurnManifestCommand.cs | 11 +- .../Bundles/HarvestBundlePackageCommand.cs | 20 +- .../Bundles/ProcessBundlePackageCommand.cs | 2 +- .../Bundles/ProcessMsiPackageCommand.cs | 29 +- .../Bundles/ProcessMsuPackageCommand.cs | 2 +- .../WixToolset.Core.Burn/BurnBackendWarnings.cs | 6 - .../CommandLine/RemotePayloadSubcommand.cs | 18 +- src/wix/WixToolset.Core/Compiler_Bundle.cs | 49 +- .../BundleFixture.cs | 2 +- .../BundleManifestFixture.cs | 8 +- .../BundlePackageFixture.cs | 257 ++++++++- .../BurnRemotePayloadSubcommandFixture.cs | 16 +- .../ContainerFixture.cs | 4 +- .../DependencyExtensionFixture.cs | 2 +- .../ExePackageFixture.cs | 10 +- .../MsuPackageFixture.cs | 4 +- .../PackagePayloadFixture.cs | 6 +- .../RollbackBoundaryFixture.cs | 2 +- .../PerUserOrMachineBundlePackage.wxs | 9 + .../TestData/BundlePackage/RemoteBundlePackage.wxs | 2 +- .../BundlePerUser/BundleWithPerUserPackage.wxs | 9 + .../TestData/BundlePerUser/PerUserPackage.wxs | 5 + .../BundleWithPerUserOrMachinePackage.wxs | 9 + .../PerUserOrMachinePackage.wxs | 5 + 174 files changed, 3547 insertions(+), 649 deletions(-) create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/AllPmouBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/AllPuomBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PerMachineBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PerUserBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PmPmouBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PmPuPmouBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PmPuPuomBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PmPuomBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PuPmouBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PuPuomBundle_manifest.xml create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/PuomBundlePackage_manifest.xml create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPmouBundle/AllPmouBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPmouBundle/AllPmouBundleWixStdBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPmouBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPmouBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleWixStdBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerMachineBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerMachineBundle/PerMachineBundle.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerMachinePkg/PerMachinePkg.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerMachinePkg/product.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerUserBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerUserBundle/PerUserBundle.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerUserPkg/PerUserPkg.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PerUserPkg/product.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPmouBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPmouBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPmouBundle/PmPmouBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuPmouBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuPmouBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuPmouBundle/PmPuPmouBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuPuomBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuPuomBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuPuomBundle/PmPuPuomBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuomBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuomBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmPuomBundle/PmPuomBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmouPkg1/PmouPkg1.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmouPkg1/product.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmouPkg2/PmouPkg2.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PmouPkg2/product.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuPmouBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuPmouBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuPmouBundle/PuPmouBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuPuomBundle/Bundle.props create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuPuomBundle/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuPuomBundle/PuPuomBundleTestBA.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/Bundle.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuomBundlePackage/PuomBundlePackage.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuomPkg1/PuomPkg1.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuomPkg1/product.wxs create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuomPkg2/PuomPkg2.wixproj create mode 100644 src/test/burn/TestData/ConfigurableScopeTests/PuomPkg2/product.wxs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/PerUserOrMachineBundlePackage.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePerUser/BundleWithPerUserPackage.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePerUser/PerUserPackage.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePerUserOrMachine/BundleWithPerUserOrMachinePackage.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePerUserOrMachine/PerUserOrMachinePackage.wxs diff --git a/src/api/burn/WixToolset.BootstrapperApplicationApi/BootstrapperCommand.cs b/src/api/burn/WixToolset.BootstrapperApplicationApi/BootstrapperCommand.cs index 612e8ce9..795a40d4 100644 --- a/src/api/burn/WixToolset.BootstrapperApplicationApi/BootstrapperCommand.cs +++ b/src/api/burn/WixToolset.BootstrapperApplicationApi/BootstrapperCommand.cs @@ -20,6 +20,7 @@ namespace WixToolset.BootstrapperApplicationApi [MarshalAs(UnmanagedType.I4)] internal int cbSize; [MarshalAs(UnmanagedType.U4)] private readonly LaunchAction action; [MarshalAs(UnmanagedType.U4)] private readonly Display display; + [MarshalAs(UnmanagedType.U4)] private readonly BundleScope scope; private readonly IntPtr wzCommandLine; [MarshalAs(UnmanagedType.I4)] private readonly int nCmdShow; [MarshalAs(UnmanagedType.U4)] private readonly ResumeType resume; @@ -39,6 +40,7 @@ namespace WixToolset.BootstrapperApplicationApi return new BootstrapperCommand( this.action, this.display, + this.scope, Marshal.PtrToStringUni(this.wzCommandLine), this.nCmdShow, this.resume, @@ -62,6 +64,7 @@ namespace WixToolset.BootstrapperApplicationApi public BootstrapperCommand( LaunchAction action, Display display, + BundleScope scope, string commandLine, int cmdShow, ResumeType resume, @@ -74,6 +77,7 @@ namespace WixToolset.BootstrapperApplicationApi { this.Action = action; this.Display = display; + this.Scope = scope; this.CommandLine = commandLine; this.CmdShow = cmdShow; this.Resume = resume; @@ -91,6 +95,9 @@ namespace WixToolset.BootstrapperApplicationApi /// public Display Display { get; } + /// + public BundleScope Scope { get; } + /// public string CommandLine { get; } diff --git a/src/api/burn/WixToolset.BootstrapperApplicationApi/Engine.cs b/src/api/burn/WixToolset.BootstrapperApplicationApi/Engine.cs index 25413790..82978b7d 100644 --- a/src/api/burn/WixToolset.BootstrapperApplicationApi/Engine.cs +++ b/src/api/burn/WixToolset.BootstrapperApplicationApi/Engine.cs @@ -12,7 +12,7 @@ namespace WixToolset.BootstrapperApplicationApi /// public sealed class Engine : IEngine { - private IBootstrapperEngine engine; + private readonly IBootstrapperEngine engine; internal Engine(IBootstrapperEngine engine) { @@ -24,8 +24,7 @@ namespace WixToolset.BootstrapperApplicationApi { get { - int count; - this.engine.GetPackageCount(out count); + this.engine.GetPackageCount(out var count); return count; } @@ -110,8 +109,7 @@ namespace WixToolset.BootstrapperApplicationApi /// public bool EvaluateCondition(string condition) { - bool value; - this.engine.EvaluateCondition(condition, out value); + this.engine.EvaluateCondition(condition, out var value); return value; } @@ -247,9 +245,9 @@ namespace WixToolset.BootstrapperApplicationApi } /// - public void Plan(LaunchAction action) + public void Plan(LaunchAction action, BundleScope plannedScope) { - this.engine.Plan(action); + this.engine.Plan(action, plannedScope); } /// @@ -327,16 +325,16 @@ namespace WixToolset.BootstrapperApplicationApi /// public int SendEmbeddedError(int errorCode, string message, int uiHint) { - int result = 0; - this.engine.SendEmbeddedError(errorCode, message, uiHint, out result); + this.engine.SendEmbeddedError(errorCode, message, uiHint, out var result); + return result; } /// public int SendEmbeddedProgress(int progressPercentage, int overallPercentage) { - int result = 0; - this.engine.SendEmbeddedProgress(progressPercentage, overallPercentage, out result); + this.engine.SendEmbeddedProgress(progressPercentage, overallPercentage, out var result); + return result; } diff --git a/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperCommand.cs b/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperCommand.cs index a1f8bfe0..7a5a4cfd 100644 --- a/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperCommand.cs +++ b/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperCommand.cs @@ -19,6 +19,11 @@ namespace WixToolset.BootstrapperApplicationApi /// Display Display { get; } + /// + /// Gets the bundle scope if set at the command line. + /// + BundleScope Scope { get; } + /// /// Gets the command line arguments. /// diff --git a/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs b/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs index 13702757..9df57cd3 100644 --- a/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs +++ b/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs @@ -178,10 +178,11 @@ namespace WixToolset.BootstrapperApplicationApi ); /// - /// See . + /// See . /// void Plan( - [MarshalAs(UnmanagedType.U4)] LaunchAction action + [MarshalAs(UnmanagedType.U4)] LaunchAction action, + [MarshalAs(UnmanagedType.U4)] BundleScope plannedScope ); /// @@ -343,6 +344,28 @@ namespace WixToolset.BootstrapperApplicationApi UpdateReplaceEmbedded, } + /// + /// The scope of the bundle when the chain contains per-user-or-machine or per-machone-or-user packages. + /// + public enum BundleScope + { + /// + /// Let Burn choose the scope. Per-user-or-machine packages will be + /// planned as per-machine packages. + /// + Default, + + /// + /// Set per-machine scope for per-user-or-machine packages. + /// + PerMachine, + + /// + /// Set per-user scope for per-user-or-machine packages. + /// + PerUser, + } + /// /// The message log level. /// diff --git a/src/api/burn/WixToolset.BootstrapperApplicationApi/IEngine.cs b/src/api/burn/WixToolset.BootstrapperApplicationApi/IEngine.cs index 03ceed06..a763d741 100644 --- a/src/api/burn/WixToolset.BootstrapperApplicationApi/IEngine.cs +++ b/src/api/burn/WixToolset.BootstrapperApplicationApi/IEngine.cs @@ -139,7 +139,8 @@ namespace WixToolset.BootstrapperApplicationApi /// Determine the installation sequencing and costing. /// /// The action to perform when planning. - void Plan(LaunchAction action); + /// The bundle scope for per-user-or-machine packages. + void Plan(LaunchAction action, BundleScope plannedScope); /// /// Set the update information for a bundle. diff --git a/src/api/burn/balutil/BalBootstrapperEngine.cpp b/src/api/burn/balutil/BalBootstrapperEngine.cpp index 61e7e31b..14aa5c25 100644 --- a/src/api/burn/balutil/BalBootstrapperEngine.cpp +++ b/src/api/burn/balutil/BalBootstrapperEngine.cpp @@ -1188,7 +1188,8 @@ public: // IBootstrapperEngine } virtual STDMETHODIMP Plan( - __in BOOTSTRAPPER_ACTION action + __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_SCOPE plannedScope ) { HRESULT hr = S_OK; @@ -1199,17 +1200,21 @@ public: // IBootstrapperEngine PIPE_RPC_RESULT rpc = { }; // Init send structs. - args.dwApiVersion = WIX_5_BOOTSTRAPPER_APPLICATION_API_VERSION; + args.dwApiVersion = WIX_7_BOOTSTRAPPER_APPLICATION_API_VERSION; args.action = action; + args.plannedScope = plannedScope; - results.dwApiVersion = WIX_5_BOOTSTRAPPER_APPLICATION_API_VERSION; + results.dwApiVersion = WIX_7_BOOTSTRAPPER_APPLICATION_API_VERSION; // Send args. hr = BuffWriteNumberToBuffer(&bufferArgs, args.dwApiVersion); ExitOnFailure(hr, "Failed to write API version of Plan args."); hr = BuffWriteNumberToBuffer(&bufferArgs, static_cast(args.action)); - ExitOnFailure(hr, "Failed to write parent window of Plan args."); + ExitOnFailure(hr, "Failed to write action of Plan args."); + + hr = BuffWriteNumberToBuffer(&bufferArgs, static_cast(args.plannedScope)); + ExitOnFailure(hr, "Failed to write planned scope of Plan args."); // Send results. hr = BuffWriteNumberToBuffer(&bufferResults, results.dwApiVersion); diff --git a/src/api/burn/balutil/inc/BootstrapperApplicationBase.h b/src/api/burn/balutil/inc/BootstrapperApplicationBase.h index 80bfd361..41c151d9 100644 --- a/src/api/burn/balutil/inc/BootstrapperApplicationBase.h +++ b/src/api/burn/balutil/inc/BootstrapperApplicationBase.h @@ -16,7 +16,7 @@ class CBootstrapperApplicationBase : public IBootstrapperApplication public: // IUnknown virtual STDMETHODIMP QueryInterface( __in REFIID riid, - __out LPVOID *ppvObject + __out LPVOID* ppvObject ) { if (!ppvObject) @@ -478,12 +478,14 @@ public: // IBootstrapperApplication __in DWORD dwCode, __in_z LPCWSTR wzError, __in DWORD dwUIHint, - __in DWORD /*cData*/, + __in DWORD cData, __in_ecount_z_opt(cData) LPCWSTR* /*rgwzData*/, __in int /*nRecommendation*/, __inout int* pResult ) { + UNREFERENCED_PARAMETER(cData); + BalRetryErrorOccurred(wzPackageId, dwCode); if (BOOTSTRAPPER_DISPLAY_EMBEDDED == m_commandDisplay) @@ -781,12 +783,14 @@ public: // IBootstrapperApplication __in INSTALLMESSAGE /*messageType*/, __in DWORD /*dwUIHint*/, __in_z LPCWSTR /*wzMessage*/, - __in DWORD /*cData*/, + __in DWORD cData, __in_ecount_z_opt(cData) LPCWSTR* /*rgwzData*/, __in int /*nRecommendation*/, __inout int* pResult ) { + UNREFERENCED_PARAMETER(cData); + if (CheckCanceled()) { *pResult = IDCANCEL; @@ -797,13 +801,15 @@ public: // IBootstrapperApplication virtual STDMETHODIMP OnExecuteFilesInUse( __in_z LPCWSTR /*wzPackageId*/, - __in DWORD /*cFiles*/, + __in DWORD cFiles, __in_ecount_z(cFiles) LPCWSTR* /*rgwzFiles*/, __in int /*nRecommendation*/, __in BOOTSTRAPPER_FILES_IN_USE_TYPE /*source*/, __inout int* pResult ) { + UNREFERENCED_PARAMETER(cFiles); + if (CheckCanceled()) { *pResult = IDCANCEL; diff --git a/src/api/burn/balutil/inc/IBootstrapperEngine.h b/src/api/burn/balutil/inc/IBootstrapperEngine.h index 57fc9be9..ad6e6042 100644 --- a/src/api/burn/balutil/inc/IBootstrapperEngine.h +++ b/src/api/burn/balutil/inc/IBootstrapperEngine.h @@ -108,7 +108,8 @@ DECLARE_INTERFACE_IID_(IBootstrapperEngine, IUnknown, "6480D616-27A0-44D7-905B-8 ) = 0; STDMETHOD(Plan)( - __in BOOTSTRAPPER_ACTION action + __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_SCOPE plannedScope ) = 0; STDMETHOD(Elevate)( diff --git a/src/api/burn/inc/BootstrapperApplicationTypes.h b/src/api/burn/inc/BootstrapperApplicationTypes.h index 2ece1b7b..b430e04a 100644 --- a/src/api/burn/inc/BootstrapperApplicationTypes.h +++ b/src/api/burn/inc/BootstrapperApplicationTypes.h @@ -10,6 +10,7 @@ extern "C" { const LPCWSTR BOOTSTRAPPER_APPLICATION_COMMANDLINE_SWITCH_API_VERSION = L"burn.ba.apiver"; const LPCWSTR BOOTSTRAPPER_APPLICATION_COMMANDLINE_SWITCH_PIPE_NAME = L"burn.ba.pipe"; const DWORD WIX_5_BOOTSTRAPPER_APPLICATION_API_VERSION = 5; +const DWORD WIX_7_BOOTSTRAPPER_APPLICATION_API_VERSION = 7; enum BOOTSTRAPPER_DISPLAY { @@ -27,6 +28,15 @@ enum BOOTSTRAPPER_REGISTRATION_TYPE BOOTSTRAPPER_REGISTRATION_TYPE_FULL, }; +enum BOOTSTRAPPER_PACKAGE_SCOPE +{ + BOOTSTRAPPER_PACKAGE_SCOPE_INVALID, + BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE, + BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER, + BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE, + BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER, +}; + enum BOOTSTRAPPER_RESUME_TYPE { BOOTSTRAPPER_RESUME_TYPE_NONE, @@ -353,6 +363,7 @@ struct BOOTSTRAPPER_COMMAND DWORD cbSize; BOOTSTRAPPER_ACTION action; BOOTSTRAPPER_DISPLAY display; + BOOTSTRAPPER_SCOPE commandLineScope; LPWSTR wzCommandLine; INT32 nCmdShow; diff --git a/src/api/burn/inc/BootstrapperEngineTypes.h b/src/api/burn/inc/BootstrapperEngineTypes.h index f89238c0..6dced349 100644 --- a/src/api/burn/inc/BootstrapperEngineTypes.h +++ b/src/api/burn/inc/BootstrapperEngineTypes.h @@ -30,6 +30,13 @@ enum BOOTSTRAPPER_ACTION BOOTSTRAPPER_ACTION_UPDATE_REPLACE_EMBEDDED, }; +enum BOOTSTRAPPER_SCOPE +{ + BOOTSTRAPPER_SCOPE_DEFAULT, + BOOTSTRAPPER_SCOPE_PER_MACHINE, + BOOTSTRAPPER_SCOPE_PER_USER, +}; + enum BOOTSTRAPPER_ACTION_STATE { BOOTSTRAPPER_ACTION_STATE_NONE, @@ -183,7 +190,7 @@ typedef struct _BAENGINE_ESCAPESTRING_RESULTS { DWORD dwApiVersion; LPWSTR wzOut; - // Should be initialized to the size of wzOut. + // Should be initialized to the count of wzOut. DWORD cchOut; } BAENGINE_ESCAPESTRING_RESULTS; @@ -306,6 +313,7 @@ typedef struct _BAENGINE_PLAN_ARGS { DWORD dwApiVersion; BOOTSTRAPPER_ACTION action; + BOOTSTRAPPER_SCOPE plannedScope; } BAENGINE_PLAN_ARGS; typedef struct _BAENGINE_PLAN_RESULTS diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedBundlePackageSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedBundlePackageSymbol.cs index 8c969e77..adec1d78 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedBundlePackageSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedBundlePackageSymbol.cs @@ -18,6 +18,7 @@ namespace WixToolset.Data new IntermediateFieldDefinition(nameof(WixBundleHarvestedBundlePackageSymbolFields.Version), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleHarvestedBundlePackageSymbolFields.DisplayName), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleHarvestedBundlePackageSymbolFields.InstallSize), IntermediateFieldType.LargeNumber), + new IntermediateFieldDefinition(nameof(WixBundleHarvestedBundlePackageSymbolFields.Scope), IntermediateFieldType.Number), }, typeof(WixBundleHarvestedBundlePackageSymbol)); } @@ -39,13 +40,13 @@ namespace WixToolset.Data.Symbols Version, DisplayName, InstallSize, + Scope, } [Flags] public enum WixBundleHarvestedBundlePackageAttributes { None = 0x0, - PerMachine = 0x1, Win64 = 0x2, } @@ -116,20 +117,10 @@ namespace WixToolset.Data.Symbols set => this.Set((int)WixBundleHarvestedBundlePackageSymbolFields.InstallSize, value); } - public bool PerMachine + public WixBundleScopeType Scope { - get { return this.Attributes.HasFlag(WixBundleHarvestedBundlePackageAttributes.PerMachine); } - set - { - if (value) - { - this.Attributes |= WixBundleHarvestedBundlePackageAttributes.PerMachine; - } - else - { - this.Attributes &= ~WixBundleHarvestedBundlePackageAttributes.PerMachine; - } - } + get => Enum.TryParse((string)this.Fields[(int)WixBundleHarvestedBundlePackageSymbolFields.Scope], true, out WixBundleScopeType value) ? value : WixBundleScopeType.PerMachine; + set => this.Set((int)WixBundleHarvestedBundlePackageSymbolFields.Scope, (int)value); } public bool Win64 diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedMsiPackageSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedMsiPackageSymbol.cs index 8a274720..02cbc4bc 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedMsiPackageSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedMsiPackageSymbol.cs @@ -14,6 +14,7 @@ namespace WixToolset.Data new IntermediateFieldDefinition(nameof(WixBundleHarvestedMsiPackageSymbolFields.ProductName), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleHarvestedMsiPackageSymbolFields.ArpComments), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleHarvestedMsiPackageSymbolFields.AllUsers), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixBundleHarvestedMsiPackageSymbolFields.MsiInstallPerUser), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleHarvestedMsiPackageSymbolFields.MsiFastInstall), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleHarvestedMsiPackageSymbolFields.ArpSystemComponent), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleHarvestedMsiPackageSymbolFields.ProductCode), IntermediateFieldType.String), @@ -37,6 +38,7 @@ namespace WixToolset.Data.Symbols ProductName, ArpComments, AllUsers, + MsiInstallPerUser, MsiFastInstall, ArpSystemComponent, ProductCode, @@ -91,6 +93,12 @@ namespace WixToolset.Data.Symbols set => this.Set((int)WixBundleHarvestedMsiPackageSymbolFields.AllUsers, value); } + public string MsiInstallPerUser + { + get => this.Fields[(int)WixBundleHarvestedMsiPackageSymbolFields.MsiInstallPerUser].AsString(); + set => this.Set((int)WixBundleHarvestedMsiPackageSymbolFields.MsiInstallPerUser, value); + } + public string MsiFastInstall { get => this.Fields[(int)WixBundleHarvestedMsiPackageSymbolFields.MsiFastInstall].AsString(); diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageSymbol.cs index 8d625664..e888856b 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageSymbol.cs @@ -17,7 +17,7 @@ namespace WixToolset.Data new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.RepairCondition), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.Cache), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.CacheId), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.PerMachine), IntermediateFieldType.Bool), + new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.Scope), IntermediateFieldType.Number), new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.LogPathVariable), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.RollbackLogPathVariable), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.Size), IntermediateFieldType.LargeNumber), @@ -46,7 +46,7 @@ namespace WixToolset.Data.Symbols RepairCondition, Cache, CacheId, - PerMachine, + Scope, LogPathVariable, RollbackLogPathVariable, Size, @@ -144,10 +144,32 @@ namespace WixToolset.Data.Symbols set => this.Set((int)WixBundlePackageSymbolFields.CacheId, value); } - public bool? PerMachine + public WixBundleScopeType? Scope { - get => (bool?)this.Fields[(int)WixBundlePackageSymbolFields.PerMachine]; - set => this.Set((int)WixBundlePackageSymbolFields.PerMachine, value); + get => (WixBundleScopeType?)this.Fields[(int)WixBundlePackageSymbolFields.Scope].AsNullableNumber(); + set => this.Set((int)WixBundlePackageSymbolFields.Scope, (int)value); + } + + public string ScopeAsString + { + get + { + var value = (WixBundleScopeType?)this.Fields[(int)WixBundlePackageSymbolFields.Scope].AsNullableNumber(); + + switch (value) + { + case WixBundleScopeType.PerMachine: + return "perMachine"; + case WixBundleScopeType.PerUser: + return "perUser"; + case WixBundleScopeType.PerUserOrMachine: + return "perUserOrMachine"; + case WixBundleScopeType.PerMachineOrUser: + return "perMachineOrUser"; + default: + return null; + } + } } public string LogPathVariable diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundleSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundleSymbol.cs index f16cdbb8..a06a8610 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixBundleSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixBundleSymbol.cs @@ -16,6 +16,7 @@ namespace WixToolset.Data new IntermediateFieldDefinition(nameof(WixBundleSymbolFields.Name), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleSymbolFields.Manufacturer), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleSymbolFields.Attributes), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixBundleSymbolFields.Scope), IntermediateFieldType.Number), new IntermediateFieldDefinition(nameof(WixBundleSymbolFields.AboutUrl), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleSymbolFields.HelpUrl), IntermediateFieldType.String), new IntermediateFieldDefinition(nameof(WixBundleSymbolFields.HelpTelephone), IntermediateFieldType.String), @@ -42,6 +43,7 @@ namespace WixToolset.Data namespace WixToolset.Data.Symbols { using System; + using System.Xml.Linq; public enum WixBundleSymbolFields { @@ -51,6 +53,7 @@ namespace WixToolset.Data.Symbols Name, Manufacturer, Attributes, + Scope, AboutUrl, HelpUrl, HelpTelephone, @@ -78,7 +81,6 @@ namespace WixToolset.Data.Symbols { None = 0x0, DisableRemove = 0x1, - PerMachine = 0x2, } public enum WixBundleModifyType @@ -88,6 +90,14 @@ namespace WixToolset.Data.Symbols SingleChangeUninstallButton = 2, } + public enum WixBundleScopeType + { + PerMachine, + PerMachineOrUser, + PerUserOrMachine, + PerUser, + } + public class WixBundleSymbol : IntermediateSymbol { public WixBundleSymbol() : base(SymbolDefinitions.WixBundle, null, null) @@ -136,6 +146,34 @@ namespace WixToolset.Data.Symbols set => this.Set((int)WixBundleSymbolFields.Attributes, (int)value); } + public WixBundleScopeType Scope + { + get => (WixBundleScopeType)this.Fields[(int)WixBundleSymbolFields.Scope].AsNumber(); + set => this.Set((int)WixBundleSymbolFields.Scope, (int)value); + } + + public string ScopeAsString + { + get + { + var value = (WixBundleScopeType)this.Fields[(int)WixBundleSymbolFields.Scope].AsNumber(); + + switch (value) + { + case WixBundleScopeType.PerMachine: + return "perMachine"; + case WixBundleScopeType.PerUser: + return "perUser"; + case WixBundleScopeType.PerUserOrMachine: + return "perUserOrMachine"; + case WixBundleScopeType.PerMachineOrUser: + return "perMachineOrUser"; + default: + return null; + } + } + } + public string AboutUrl { get => (string)this.Fields[(int)WixBundleSymbolFields.AboutUrl]; @@ -276,21 +314,5 @@ namespace WixToolset.Data.Symbols } } } - - public bool PerMachine - { - get { return this.Attributes.HasFlag(WixBundleAttributes.PerMachine); } - set - { - if (value) - { - this.Attributes |= WixBundleAttributes.PerMachine; - } - else - { - this.Attributes &= ~WixBundleAttributes.PerMachine; - } - } - } } } diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index e4e76a6c..68aded71 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp @@ -632,7 +632,7 @@ extern "C" HRESULT ApplyCache( { hr = ElevationCachePreparePackage(hPipe, pPackage); } - LogExitOnFailure(hr, MSG_CACHE_PREPARE_PACKAGE_FAILED, "Cache prepare package failed: %ls", pPackage->sczId, NULL, NULL); + LogExitOnFailure(hr, MSG_CACHE_PREPARE_PACKAGE_FAILED, "Cache prepare package failed: %ls", pPackage->sczId); } hr = ApplyCachePackage(&cacheContext, pPackage); diff --git a/src/burn/engine/baengine.cpp b/src/burn/engine/baengine.cpp index d1704ad9..e48f71c0 100644 --- a/src/burn/engine/baengine.cpp +++ b/src/burn/engine/baengine.cpp @@ -1134,12 +1134,15 @@ static HRESULT BAEnginePlan( hr = BuffReaderReadNumber(pReaderArgs, reinterpret_cast(&args.action)); ExitOnFailure(hr, "Failed to read plan action of BAEnginePlan args."); + hr = BuffReaderReadNumber(pReaderArgs, reinterpret_cast(&args.plannedScope)); + ExitOnFailure(hr, "Failed to read plan scope of BAEnginePlan args."); + // Read results. hr = BuffReaderReadNumber(pReaderResults, &results.dwApiVersion); ExitOnFailure(hr, "Failed to read API version of BAEnginePlan results."); // Execute. - hr = ExternalEnginePlan(pContext, args.action); + hr = ExternalEnginePlan(pContext, args.action, args.plannedScope); ExitOnFailure(hr, "Failed to plan in the engine."); // Pack result. diff --git a/src/burn/engine/baengine.h b/src/burn/engine/baengine.h index 97cfea9c..39e5ae0b 100644 --- a/src/burn/engine/baengine.h +++ b/src/burn/engine/baengine.h @@ -31,6 +31,7 @@ typedef struct _BAENGINE_ACTION struct { BOOTSTRAPPER_ACTION action; + BOOTSTRAPPER_SCOPE plannedScope; } plan; struct { diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index c85a1be4..21bd42be 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp @@ -36,8 +36,8 @@ static HRESULT SecurePerMachineCacheRoot( static HRESULT CreateCompletedPath( __in BURN_CACHE* pCache, __in BOOL fPerMachine, - __in LPCWSTR wzCacheId, - __in LPCWSTR wzFilePath, + __in_z LPCWSTR wzId, + __in_z_opt LPCWSTR wzFilePath, __out_z LPWSTR* psczCachePath ); static HRESULT CreateUnverifiedPath( @@ -1658,8 +1658,8 @@ LExit: static HRESULT CreateCompletedPath( __in BURN_CACHE* pCache, __in BOOL fPerMachine, - __in LPCWSTR wzId, - __in LPCWSTR wzFilePath, + __in_z LPCWSTR wzId, + __in_z_opt LPCWSTR wzFilePath, __out_z LPWSTR* psczCachePath ) { diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 2dfa4857..7937bd65 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -379,7 +379,7 @@ extern "C" HRESULT CoreDetect( pEngineState->registration.fEligibleForCleanup = FALSE; } - LogId(REPORT_STANDARD, MSG_DETECTED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingBoolToString(pPackage->fCached), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->installRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->cacheRegistrationState)); + LogId(REPORT_STANDARD, MSG_DETECTED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingBoolToString(pPackage->fCached), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->installRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->cacheRegistrationState), LoggingPackageScopeToString(pPackage->scope)); if (BURN_PACKAGE_TYPE_MSI == pPackage->type) { @@ -424,8 +424,9 @@ LExit: extern "C" HRESULT CorePlan( __in BURN_ENGINE_STATE* pEngineState, - __in BOOTSTRAPPER_ACTION action - ) + __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_SCOPE plannedScope +) { HRESULT hr = S_OK; BOOL fPlanBegan = FALSE; @@ -433,7 +434,7 @@ extern "C" HRESULT CorePlan( BURN_PACKAGE* pForwardCompatibleBundlePackage = NULL; BOOL fContinuePlanning = TRUE; // assume we won't skip planning due to dependencies. - LogId(REPORT_STANDARD, MSG_PLAN_BEGIN, pEngineState->packages.cPackages, LoggingBurnActionToString(action)); + LogId(REPORT_STANDARD, MSG_PLAN_BEGIN, pEngineState->packages.cPackages, LoggingBurnActionToString(action), LoggingBundleScopeToString(plannedScope)); fPlanBegan = TRUE; hr = BACallbackOnPlanBegin(&pEngineState->userExperience, pEngineState->packages.cPackages); @@ -452,12 +453,13 @@ extern "C" HRESULT CorePlan( pEngineState->fPlanned = FALSE; PlanReset(&pEngineState->plan, &pEngineState->variables, &pEngineState->containers, &pEngineState->packages, &pEngineState->layoutPayloads); - hr = PlanSetVariables(action, &pEngineState->variables); - ExitOnFailure(hr, "Failed to update action."); + hr = PlanSetVariables(action, pEngineState->registration.scope, pEngineState->plan.plannedScope, &pEngineState->variables); + ExitOnFailure(hr, "Failed to update plan variables."); // Remember the overall action state in the plan since it shapes the changes // we make everywhere. pEngineState->plan.action = action; + pEngineState->plan.plannedScope = plannedScope; pEngineState->plan.pCache = &pEngineState->cache; pEngineState->plan.pCommand = &pEngineState->command; pEngineState->plan.pInternalCommand = &pEngineState->internalCommand; @@ -467,6 +469,17 @@ extern "C" HRESULT CorePlan( pEngineState->plan.fDisableRollback = pEngineState->fDisableRollback || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pEngineState->plan.action; pEngineState->plan.fPlanPackageCacheRollback = BOOTSTRAPPER_REGISTRATION_TYPE_NONE == pEngineState->registration.detectedRegistrationType; + hr = PlanPackagesAndBundleScope(pEngineState->packages.rgPackages, pEngineState->packages.cPackages, pEngineState->plan.plannedScope, pEngineState->registration.scope, pEngineState->command.commandLineScope, &pEngineState->plan.plannedScope, &pEngineState->registration.fPerMachine); + ExitOnFailure(hr, "Failed to determine packages and bundle scope."); + + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pEngineState->registration.scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pEngineState->registration.scope) + { + LogId(REPORT_STANDARD, MSG_PLAN_CONFIGURED_SCOPE, LoggingInstallScopeToString(pEngineState->registration.fPerMachine)); + } + + hr = RegistrationSetPaths(&pEngineState->registration, &pEngineState->cache); + ExitOnFailure(hr, "Failed to set registration paths."); + // Set resume commandline hr = PlanSetResumeCommand(&pEngineState->plan, &pEngineState->registration, &pEngineState->log); ExitOnFailure(hr, "Failed to set resume command"); @@ -475,7 +488,7 @@ extern "C" HRESULT CorePlan( ExitOnFailure(hr, "Failed to initialize the dependencies for the plan."); hr = RegistrationPlanInitialize(&pEngineState->registration); - ExitOnFailure(hr, "Failed to initialize registration for the plan."); + ExitOnFailure(hr, "Failed to initialize the plan for registration."); if (BOOTSTRAPPER_ACTION_LAYOUT == action) { @@ -556,6 +569,9 @@ extern "C" HRESULT CorePlan( LogPackages(pUpgradeBundlePackage, pForwardCompatibleBundlePackage, &pEngineState->packages, &pEngineState->registration.relatedBundles, action); } + hr = PlanSetVariables(action, pEngineState->registration.scope, pEngineState->plan.plannedScope, &pEngineState->variables); + ExitOnFailure(hr, "Failed to update plan variables after planning."); + PlanDump(&pEngineState->plan); LExit: @@ -1331,7 +1347,7 @@ extern "C" void CoreCleanup( ExitFunction(); } - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); ExitOnFailure(hr, "Plan during cleanup failed"); hr = CoreApply(pEngineState, pEngineState->hMessageWindow); @@ -1470,6 +1486,14 @@ extern "C" HRESULT CoreParseCommandLine( { pInternalCommand->fDisableSystemRestore = TRUE; } + else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"peruser", -1, TRUE)) + { + pCommand->commandLineScope = BOOTSTRAPPER_SCOPE_PER_USER; + } + else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"permachine", -1, TRUE)) + { + pCommand->commandLineScope = BOOTSTRAPPER_SCOPE_PER_MACHINE; + } else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"originalsource", -1, TRUE)) { if (i + 1 >= argc) @@ -2346,7 +2370,7 @@ static void LogPackages( LogRollbackBoundary(pPackage->pRollbackBoundaryBackward); } - LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingPlannedCacheToString(pPackage), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState)); + LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingPlannedCacheToString(pPackage), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState), LoggingInstallScopeToString(pPackage->fPerMachine)); if (BURN_PACKAGE_TYPE_MSI == pPackage->type) { diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h index cf615e35..75c0c941 100644 --- a/src/burn/engine/core.h +++ b/src/burn/engine/core.h @@ -45,7 +45,9 @@ const LPCWSTR BURN_BUNDLE_EXECUTE_PACKAGE_ACTION = L"WixBundleExecutePackageActi const LPCWSTR BURN_BUNDLE_FORCED_RESTART_PACKAGE = L"WixBundleForcedRestartPackage"; const LPCWSTR BURN_BUNDLE_INSTALLED = L"WixBundleInstalled"; const LPCWSTR BURN_BUNDLE_ELEVATED = L"WixBundleElevated"; +const LPCWSTR BURN_BUNDLE_PLANNED_SCOPE = L"WixBundlePlannedScope"; const LPCWSTR BURN_BUNDLE_PROVIDER_KEY = L"WixBundleProviderKey"; +const LPCWSTR BURN_BUNDLE_SCOPE = L"WixBundleScope"; const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_PATH = L"WixBundleSourceProcessPath"; const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_FOLDER = L"WixBundleSourceProcessFolder"; const LPCWSTR BURN_BUNDLE_TAG = L"WixBundleTag"; @@ -243,7 +245,8 @@ HRESULT CoreDetect( ); HRESULT CorePlan( __in BURN_ENGINE_STATE* pEngineState, - __in BOOTSTRAPPER_ACTION action + __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_SCOPE scope ); HRESULT CoreElevate( __in BURN_ENGINE_STATE* pEngineState, diff --git a/src/burn/engine/dependency.cpp b/src/burn/engine/dependency.cpp index 94a8a1e4..7cd0db9f 100644 --- a/src/burn/engine/dependency.cpp +++ b/src/burn/engine/dependency.cpp @@ -12,6 +12,7 @@ const LPCWSTR vcszIgnoreDependenciesDelim = L";"; static HRESULT DetectPackageDependents( __in BURN_PACKAGE* pPackage, + __in BOOL fPackagePerMachine, __in const BURN_REGISTRATION* pRegistration ); @@ -249,7 +250,22 @@ extern "C" HRESULT DependencyDetectProviderKeyBundleCode( { HRESULT hr = S_OK; - hr = DepGetProviderInformation(pRegistration->hkRoot, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + // For configurable packages, check both scopes because until planning, + // we can't know their planned scope. + if (pRegistration->hkRoot) + { + hr = DepGetProviderInformation(pRegistration->hkRoot, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + } + else + { + hr = DepGetProviderInformation(HKEY_LOCAL_MACHINE, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + + if (E_NOTFOUND == hr) + { + hr = DepGetProviderInformation(HKEY_CURRENT_USER, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + } + } + if (E_NOTFOUND == hr) { ReleaseNullStr(pRegistration->sczDetectedProviderKeyBundleCode); @@ -284,7 +300,21 @@ extern "C" HRESULT DependencyDetectBundle( hr = DependencyDetectProviderKeyBundleCode(pRegistration); ExitOnFailure(hr, "Failed to detect provider key bundle code."); - hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + // For configurable packages, check both scopes because until planning, + // we can't know their planned scope. + if (pRegistration->hkRoot) + { + hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + } + else + { + hr = DepCheckDependents(HKEY_LOCAL_MACHINE, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + + if (E_NOTFOUND == hr) + { + hr = DepCheckDependents(HKEY_CURRENT_USER, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + } + } ExitOnPathFailure(hr, fExists, "Failed dependents check on bundle."); if (pDependencies->fSelfDependent || pDependencies->fActiveParent) @@ -292,13 +322,13 @@ extern "C" HRESULT DependencyDetectBundle( for (DWORD i = 0; i < pRegistration->cDependents; ++i) { DEPENDENCY* pDependent = pRegistration->rgDependents + i; - - if (pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzActiveParent, -1, pDependent->sczKey, -1, TRUE)) + + if (pDependent && pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzActiveParent, -1, pDependent->sczKey, -1, TRUE)) { pRegistration->fParentRegisteredAsDependent = TRUE; } - if (pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzSelfDependent, -1, pDependent->sczKey, -1, TRUE)) + if (pDependent && pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzSelfDependent, -1, pDependent->sczKey, -1, TRUE)) { pRegistration->fSelfRegisteredAsDependent = TRUE; } @@ -316,11 +346,24 @@ extern "C" HRESULT DependencyDetectChainPackage( { HRESULT hr = S_OK; - hr = DetectPackageDependents(pPackage, pRegistration); - ExitOnFailure(hr, "Failed to detect dependents for package '%ls'", pPackage->sczId); + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope) + { + // For configurable packages, check both scopes because until planning, + // we can't know their planned scope. + hr = DetectPackageDependents(pPackage, /*fPerMachine*/TRUE, pRegistration); + ExitOnFailure(hr, "Failed to detect per-machine dependents for configurable package '%ls'", pPackage->sczId); + + hr = DetectPackageDependents(pPackage, /*fPerMachine*/FALSE, pRegistration); + ExitOnFailure(hr, "Failed to detect per-user dependents for configurable package '%ls'", pPackage->sczId); + } + else + { + hr = DetectPackageDependents(pPackage, pPackage->fPerMachine, pRegistration); + ExitOnFailure(hr, "Failed to detect dependents for %hs package '%ls'", LoggingInstallScopeToString(pPackage->fPerMachine), pPackage->sczId); + } hr = DependencyDetectCompatibleEntry(pPackage, pRegistration); - ExitOnFailure(hr, "Failed to detect compatible package for package '%ls'", pPackage->sczId); + ExitOnFailure(hr, "Failed to detect compatible package for %hs package '%ls'", LoggingInstallScopeToString(pPackage->fPerMachine), pPackage->sczId); LExit: return hr; @@ -336,7 +379,7 @@ extern "C" HRESULT DependencyDetectRelatedBundle( if (pRelatedBundle->fPlannable) { - hr = DetectPackageDependents(pPackage, pRegistration); + hr = DetectPackageDependents(pPackage, pPackage->fPerMachine, pRegistration); ExitOnFailure(hr, "Failed to detect dependents for related bundle '%ls'", pPackage->sczId); } @@ -626,7 +669,7 @@ LExit: } extern "C" HRESULT DependencyPlanPackage( - __in_opt DWORD *pdwInsertSequence, + __in_opt DWORD* pdwInsertSequence, __in const BURN_PACKAGE* pPackage, __in BURN_PLAN* pPlan ) @@ -946,18 +989,19 @@ LExit: static HRESULT DetectPackageDependents( __in BURN_PACKAGE* pPackage, + __in BOOL fPackagePerMachine, __in const BURN_REGISTRATION* pRegistration ) { HRESULT hr = S_OK; - HKEY hkHive = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + HKEY hkHive = fPackagePerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; BOOL fCanIgnorePresence = pPackage->fCanAffectRegistration && 0 < pPackage->cDependencyProviders && (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->cacheRegistrationState || BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->installRegistrationState); BOOL fBundleRegisteredAsDependent = FALSE; // There's currently no point in getting the dependents if the scope doesn't match, // because they will just get ignored. - if (pRegistration->fPerMachine != pPackage->fPerMachine) + if (pRegistration->fPerMachine != fPackagePerMachine) { ExitFunction(); } @@ -979,7 +1023,7 @@ static HRESULT DetectPackageDependents( { DEPENDENCY* pDependent = pProvider->rgDependents + iDependent; - if (CSTR_EQUAL == ::CompareStringOrdinal(pRegistration->sczCode, -1, pDependent->sczKey, -1, TRUE)) + if (pDependent && CSTR_EQUAL == ::CompareStringOrdinal(pRegistration->sczCode, -1, pDependent->sczKey, -1, TRUE)) { pProvider->fBundleRegisteredAsDependent = TRUE; fBundleRegisteredAsDependent = TRUE; @@ -994,10 +1038,12 @@ static HRESULT DetectPackageDependents( { pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; } + if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->installRegistrationState) { pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; } + if (BURN_PACKAGE_TYPE_MSP == pPackage->type) { for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index ef87841f..711ce4af 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -1191,7 +1191,6 @@ extern "C" HRESULT ElevationExecuteMsiPackage( hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData); ExitOnFailure(hr, "Failed to write variables."); - // send message context.pfnMessageHandler = pfnMessageHandler; context.pvContext = pvContext; @@ -2572,6 +2571,11 @@ static HRESULT OnSessionBegin( ExitOnFailure(hr, "Failed to read variables."); // Begin session in per-machine process. + pRegistration->fPerMachine = TRUE; + + hr = RegistrationSetPaths(pRegistration, pCache); + ExitOnFailure(hr, "Failed to set elevated registration paths."); + hr = RegistrationSessionBegin(sczEngineWorkingPath, pRegistration, pCache, pVariables, dwRegistrationOperations, qwEstimatedSize, (BOOTSTRAPPER_REGISTRATION_TYPE)dwRegistrationType); ExitOnFailure(hr, "Failed to begin registration session."); @@ -2657,6 +2661,8 @@ static HRESULT OnCachePreparePackage( { hr = PackageFindById(pPackages, scz, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", scz); + + pPackage->fPerMachine = TRUE; } else { @@ -2698,6 +2704,8 @@ static HRESULT OnCacheCompletePayload( { hr = PackageFindById(pPackages, scz, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", scz); + + pPackage->fPerMachine = TRUE; } hr = BuffReadString(pbData, cbData, &iData, &scz); @@ -2717,8 +2725,8 @@ static HRESULT OnCacheCompletePayload( if (pPackage && pPayload) // complete payload. { - hr = CacheCompletePayload(pCache, pPackage->fPerMachine, pPayload, pPackage->sczCacheId, sczUnverifiedPath, fMove, BurnCacheMessageHandler, ElevatedProgressRoutine, hPipe); - ExitOnFailure(hr, "Failed to cache payload: %ls", pPayload->sczKey); + hr = CacheCompletePayload(pCache, TRUE/*fPerMachine*/, pPayload, pPackage->sczCacheId, sczUnverifiedPath, fMove, BurnCacheMessageHandler, ElevatedProgressRoutine, hPipe); + ExitOnFailure(hr, "Failed to cache per-machine payload: %ls", pPayload->sczKey); } else { @@ -2755,6 +2763,8 @@ static HRESULT OnCacheVerifyPayload( { hr = PackageFindById(pPackages, scz, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", scz); + + pPackage->fPerMachine = TRUE; } hr = BuffReadString(pbData, cbData, &iData, &scz); @@ -2970,6 +2980,8 @@ static HRESULT OnExecuteBundlePackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.bundlePackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.bundlePackage.pPackage->fPerMachine = TRUE; + if (BURN_PACKAGE_TYPE_BUNDLE != executeAction.bundlePackage.pPackage->type) { ExitWithRootFailure(hr, E_INVALIDARG, "Package is not a BUNDLE package: %ls", sczPackage); @@ -3052,6 +3064,8 @@ static HRESULT OnExecuteExePackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.exePackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.exePackage.pPackage->fPerMachine = TRUE; + if (BURN_PACKAGE_TYPE_EXE != executeAction.exePackage.pPackage->type) { ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage); @@ -3113,6 +3127,8 @@ static HRESULT OnExecuteMsiPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.msiPackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.msiPackage.pPackage->fPerMachine = TRUE; + hr = BuffReadPointer(pbData, cbData, &iData, (DWORD_PTR*)&hwndParent); ExitOnFailure(hr, "Failed to read parent hwnd."); @@ -3205,6 +3221,8 @@ static HRESULT OnExecuteMspPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.mspTarget.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.mspTarget.pPackage->fPerMachine = TRUE; + hr = BuffReadPointer(pbData, cbData, &iData, (DWORD_PTR*)&hwndParent); ExitOnFailure(hr, "Failed to read parent hwnd."); @@ -3246,6 +3264,8 @@ static HRESULT OnExecuteMspPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.mspTarget.rgOrderedPatches[i].pPackage); ExitOnFailure(hr, "Failed to find ordered patch package: %ls", sczPackage); + + executeAction.mspTarget.rgOrderedPatches[i].pPackage->fPerMachine = TRUE; } } @@ -3310,6 +3330,8 @@ static HRESULT OnExecuteMsuPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.msuPackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.msuPackage.pPackage->fPerMachine = TRUE; + if (BURN_PACKAGE_TYPE_MSU != executeAction.msuPackage.pPackage->type) { ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSU package: %ls", sczPackage); @@ -3371,6 +3393,8 @@ static HRESULT OnUninstallMsiCompatiblePackage( hr = PackageFindById(pPackages, sczPackageId, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId); + pPackage->fPerMachine = TRUE; + executeAction.uninstallMsiCompatiblePackage.pParentPackage = pPackage; pCompatiblePackage = &pPackage->compatiblePackage; @@ -3424,6 +3448,8 @@ static HRESULT OnExecutePackageProviderAction( } ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.packageProvider.pPackage->fPerMachine; + hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback); ExitOnFailure(hr, "Failed to read rollback flag."); @@ -3436,11 +3462,6 @@ static HRESULT OnExecutePackageProviderAction( ExitOnFailure(hr, "Failed to read provider action."); } - if (!executeAction.packageProvider.pPackage->fPerMachine) - { - ExitWithRootFailure(hr, E_INVALIDARG, "ExecutePackageProviderAction called for per-user package."); - } - // Execute the package provider action. hr = DependencyExecutePackageProviderAction(&executeAction, fRollback); ExitOnFailure(hr, "Failed to execute package provider action."); @@ -3479,6 +3500,8 @@ static HRESULT OnExecutePackageDependencyAction( } ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.packageDependency.pPackage->fPerMachine = TRUE; + hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback); ExitOnFailure(hr, "Failed to read rollback flag."); @@ -3784,6 +3807,8 @@ static HRESULT OnCleanCompatiblePackage( hr = PackageFindById(pPackages, sczPackageId, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId); + pPackage->fPerMachine = TRUE; + pCompatiblePackage = &pPackage->compatiblePackage; if (!pCompatiblePackage->fDetected || !pCompatiblePackage->compatibleEntry.sczId || !pCompatiblePackage->sczCacheId || !*pCompatiblePackage->sczCacheId) @@ -3826,6 +3851,8 @@ static HRESULT OnCleanPackage( hr = PackageFindById(pPackages, sczPackage, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + pPackage->fPerMachine = TRUE; + // Remove the package from the cache. hr = CacheRemovePackage(pCache, TRUE, pPackage->sczId, pPackage->sczCacheId); ExitOnFailure(hr, "Failed to remove from cache package: %ls", pPackage->sczId); diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index d432f732..8423da41 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp @@ -16,11 +16,6 @@ static HRESULT InitializeEngineState( static void UninitializeEngineState( __in BURN_ENGINE_STATE* pEngineState ); -#if 0 -static HRESULT RunUntrusted( - __in BURN_ENGINE_STATE* pEngineState - ); -#endif static HRESULT RunNormal( __in HINSTANCE hInstance, __in BURN_ENGINE_STATE* pEngineState @@ -812,7 +807,7 @@ static HRESULT ProcessMessage( break; case WM_BURN_PLAN: - hr = CorePlan(pEngineState, pAction->plan.action); + hr = CorePlan(pEngineState, pAction->plan.action, pAction->plan.plannedScope); break; case WM_BURN_ELEVATE: diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 776f7832..8e2f1a2e 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc @@ -271,7 +271,7 @@ MessageId=101 Severity=Success SymbolicName=MSG_DETECTED_PACKAGE Language=English -Detected package: %1!ls!, state: %2!hs!, cached: %3!hs!, install registration state: %4!hs!, cache registration state: %5!hs! +Detected package: %1!ls!, state: %2!hs!, authored scope: %6!hs!, cached: %3!hs!, install registration state: %4!hs!, cache registration state: %5!hs! . MessageId=102 @@ -404,14 +404,21 @@ MessageId=200 Severity=Success SymbolicName=MSG_PLAN_BEGIN Language=English -Plan begin, %1!u! packages, action: %2!hs! +Plan begin, %1!u! packages, action: %2!hs!, planned scope: %3!hs! +. + +MessageId=226 +Severity=Success +SymbolicName=MSG_PLAN_CONFIGURED_SCOPE +Language=English +Planned configurable scope: %1!hs! . MessageId=201 Severity=Success SymbolicName=MSG_PLANNED_PACKAGE Language=English -Planned package: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, default cache strategy: %7!hs!, ba requested strategy: %8!hs!, cache: %9!hs!, uncache: %10!hs!, dependency: %11!hs!, expected install registration state: %12!hs!, expected cache registration state: %13!hs! +Planned package: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, scope: %14!hs!, default cache strategy: %7!hs!, ba requested strategy: %8!hs!, cache: %9!hs!, uncache: %10!hs!, dependency: %11!hs!, expected install registration state: %12!hs!, expected cache registration state: %13!hs! . MessageId=203 @@ -782,7 +789,7 @@ MessageId=328 Severity=Warning SymbolicName=MSG_DEPENDENCY_PACKAGE_DEPENDENT Language=English -Found dependent: %1!ls!, name: %2!ls! + Found dependent: %1!ls!, name: %2!ls! . MessageId=329 @@ -1288,3 +1295,17 @@ SymbolicName=MSG_DEPENDENCY_PACKAGE_DEPENDENTS_OVERRIDDEN Language=English BA requested to uninstall package: %1!ls!, despite dependents: . +MessageId=702 +Severity=Warning +SymbolicName=MSG_SCOPE_IGNORED_BA_SCOPE +Language=English +Scope command-line switch ignored because the bootstrapper application already specified a scope. +. + +MessageId=703 +Severity=Warning +SymbolicName=MSG_SCOPE_IGNORED_UNCONFIGURABLE +Language=English +Scope command-line switch ignored because the bundle doesn't have any packages with configurable scope. +. + diff --git a/src/burn/engine/engine.vcxproj b/src/burn/engine/engine.vcxproj index 98556ea6..5ab9f1ce 100644 --- a/src/burn/engine/engine.vcxproj +++ b/src/burn/engine/engine.vcxproj @@ -1,6 +1,5 @@ - @@ -28,7 +27,6 @@ ARM64 - {8119537D-E1D9-6591-D51A-49768A2F9C37} StaticLibrary @@ -37,20 +35,15 @@ Native component of WixToolset.Burn ClCompile - - ..\..\api\burn\inc;$(BurnGeneratedHeaderDirectory);$(ProjectAdditionalIncludeDirectories) - - - @@ -97,7 +90,6 @@ - @@ -147,7 +139,6 @@ - Compiling message file... @@ -157,7 +148,6 @@ rc.exe -fo "$(OutDir)engine.res" "$(IntDir)engine.messages.rc" $(IntDir)engine.messages.h;$(IntDir)engine.messages.rc - $(SomeVerInfoMajor) @@ -172,11 +162,12 @@ rc.exe -fo "$(OutDir)engine.res" "$(IntDir)engine.messages.rc" - - + + + - + \ No newline at end of file diff --git a/src/burn/engine/externalengine.cpp b/src/burn/engine/externalengine.cpp index 352d184c..d4814dc1 100644 --- a/src/burn/engine/externalengine.cpp +++ b/src/burn/engine/externalengine.cpp @@ -633,8 +633,9 @@ LExit: HRESULT ExternalEnginePlan( __in BAENGINE_CONTEXT* pEngineContext, - __in const BOOTSTRAPPER_ACTION action - ) + __in const BOOTSTRAPPER_ACTION action, + __in const BOOTSTRAPPER_SCOPE plannedScope +) { HRESULT hr = S_OK; BAENGINE_ACTION* pAction = NULL; @@ -649,6 +650,7 @@ HRESULT ExternalEnginePlan( pAction->dwMessage = WM_BURN_PLAN; pAction->plan.action = action; + pAction->plan.plannedScope = plannedScope; hr = EnqueueAction(pEngineContext, &pAction); ExitOnFailure(hr, "Failed to enqueue plan action."); diff --git a/src/burn/engine/externalengine.h b/src/burn/engine/externalengine.h index 9b95e645..1053d0c0 100644 --- a/src/burn/engine/externalengine.h +++ b/src/burn/engine/externalengine.h @@ -146,8 +146,9 @@ HRESULT ExternalEngineDetect( HRESULT ExternalEnginePlan( __in BAENGINE_CONTEXT* pEngineContext, - __in const BOOTSTRAPPER_ACTION action - ); + __in const BOOTSTRAPPER_ACTION action, + __in const BOOTSTRAPPER_SCOPE plannedScope +); HRESULT ExternalEngineElevate( __in BAENGINE_CONTEXT* pEngineContext, diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 52123499..47f52d27 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -968,6 +968,42 @@ extern "C" LPCSTR LoggingInstallScopeToString( return fPerMachine ? "PerMachine" : "PerUser"; } +extern "C" LPCSTR LoggingPackageScopeToString( + __in BOOTSTRAPPER_PACKAGE_SCOPE scope + ) +{ + switch (scope) + { + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE: + return "PerMachine"; + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER: + return "PerMachineOrUser"; + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE: + return "PerUserOrMachine"; + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER: + return "PerUser"; + default: + return "Invalid"; + } +} + +extern "C" LPCSTR LoggingBundleScopeToString( + __in BOOTSTRAPPER_SCOPE scope + ) +{ + switch (scope) + { + case BOOTSTRAPPER_SCOPE_DEFAULT: + return "Default"; + case BOOTSTRAPPER_SCOPE_PER_MACHINE: + return "PerMachine"; + case BOOTSTRAPPER_SCOPE_PER_USER: + return "PerUser"; + default: + return "Invalid"; + } +} + // internal function declarations diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h index b28a53d4..76103732 100644 --- a/src/burn/engine/logging.h +++ b/src/burn/engine/logging.h @@ -202,6 +202,13 @@ LPCSTR LoggingInstallScopeToString( __in BOOL fPerMachine ); +LPCSTR LoggingPackageScopeToString( + __in BOOTSTRAPPER_PACKAGE_SCOPE scope + ); + +LPCSTR LoggingBundleScopeToString( + __in BOOTSTRAPPER_SCOPE scope + ); #if defined(__cplusplus) } diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp index a1379054..11bb8a0e 100644 --- a/src/burn/engine/msiengine.cpp +++ b/src/burn/engine/msiengine.cpp @@ -454,7 +454,18 @@ extern "C" HRESULT MsiEngineDetectPackage( // detect self by product code // TODO: what to do about MSIINSTALLCONTEXT_USERMANAGED? - hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope) + { + hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, MSIINSTALLCONTEXT_MACHINE, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + if (FAILED(hr)) + { + hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + } + } + else + { + hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, pPackage->scope == BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + } if (SUCCEEDED(hr)) { fDetectFeatures = TRUE; @@ -777,7 +788,18 @@ extern "C" HRESULT MsiEngineDetectCompatiblePackage( ExitFunction(); } - hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope) + { + hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, MSIINSTALLCONTEXT_MACHINE, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + if (FAILED(hr)) + { + hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + } + } + else + { + hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, pPackage->scope == BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + } if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) == hr || E_INVALIDARG == hr) { ExitFunction1(hr = S_OK); @@ -1336,10 +1358,10 @@ extern "C" HRESULT MsiEngineExecutePackage( hr = ConcatPatchProperty(pCache, pPackage, fRollback, &sczObfuscatedProperties); ExitOnFailure(hr, "Failed to add patch properties to obfuscated argument string."); - hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, &sczProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, pExecuteAction->msiPackage.pPackage->scope, pExecuteAction->msiPackage.pPackage->fPerMachine, &sczProperties); ExitOnFailure(hr, "Failed to add action property to argument string."); - hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, &sczObfuscatedProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, pPackage->scope, pPackage->fPerMachine, &sczObfuscatedProperties); ExitOnFailure(hr, "Failed to add action property to obfuscated argument string."); LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->msiPackage.action), sczMsiPath, sczObfuscatedProperties ? sczObfuscatedProperties : L""); @@ -1449,7 +1471,7 @@ extern "C" HRESULT MsiEngineUninstallCompatiblePackage( ExitOnFailure(hr, "Failed to enable logging for compatible package: %ls to: %ls", pCompatibleEntry->sczId, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath); } - hr = MsiEngineConcatBurnProperties(action, burnMsiProperty, fileVersioning, TRUE, FALSE, &sczProperties); + hr = MsiEngineConcatBurnProperties(action, burnMsiProperty, fileVersioning, TRUE, FALSE, pParentPackage->scope, pParentPackage->fPerMachine, &sczProperties); ExitOnFailure(hr, "Failed to add action property to argument string."); LogId(REPORT_STANDARD, MSG_APPLYING_ORPHAN_COMPATIBLE_PACKAGE, LoggingRollbackOrExecute(fRollback), pCompatibleEntry->sczId, pParentPackage->sczId, LoggingActionStateToString(action), sczProperties ? sczProperties : L""); @@ -1491,6 +1513,8 @@ extern "C" HRESULT MsiEngineConcatBurnProperties( __in BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning, __in BOOL fMsiPackage, __in BOOL fFeatureSelectionEnabled, + __in BOOTSTRAPPER_PACKAGE_SCOPE scope, + __in BOOL fPlannedPerMachineScope, __deref_out_z LPWSTR* psczProperties ) { @@ -1534,6 +1558,7 @@ extern "C" HRESULT MsiEngineConcatBurnProperties( break; } + // Append properties used by WixUI (and usable otherwise) to adjust internal UI behavior. switch (actionMsiProperty) { case BURN_MSI_PROPERTY_INSTALL: @@ -1581,6 +1606,20 @@ extern "C" HRESULT MsiEngineConcatBurnProperties( ExitOnFailure(hr, "Failed to add reinstall mode."); } + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == scope) + { + if (fPlannedPerMachineScope) + { + hr = StrAllocConcatFormattedSecure(psczProperties, L" MSIINSTALLPERUSER=\"\""); + ExitOnFailure(hr, "Failed to add per-machine scope properties."); + } + else + { + hr = StrAllocConcatFormattedSecure(psczProperties, L" MSIINSTALLPERUSER=\"1\""); + ExitOnFailure(hr, "Failed to add per-user scope properties."); + } + } + hr = StrAllocConcatSecure(psczProperties, L" REBOOT=ReallySuppress", 0); ExitOnFailure(hr, "Failed to add reboot suppression property."); diff --git a/src/burn/engine/msiengine.h b/src/burn/engine/msiengine.h index 862c4f6a..d4660dc8 100644 --- a/src/burn/engine/msiengine.h +++ b/src/burn/engine/msiengine.h @@ -93,6 +93,8 @@ HRESULT MsiEngineConcatBurnProperties( __in BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning, __in BOOL fMsiPackage, __in BOOL fFeatureSelectionEnabled, + __in BOOTSTRAPPER_PACKAGE_SCOPE scope, + __in BOOL fPlannedPerMachineScope, __deref_out_z LPWSTR* psczProperties ); HRESULT MsiEngineConcatPackageProperties( diff --git a/src/burn/engine/mspengine.cpp b/src/burn/engine/mspengine.cpp index e8ef7fcb..18be3cc6 100644 --- a/src/burn/engine/mspengine.cpp +++ b/src/burn/engine/mspengine.cpp @@ -676,10 +676,10 @@ extern "C" HRESULT MspEngineExecutePackage( } // Always add Burn properties last. - hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, &sczProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, pExecuteAction->mspTarget.pPackage->scope, pExecuteAction->mspTarget.pPackage->fPerMachine, &sczProperties); ExitOnFailure(hr, "Failed to add action property to argument string."); - hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, &sczObfuscatedProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, pExecuteAction->mspTarget.pPackage->scope, pExecuteAction->mspTarget.pPackage->fPerMachine, &sczObfuscatedProperties); ExitOnFailure(hr, "Failed to add action property to obfuscated argument string."); LogId(REPORT_STANDARD, MSG_APPLYING_PATCH_PACKAGE, pExecuteAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pExecuteAction->mspTarget.action), sczPatches, sczObfuscatedProperties, pExecuteAction->mspTarget.sczTargetProductCode); diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp index 3bf676ba..61b73dc6 100644 --- a/src/burn/engine/package.cpp +++ b/src/burn/engine/package.cpp @@ -154,9 +154,12 @@ extern "C" HRESULT PackagesParseFromXml( hr = XmlGetAttributeUInt64(pixnNode, L"InstallSize", &pPackage->qwInstallSize); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallSize."); - // @PerMachine - hr = XmlGetYesNoAttribute(pixnNode, L"PerMachine", &pPackage->fPerMachine); - ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PerMachine."); + // @Scope + hr = PackageParseScopeFromXml(pixnNode, &pPackage->scope); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Scope."); + + // Shortcut for static per-machine or per-user packages. + pPackage->fPerMachine = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pPackage->scope; // @Permanent hr = XmlGetYesNoAttribute(pixnNode, L"Permanent", &pPackage->fPermanent); @@ -593,6 +596,45 @@ LExit: return hr; } +extern "C" HRESULT PackageParseScopeFromXml( + __in IXMLDOMNode* pixn, + __in BOOTSTRAPPER_PACKAGE_SCOPE* pScope +) +{ + HRESULT hr = S_OK; + LPWSTR scz = NULL; + + hr = XmlGetAttributeEx(pixn, L"Scope", &scz); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Scope."); + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perMachine", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perUser", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perUserOrMachine", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perMachineOrUser", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER; + } + else + { + hr = E_UNEXPECTED; + ExitOnRootFailure(hr, "Invalid scope: %ls", scz); + } + +LExit: + ReleaseStr(scz); + + return hr; +} + // internal function declarations diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index d596d7c0..5397e9cc 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -268,7 +268,8 @@ typedef struct _BURN_PACKAGE LPWSTR sczInstallCondition; LPWSTR sczRepairCondition; - BOOL fPerMachine; + BOOTSTRAPPER_PACKAGE_SCOPE scope; + BOOL fPerMachine; // only valid after Plan (for PUOM/PMOU packages). BOOL fPermanent; BOOL fVital; BOOL fCanAffectRegistration; @@ -483,6 +484,10 @@ HRESULT PackageFindRollbackBoundaryById( __in_z LPCWSTR wzId, __out BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary ); +HRESULT PackageParseScopeFromXml( + __in IXMLDOMNode* pixn, + __in BOOTSTRAPPER_PACKAGE_SCOPE* pScope + ); #if defined(__cplusplus) diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index edc09033..6c46269b 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -278,7 +278,7 @@ extern "C" void PlanReset( } } - PlanSetVariables(BOOTSTRAPPER_ACTION_UNKNOWN, pVariables); + PlanSetVariables(BOOTSTRAPPER_ACTION_UNKNOWN, BOOTSTRAPPER_PACKAGE_SCOPE_INVALID, BOOTSTRAPPER_SCOPE_DEFAULT, pVariables); } extern "C" void PlanUninitializeExecuteAction( @@ -332,6 +332,8 @@ extern "C" void PlanUninitializeExecuteAction( extern "C" HRESULT PlanSetVariables( __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE plannedScope, __in BURN_VARIABLES* pVariables ) { @@ -340,6 +342,12 @@ extern "C" HRESULT PlanSetVariables( hr = VariableSetNumeric(pVariables, BURN_BUNDLE_ACTION, action, TRUE); ExitOnFailure(hr, "Failed to set the bundle action built-in variable."); + hr = VariableSetNumeric(pVariables, BURN_BUNDLE_SCOPE, authoredScope, TRUE); + ExitOnFailure(hr, "Failed to set the bundle authored scope built-in variable."); + + hr = VariableSetNumeric(pVariables, BURN_BUNDLE_PLANNED_SCOPE, plannedScope, TRUE); + ExitOnFailure(hr, "Failed to set the bundle planned scope built-in variable."); + LExit: return hr; } @@ -812,6 +820,66 @@ LExit: return hr; } +extern "C" HRESULT PlanPackagesAndBundleScope( + __in BURN_PACKAGE* rgPackages, + __in DWORD cPackages, + __in BOOTSTRAPPER_SCOPE scope, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE commandLineScope, + __out BOOTSTRAPPER_SCOPE* pResultingScope, + __out BOOL* pfRegistrationPerMachine +) +{ + HRESULT hr = S_OK; + BOOL fRegistrationPerMachine = TRUE; + + // If a scope was specified on the command line and the BA didn't set a scope, + // let the command-line switch override. + if (BOOTSTRAPPER_SCOPE_DEFAULT != commandLineScope) + { + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == authoredScope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == authoredScope) + { + if (BOOTSTRAPPER_SCOPE_DEFAULT == scope) + { + scope = commandLineScope; + } + else + { + LogId(REPORT_STANDARD, MSG_SCOPE_IGNORED_BA_SCOPE); + } + } + else + { + LogId(REPORT_STANDARD, MSG_SCOPE_IGNORED_UNCONFIGURABLE); + } + } + + for (DWORD i = 0; i < cPackages; ++i) + { + BURN_PACKAGE* pPackage = rgPackages + i; + + pPackage->fPerMachine = + (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pPackage->scope) + || (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope && + (BOOTSTRAPPER_SCOPE_DEFAULT == scope || BOOTSTRAPPER_SCOPE_PER_MACHINE == scope)) + || (BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope && + BOOTSTRAPPER_SCOPE_PER_MACHINE == scope); + + // Any per-user package makes the registration per-user as well. + if (!pPackage->fPerMachine) + { + fRegistrationPerMachine = FALSE; + } + } + + *pResultingScope = scope; + *pfRegistrationPerMachine = fRegistrationPerMachine; + +//LExit: + return hr; +} + + static HRESULT PlanPackagesHelper( __in BURN_PACKAGE* rgPackages, __in DWORD cPackages, @@ -2971,7 +3039,7 @@ static void ExecuteActionLog( break; case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: - LogStringLine(PlanDumpLevel, "%ls action[%u]: MSI_PACKAGE package id: %ls, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, LoggingBoolToString(pAction->msiPackage.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->msiPackage.fileVersioning), pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes); + LogStringLine(PlanDumpLevel, "%ls action[%u]: MSI_PACKAGE package id: %ls, scope: %hs, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingPackageScopeToString(pAction->msiPackage.pPackage->scope), LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, LoggingBoolToString(pAction->msiPackage.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->msiPackage.fileVersioning), pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes); for (DWORD j = 0; j < pAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++j) { const BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pAction->msiPackage.pPackage->Msi.rgSlipstreamMsps + j; @@ -3083,6 +3151,7 @@ extern "C" void PlanDump( LogStringLine(PlanDumpLevel, " bundle code: %ls", pPlan->wzBundleCode); LogStringLine(PlanDumpLevel, " bundle provider key: %ls", pPlan->wzBundleProviderKey); LogStringLine(PlanDumpLevel, " use-forward-compatible: %hs", LoggingTrueFalseToString(pPlan->fEnabledForwardCompatibleBundle)); + LogStringLine(PlanDumpLevel, " planned scope: %hs", LoggingBundleScopeToString(pPlan->plannedScope)); LogStringLine(PlanDumpLevel, " per-machine: %hs", LoggingTrueFalseToString(pPlan->fPerMachine)); LogStringLine(PlanDumpLevel, " can affect machine state: %hs", LoggingTrueFalseToString(pPlan->fCanAffectMachineState)); LogStringLine(PlanDumpLevel, " disable-rollback: %hs", LoggingTrueFalseToString(pPlan->fDisableRollback)); diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 03b1423d..a20d7c76 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -249,6 +249,7 @@ typedef struct _BURN_CLEAN_ACTION typedef struct _BURN_PLAN { BOOTSTRAPPER_ACTION action; + BOOTSTRAPPER_SCOPE plannedScope; BURN_CACHE* pCache; BOOTSTRAPPER_COMMAND* pCommand; BURN_ENGINE_COMMAND* pInternalCommand; @@ -328,6 +329,8 @@ void PlanUninitializeExecuteAction( ); HRESULT PlanSetVariables( __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE plannedScope, __in BURN_VARIABLES* pVariables ); HRESULT PlanDefaultRelatedBundlePlanType( @@ -479,6 +482,15 @@ HRESULT PlanSetResumeCommand( void PlanDump( __in BURN_PLAN* pPlan ); +HRESULT PlanPackagesAndBundleScope( + __in BURN_PACKAGE* rgPackages, + __in DWORD cPackages, + __in BOOTSTRAPPER_SCOPE scope, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE commandLineScope, + __out BOOTSTRAPPER_SCOPE* pResultingScope, + __out BOOL* pfPerMachine +); #if defined(__cplusplus) } diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp index 9733e92c..fa1b024a 100644 --- a/src/burn/engine/registration.cpp +++ b/src/burn/engine/registration.cpp @@ -39,10 +39,6 @@ static HRESULT ParseSoftwareTagsFromXml( __out BURN_SOFTWARE_TAG** prgSoftwareTags, __out DWORD* pcSoftwareTags ); -static HRESULT SetPaths( - __in BURN_REGISTRATION* pRegistration, - __in BURN_CACHE* pCache - ); static HRESULT GetBundleManufacturer( __in BURN_REGISTRATION* pRegistration, __in BURN_VARIABLES* pVariables, @@ -108,6 +104,15 @@ static HRESULT UpdateEstimatedSize( ); static BOOL IsWuRebootPending(); static BOOL IsRegistryRebootPending(); +static HRESULT RegistrationDetectResumeTypeByHive( + __in HKEY hkRegistrationRoot, + __in BURN_REGISTRATION* pRegistration, + __out BOOTSTRAPPER_RESUME_TYPE* pResumeType +); +static HRESULT DetectInstalled( + __in BURN_REGISTRATION* pRegistration, + __in HKEY hkRoot +); // function definitions @@ -163,9 +168,9 @@ extern "C" HRESULT RegistrationParseFromXml( hr = XmlGetAttributeEx(pixnRegistrationNode, L"ExecutableName", &pRegistration->sczExecutableName); ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ExecutableName."); - // @PerMachine - hr = XmlGetYesNoAttribute(pixnRegistrationNode, L"PerMachine", &pRegistration->fPerMachine); - ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PerMachine."); + // @Scope + hr = PackageParseScopeFromXml(pixnRegistrationNode, &pRegistration->scope); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Scope."); // select ARP node hr = XmlSelectSingleNode(pixnRegistrationNode, L"Arp", &pixnArpNode); @@ -285,8 +290,18 @@ extern "C" HRESULT RegistrationParseFromXml( ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Classification."); } - hr = SetPaths(pRegistration, pCache); - ExitOnFailure(hr, "Failed to set registration paths."); + // Handle the easy case of build-time bundle scope early. + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pRegistration->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER == pRegistration->scope) + { + pRegistration->fPerMachine = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pRegistration->scope; + + hr = RegistrationSetPaths(pRegistration, pCache); + ExitOnFailure(hr, "Failed to set registration paths for fixed scope."); + } + else + { + pRegistration->hkRoot = reinterpret_cast(0ull); + } LExit: ReleaseObject(pixnRegistrationNode); @@ -452,31 +467,28 @@ LExit: extern "C" HRESULT RegistrationDetectInstalled( __in BURN_REGISTRATION* pRegistration - ) +) { HRESULT hr = S_OK; - HKEY hkRegistration = NULL; - DWORD dwInstalled = 0; - pRegistration->fCached = FileExistsEx(pRegistration->sczCacheExecutablePath, NULL); - pRegistration->detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_NONE; - - // open registration key - hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); - if (SUCCEEDED(hr)) + if (pRegistration->hkRoot) { - hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); - - pRegistration->detectedRegistrationType = (1 == dwInstalled) ? BOOTSTRAPPER_REGISTRATION_TYPE_FULL : BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS; + hr = DetectInstalled(pRegistration, pRegistration->hkRoot); } - - // Not finding the key or value is okay. - if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + else { - hr = S_OK; + // For PUOM/PMOU bundles, check per-machine then fall back to per-user. + hr = DetectInstalled(pRegistration, HKEY_LOCAL_MACHINE); + ExitOnFailure(hr, "Failed to detect HKEY_LOCAL_MACHINE bundle registration install state."); + + if (BOOTSTRAPPER_REGISTRATION_TYPE_NONE == pRegistration->detectedRegistrationType) + { + hr = DetectInstalled(pRegistration, HKEY_CURRENT_USER); + ExitOnFailure(hr, "Failed to detect HKEY_CURRENT_USER bundle registration install state."); + } } - ReleaseRegKey(hkRegistration); +LExit: return hr; } @@ -488,63 +500,26 @@ extern "C" HRESULT RegistrationDetectInstalled( extern "C" HRESULT RegistrationDetectResumeType( __in BURN_REGISTRATION* pRegistration, __out BOOTSTRAPPER_RESUME_TYPE* pResumeType - ) +) { HRESULT hr = S_OK; - HKEY hkRegistration = NULL; - BOOL fExists = FALSE; - DWORD dwResume = 0; - // open registration key - hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); - ExitOnPathFailure(hr, fExists, "Failed to open registration key."); - - if (!fExists) + if (pRegistration->hkRoot) { - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE; - ExitFunction(); + hr = RegistrationDetectResumeTypeByHive(pRegistration->hkRoot, pRegistration, pResumeType); } - - // read Resume value - hr = RegReadNumber(hkRegistration, L"Resume", &dwResume); - ExitOnPathFailure(hr, fExists, "Failed to read Resume value."); - - if (!fExists) - { - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; - ExitFunction(); - } - - switch (dwResume) + else { - case BURN_RESUME_MODE_ACTIVE: - // a previous run was interrupted - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED; - break; - - case BURN_RESUME_MODE_SUSPEND: - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_SUSPEND; - break; - - case BURN_RESUME_MODE_ARP: - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_ARP; - break; - - case BURN_RESUME_MODE_REBOOT_PENDING: - // The volatile pending registry doesn't exist (checked above) which means - // the system was successfully restarted. - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT; - break; + hr = RegistrationDetectResumeTypeByHive(HKEY_LOCAL_MACHINE, pRegistration, pResumeType); - default: - // the value stored in the registry is not valid - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; - break; + if (BOOTSTRAPPER_RESUME_TYPE_NONE == *pResumeType) + { + hr = RegistrationDetectResumeTypeByHive(HKEY_CURRENT_USER, pRegistration, pResumeType); + } } + ExitOnFailure(hr, "Failed to find bundle registration: %ls", pRegistration->sczRegistrationKey); LExit: - ReleaseRegKey(hkRegistration); - return hr; } @@ -889,7 +864,7 @@ extern "C" HRESULT RegistrationSessionEnd( // Open registration key. hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_WRITE, &hkRegistration); - ExitOnFailure(hr, "Failed to open registration key."); + ExitOnFailure(hr, "Failed to open registration key for ending session."); // update display name hr = UpdateBundleNameRegistration(pRegistration, pVariables, hkRegistration, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS == registrationType); @@ -1068,6 +1043,39 @@ extern "C" HRESULT RegistrationGetResumeCommandLine( return hr; } +extern "C" HRESULT RegistrationSetPaths( + __in BURN_REGISTRATION* pRegistration, + __in BURN_CACHE* pCache + ) +{ + HRESULT hr = S_OK; + LPWSTR sczCacheDirectory = NULL; + + // save registration key root + pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + + // build uninstall registry key path + hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczCode); + ExitOnFailure(hr, "Failed to build uninstall registry key path."); + + // build cache directory + hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCacheDirectory); + ExitOnFailure(hr, "Failed to build cache directory."); + + // build cached executable path + hr = PathConcatRelativeToFullyQualifiedBase(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath); + ExitOnFailure(hr, "Failed to build cached executable path."); + + // build state file path + hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%ls\\state.rsm", sczCacheDirectory); + ExitOnFailure(hr, "Failed to build state file path."); + +LExit: + ReleaseStr(sczCacheDirectory); + + return hr; +} + // internal helper functions @@ -1141,38 +1149,6 @@ LExit: return hr; } -static HRESULT SetPaths( - __in BURN_REGISTRATION* pRegistration, - __in BURN_CACHE* pCache - ) -{ - HRESULT hr = S_OK; - LPWSTR sczCacheDirectory = NULL; - - // save registration key root - pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - - // build uninstall registry key path - hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczCode); - ExitOnFailure(hr, "Failed to build uninstall registry key path."); - - // build cache directory - hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCacheDirectory); - ExitOnFailure(hr, "Failed to build cache directory."); - - // build cached executable path - hr = PathConcatRelativeToFullyQualifiedBase(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath); - ExitOnFailure(hr, "Failed to build cached executable path."); - - // build state file path - hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%ls\\state.rsm", sczCacheDirectory); - ExitOnFailure(hr, "Failed to build state file path."); - -LExit: - ReleaseStr(sczCacheDirectory); - return hr; -} - static HRESULT GetBundleManufacturer( __in BURN_REGISTRATION* pRegistration, __in BURN_VARIABLES* pVariables, @@ -1703,3 +1679,102 @@ static BOOL IsRegistryRebootPending() return fRebootPending; } + +static HRESULT RegistrationDetectResumeTypeByHive( + __in HKEY hkRegistrationRoot, + __in BURN_REGISTRATION* pRegistration, + __out BOOTSTRAPPER_RESUME_TYPE* pResumeType +) +{ + HRESULT hr = S_OK; + HKEY hkRegistration = NULL; + BOOL fExists = FALSE; + DWORD dwResume = 0; + + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE; + + // open registration key + hr = RegOpen(hkRegistrationRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); + ExitOnPathFailure(hr, fExists, "Failed to open registration key."); + + if (!fExists) + { + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE; + ExitFunction(); + } + + // read Resume value + hr = RegReadNumber(hkRegistration, L"Resume", &dwResume); + ExitOnPathFailure(hr, fExists, "Failed to read Resume value."); + + if (!fExists) + { + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; + ExitFunction(); + } + + switch (dwResume) + { + case BURN_RESUME_MODE_ACTIVE: + // a previous run was interrupted + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED; + break; + + case BURN_RESUME_MODE_SUSPEND: + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_SUSPEND; + break; + + case BURN_RESUME_MODE_ARP: + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_ARP; + break; + + case BURN_RESUME_MODE_REBOOT_PENDING: + // The volatile pending registry doesn't exist (checked above) which means + // the system was successfully restarted. + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT; + break; + + default: + // the value stored in the registry is not valid + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; + break; + } + +LExit: + ReleaseRegKey(hkRegistration); + + return hr; +} + +static HRESULT DetectInstalled( + __in BURN_REGISTRATION* pRegistration, + __in HKEY hkRoot +) +{ + HRESULT hr = S_OK; + HKEY hkRegistration = NULL; + DWORD dwInstalled = 0; + + pRegistration->fCached = pRegistration->sczCacheExecutablePath && FileExistsEx(pRegistration->sczCacheExecutablePath, NULL); + pRegistration->detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_NONE; + + // open registration key + hr = RegOpen(hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); + if (SUCCEEDED(hr)) + { + hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); + + pRegistration->detectedRegistrationType = (1 == dwInstalled) ? BOOTSTRAPPER_REGISTRATION_TYPE_FULL : BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS; + } + + // Not finding the key or value is okay. + if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + { + hr = S_OK; + } + + ReleaseRegKey(hkRegistration); + + return hr; +} + diff --git a/src/burn/engine/registration.h b/src/burn/engine/registration.h index 326f21c6..e83b75b6 100644 --- a/src/burn/engine/registration.h +++ b/src/burn/engine/registration.h @@ -94,11 +94,12 @@ typedef struct _BURN_SOFTWARE_TAGS typedef struct _BURN_REGISTRATION { - BOOL fPerMachine; + BOOL fPerMachine; // For PUOM/PMOU bundles, only valid after planning. BOOL fForceSystemComponent; BOOL fDisableResume; BOOL fCached; BOOTSTRAPPER_REGISTRATION_TYPE detectedRegistrationType; + BOOTSTRAPPER_PACKAGE_SCOPE scope; LPWSTR sczCode; LPWSTR sczTag; @@ -167,7 +168,7 @@ HRESULT RegistrationParseFromXml( __in BURN_REGISTRATION* pRegistration, __in BURN_CACHE* pCache, __in IXMLDOMNode* pixnBundle - ); +); void RegistrationUninitialize( __in BURN_REGISTRATION* pRegistration ); @@ -191,7 +192,7 @@ HRESULT RegistrationDetectRelatedBundles( ); HRESULT RegistrationPlanInitialize( __in BURN_REGISTRATION* pRegistration - ); +); HRESULT RegistrationSessionBegin( __in_z LPCWSTR wzEngineWorkingPath, __in BURN_REGISTRATION* pRegistration, @@ -225,6 +226,10 @@ HRESULT RegistrationGetResumeCommandLine( __in const BURN_REGISTRATION* pRegistration, __deref_out_z LPWSTR* psczResumeCommandLine ); +HRESULT RegistrationSetPaths( + __in BURN_REGISTRATION* pRegistration, + __in BURN_CACHE* pCache + ); #if defined(__cplusplus) diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp index c9aa7170..d0b97af0 100644 --- a/src/burn/engine/relatedbundle.cpp +++ b/src/burn/engine/relatedbundle.cpp @@ -22,7 +22,7 @@ static __callback int __cdecl CompareRelatedBundlesPlan( ); static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, - __in_opt LPVOID pvContext + __in LPVOID pvContext ); static HRESULT LoadIfRelatedBundle( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, @@ -258,7 +258,7 @@ static __callback int __cdecl CompareRelatedBundlesPlan( static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, - __in_opt LPVOID pvContext + __in LPVOID pvContext ) { HRESULT hr = S_OK; diff --git a/src/burn/engine/uithread.cpp b/src/burn/engine/uithread.cpp index 9beb9f80..1f7db965 100644 --- a/src/burn/engine/uithread.cpp +++ b/src/burn/engine/uithread.cpp @@ -123,7 +123,7 @@ static DWORD WINAPI ThreadProc( info.pEngineState = pEngineState; // Create the window to handle reboots without activating it. - hWnd = ::CreateWindowExW(WS_EX_NOACTIVATE, wc.lpszClassName, NULL, WS_POPUP, 0, 0, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, &info); + hWnd = ::CreateWindowExW(WS_EX_NOACTIVATE, wc.lpszClassName, BURN_UITHREAD_CLASS_WINDOW, WS_POPUP, 0, 0, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, &info); ExitOnNullWithLastError(hWnd, hr, "Failed to create Burn UI thread window."); ::ShowWindow(hWnd, SW_SHOWNA); diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp index a795d76c..1b7dc4d1 100644 --- a/src/burn/engine/variable.cpp +++ b/src/burn/engine/variable.cpp @@ -305,6 +305,8 @@ extern "C" HRESULT VariableInitialize( {BURN_BUNDLE_TAG, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE}, {BURN_BUNDLE_UILEVEL, InitializeVariableNumeric, 0, FALSE, TRUE}, {BURN_BUNDLE_VERSION, InitializeVariableVersion, (DWORD_PTR)L"0", FALSE, TRUE}, + {BURN_BUNDLE_SCOPE, InitializeVariableNumeric, 0, FALSE, TRUE}, + {BURN_BUNDLE_PLANNED_SCOPE, InitializeVariableNumeric, 0, FALSE, TRUE}, }; const WELL_KNOWN_VARIABLE_DECLARATION vrgWellKnownVariableNames[] = diff --git a/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp b/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp index da51f1f8..6798d3cb 100644 --- a/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp +++ b/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp @@ -2,11 +2,7 @@ #include "precomp.h" -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -308,5 +304,3 @@ namespace Bootstrapper } } } -} -} diff --git a/src/burn/test/BurnUnitTest/BurnTestException.h b/src/burn/test/BurnUnitTest/BurnTestException.h index b9467926..b6055041 100644 --- a/src/burn/test/BurnUnitTest/BurnTestException.h +++ b/src/burn/test/BurnUnitTest/BurnTestException.h @@ -2,11 +2,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -35,8 +31,6 @@ namespace Bootstrapper } } } -} -} // this class is used by __TestThrowOnFailure_Format() below to deallocate // the string created after the function call has returned @@ -83,6 +77,6 @@ LExit: } #pragma warning (pop) -#define TestThrowOnFailure(hr, s) if (FAILED(hr)) { throw gcnew Microsoft::Tools::WindowsInstallerXml::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(s)); } -#define TestThrowOnFailure1(hr, s, p) if (FAILED(hr)) { throw gcnew Microsoft::Tools::WindowsInstallerXml::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(__TestThrowOnFailure_Format(s, p))); } -#define TestThrowOnFailure2(hr, s, p1, p2) if (FAILED(hr)) { throw gcnew Microsoft::Tools::WindowsInstallerXml::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(__TestThrowOnFailure_Format(s, p1, p2))); } +#define TestThrowOnFailure(hr, s) if (FAILED(hr)) { throw gcnew WixToolset::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(s)); } +#define TestThrowOnFailure1(hr, s, p) if (FAILED(hr)) { throw gcnew WixToolset::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(__TestThrowOnFailure_Format(s, p))); } +#define TestThrowOnFailure2(hr, s, p1, p2) if (FAILED(hr)) { throw gcnew WixToolset::Test::Bootstrapper::BurnTestException(hr, gcnew System::String(__TestThrowOnFailure_Format(s, p1, p2))); } diff --git a/src/burn/test/BurnUnitTest/BurnTestFixture.h b/src/burn/test/BurnUnitTest/BurnTestFixture.h index 35acba67..95fd6fe5 100644 --- a/src/burn/test/BurnUnitTest/BurnTestFixture.h +++ b/src/burn/test/BurnUnitTest/BurnTestFixture.h @@ -2,11 +2,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -71,5 +67,3 @@ namespace Bootstrapper } } } -} -} diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.h b/src/burn/test/BurnUnitTest/BurnUnitTest.h index ed1d2956..33cfe46d 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.h +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.h @@ -2,11 +2,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -44,5 +40,3 @@ namespace Bootstrapper } } } -} -} diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj index 9704efa5..c741789e 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj @@ -22,7 +22,6 @@ x64 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67} @@ -34,15 +33,12 @@ false true - - $(ProjectAdditionalIncludeDirectories);$(BurnGeneratedHeaderDirectory);..\..\engine;..\..\..\api\burn\inc;..\..\..\libs\dutil\WixToolset.Dutil\inc cabinet.lib;crypt32.lib;msi.lib;rpcrt4.lib;shlwapi.lib;userenv.lib;wininet.lib;wintrust.lib;$(RootBuildFolder)libs\$(Configuration)\$(WixNativeSdkLibraryToolset)\$(PlatformTarget)\dutil.lib;engine.res - @@ -76,11 +72,9 @@ - - @@ -91,14 +85,23 @@ + + + + + + + + + + + - {8119537D-E1D9-6591-D51A-49770A2F9C37} - diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters index aac5ab8b..0c458f48 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters @@ -98,4 +98,20 @@ Resource Files - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/burn/test/BurnUnitTest/CacheTest.cpp b/src/burn/test/BurnUnitTest/CacheTest.cpp index 8e3660b2..c142e673 100644 --- a/src/burn/test/BurnUnitTest/CacheTest.cpp +++ b/src/burn/test/BurnUnitTest/CacheTest.cpp @@ -23,11 +23,7 @@ typedef struct _CACHE_TEST_CONTEXT { } CACHE_TEST_CONTEXT; -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -158,7 +154,7 @@ namespace Bootstrapper hr = StrAllocHexDecode(L"25e61cd83485062b70713aebddd3fe4992826cb121466fddc8de3eacb1e42f39d4bdd8455d95eec8c9529ced4c0296ab861931fe2c86df2f2b4e8d259a6d9223", &pb, &cb); Assert::Equal(S_OK, hr); - package.fPerMachine = FALSE; + package.scope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER; package.sczCacheId = L"Bootstrapper.CacheTest.CacheSignatureTest"; payload.sczKey = L"CacheSignatureTest.PayloadKey"; payload.sczFilePath = L"CacheSignatureTest.File"; @@ -192,8 +188,6 @@ namespace Bootstrapper } } } -} -} static HRESULT CALLBACK CacheTestEventRoutine( __in BURN_CACHE_MESSAGE* /*pMessage*/, diff --git a/src/burn/test/BurnUnitTest/ElevationTest.cpp b/src/burn/test/BurnUnitTest/ElevationTest.cpp index 81e9f93e..feacdb7c 100644 --- a/src/burn/test/BurnUnitTest/ElevationTest.cpp +++ b/src/burn/test/BurnUnitTest/ElevationTest.cpp @@ -25,11 +25,7 @@ static HRESULT ProcessChildMessages( __out DWORD* pdwResult ); -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -92,8 +88,6 @@ namespace Bootstrapper } } } -} -} static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW( diff --git a/src/burn/test/BurnUnitTest/EmbeddedTest.cpp b/src/burn/test/BurnUnitTest/EmbeddedTest.cpp index a19790ad..33f03282 100644 --- a/src/burn/test/BurnUnitTest/EmbeddedTest.cpp +++ b/src/burn/test/BurnUnitTest/EmbeddedTest.cpp @@ -33,11 +33,7 @@ static int EmbeddedTest_GenericMessageHandler( __in LPVOID pvContext ); -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -84,8 +80,6 @@ namespace Bootstrapper } } } -} -} static BOOL STDAPICALLTYPE EmbeddedTest_CreateProcessW( diff --git a/src/burn/test/BurnUnitTest/ExitCodeTest.cpp b/src/burn/test/BurnUnitTest/ExitCodeTest.cpp index 9b66f4c0..0529fa45 100644 --- a/src/burn/test/BurnUnitTest/ExitCodeTest.cpp +++ b/src/burn/test/BurnUnitTest/ExitCodeTest.cpp @@ -2,11 +2,7 @@ #include "precomp.h" -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -328,7 +324,7 @@ static void LoadEngineState( L"" L" " L" " - L" " + L" " L" " L" " L" " @@ -349,7 +345,7 @@ static void LoadEngineState( L" " L" " L" " - L" " + L" " L" " L" " L" " @@ -376,5 +372,3 @@ static void LoadEngineState( } } } -} -} diff --git a/src/burn/test/BurnUnitTest/LoggingTest.cpp b/src/burn/test/BurnUnitTest/LoggingTest.cpp index ed74c875..7619b913 100644 --- a/src/burn/test/BurnUnitTest/LoggingTest.cpp +++ b/src/burn/test/BurnUnitTest/LoggingTest.cpp @@ -2,11 +2,7 @@ #include "precomp.h" -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -64,5 +60,3 @@ namespace Bootstrapper } } } -} -} diff --git a/src/burn/test/BurnUnitTest/ManifestHelpers.cpp b/src/burn/test/BurnUnitTest/ManifestHelpers.cpp index 96d5fab4..b68504aa 100644 --- a/src/burn/test/BurnUnitTest/ManifestHelpers.cpp +++ b/src/burn/test/BurnUnitTest/ManifestHelpers.cpp @@ -7,11 +7,7 @@ using namespace System; using namespace Xunit; -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -37,5 +33,3 @@ namespace Bootstrapper } } } -} -} diff --git a/src/burn/test/BurnUnitTest/ManifestHelpers.h b/src/burn/test/BurnUnitTest/ManifestHelpers.h index e3e57555..e3c97c64 100644 --- a/src/burn/test/BurnUnitTest/ManifestHelpers.h +++ b/src/burn/test/BurnUnitTest/ManifestHelpers.h @@ -2,11 +2,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -20,5 +16,3 @@ void LoadBundleXmlHelper(LPCWSTR wzDocument, IXMLDOMElement** ppixeBundle); } } } -} -} diff --git a/src/burn/test/BurnUnitTest/ManifestTest.cpp b/src/burn/test/BurnUnitTest/ManifestTest.cpp index 4959cee0..4e6bac24 100644 --- a/src/burn/test/BurnUnitTest/ManifestTest.cpp +++ b/src/burn/test/BurnUnitTest/ManifestTest.cpp @@ -2,11 +2,7 @@ #include "precomp.h" -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -40,7 +36,7 @@ namespace Bootstrapper " " " " " " - " " + " " " "; @@ -67,5 +63,3 @@ namespace Bootstrapper } } } -} -} diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index e2850a62..7e7d84cc 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -2,12 +2,20 @@ #include "precomp.h" +#if TODO_REIMPLEMENT static HRESULT WINAPI PlanTestBAProc( __in BOOTSTRAPPER_APPLICATION_MESSAGE message, __in const LPVOID pvArgs, __inout LPVOID pvResults, __in_opt LPVOID pvContext ); +#endif + +struct REDIRECTED_LOGGING_CONTEXT +{ + LPSTR pszBuffer; +}; + static LPCWSTR wzArpEntryExeManifestFileName = L"ExePackage_PerUserArpEntry_manifest.xml"; static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; @@ -28,11 +36,7 @@ static BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE vRelatedBundlePlanType = BOOTSTRAPP static BURN_DEPENDENCY_ACTION registerActions1[] = { BURN_DEPENDENCY_ACTION_REGISTER }; static BURN_DEPENDENCY_ACTION unregisterActions1[] = { BURN_DEPENDENCY_ACTION_UNREGISTER }; -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -43,11 +47,313 @@ namespace Bootstrapper public ref class PlanTest : BurnUnitTest { + private: + void ScopeTest( + LPCWSTR wzManifestFileName, + BOOL fDefaultPlanPerMachine, + BOOL fDefaultRegistrationPerMachine, + BOOL fPerUserPlanPerMachine, + BOOL fPerUserRegistrationPerMachine, + BOOL fPerMachinePlanPerMachine, + BOOL fPerMachineRegistrationPerMachine + ) + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzManifestFileName, pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPermanentPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); + NativeAssert::Succeeded(hr, "CorePlan default failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_DEFAULT, pPlan->plannedScope); + Assert::Equal(fDefaultPlanPerMachine, pPlan->fPerMachine); + Assert::Equal(fDefaultRegistrationPerMachine, engineState.registration.fPerMachine); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_PER_USER); + NativeAssert::Succeeded(hr, "CorePlan per-user failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_USER, pPlan->plannedScope); + Assert::Equal(fPerUserPlanPerMachine, pPlan->fPerMachine); + Assert::Equal(fPerUserRegistrationPerMachine, engineState.registration.fPerMachine); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_PER_MACHINE); + NativeAssert::Succeeded(hr, "CorePlan per-machine failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_MACHINE, pPlan->plannedScope); + Assert::Equal(fPerMachinePlanPerMachine, pPlan->fPerMachine); + Assert::Equal(fPerMachineRegistrationPerMachine, engineState.registration.fPerMachine); + } + public: PlanTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture) { } + [Fact] + void CommandLineScopeTestNoop() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + engineState.command.commandLineScope = BOOTSTRAPPER_SCOPE_PER_MACHINE; + + InitializeEngineStateForCorePlan(L"AllPmouBundle_manifest.xml", pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPermanentPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_PER_USER); + NativeAssert::Succeeded(hr, "CorePlan default failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_USER, pPlan->plannedScope); + Assert::Equal(FALSE, pPlan->fPerMachine); + Assert::Equal(FALSE, engineState.registration.fPerMachine); + } + + [Fact] + void CommandLineScopePerUserTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + engineState.command.commandLineScope = BOOTSTRAPPER_SCOPE_PER_USER; + + InitializeEngineStateForCorePlan(L"AllPmouBundle_manifest.xml", pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPermanentPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); + NativeAssert::Succeeded(hr, "CorePlan default failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_USER, pPlan->plannedScope); + Assert::Equal(FALSE, pPlan->fPerMachine); + Assert::Equal(FALSE, engineState.registration.fPerMachine); + } + + [Fact] + void CommandLineScopePerMachineTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + engineState.command.commandLineScope = BOOTSTRAPPER_SCOPE_PER_MACHINE; + + InitializeEngineStateForCorePlan(L"AllPmouBundle_manifest.xml", pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPermanentPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); + NativeAssert::Succeeded(hr, "CorePlan default failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_MACHINE, pPlan->plannedScope); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(TRUE, engineState.registration.fPerMachine); + } + + [Fact] + void BundlePackageScopeTestNoop() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + engineState.command.commandLineScope = BOOTSTRAPPER_SCOPE_PER_MACHINE; + + InitializeEngineStateForCorePlan(L"PuomBundlePackage_manifest.xml", pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPermanentPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_PER_USER); + NativeAssert::Succeeded(hr, "CorePlan default failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_USER, pPlan->plannedScope); + Assert::Equal(BOOTSTRAPPER_SCOPE_DEFAULT, engineState.packages.rgPackages[0].fPerMachine); + Assert::Equal(FALSE, pPlan->fPerMachine); + Assert::Equal(FALSE, engineState.registration.fPerMachine); + } + + [Fact] + void BundlePackageScopeTestSucceeds() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + engineState.command.commandLineScope = BOOTSTRAPPER_SCOPE_PER_MACHINE; + + InitializeEngineStateForCorePlan(L"PuomBundlePackage_manifest.xml", pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPermanentPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); + NativeAssert::Succeeded(hr, "CorePlan default failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_MACHINE, pPlan->plannedScope); + Assert::Equal(BOOTSTRAPPER_SCOPE_PER_MACHINE, engineState.packages.rgPackages[0].fPerMachine); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(TRUE, engineState.registration.fPerMachine); + } + + [Fact] + void AllPerUserScopeTest() + { + ScopeTest( + L"PerUserBundle_manifest.xml", + FALSE /*fDefaultPlanPerMachine*/, + FALSE /*fDefaultRegistrationPerMachine*/, + FALSE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + FALSE /*fPerMachinePlanPerMachine*/, + FALSE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void AllPerMachineScopeTest() + { + ScopeTest( + L"PerMachineBundle_manifest.xml", + TRUE /*fDefaultPlanPerMachine*/, + TRUE /*fDefaultRegistrationPerMachine*/, + TRUE /*fPerUserPlanPerMachine*/, + TRUE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + TRUE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void AllPerMachineOrUserPackagesScopeTest() + { + ScopeTest( + L"AllPmouBundle_manifest.xml", + TRUE /*fDefaultPlanPerMachine*/, + TRUE /*fDefaultRegistrationPerMachine*/, + FALSE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + TRUE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void AllPerUserOrMachinePackagesScopeTest() + { + ScopeTest( + L"AllPuomBundle_manifest.xml", + FALSE /*fDefaultPlanPerMachine*/, + FALSE /*fDefaultRegistrationPerMachine*/, + FALSE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + TRUE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void PerMachineAndPerMachineOrUserScopeTest() + { + ScopeTest( + L"PmPmouBundle_manifest.xml", + TRUE /*fDefaultPlanPerMachine*/, + TRUE /*fDefaultRegistrationPerMachine*/, + TRUE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + TRUE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void PerMachineAndPerUserOrMachineScopeTest() + { + ScopeTest( + L"PmPuomBundle_manifest.xml", + TRUE /*fDefaultPlanPerMachine*/, + FALSE /*fDefaultRegistrationPerMachine*/, + TRUE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + TRUE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void PerMachineAndPerUserAndPerMachineOrUserScopeTest() + { + ScopeTest( + L"PmPuPmouBundle_manifest.xml", + TRUE /*fDefaultPlanPerMachine*/, + FALSE /*fDefaultRegistrationPerMachine*/, + TRUE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + FALSE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void PerMachineAndPerUserAndPerUserOrMachineScopeTest() + { + ScopeTest( + L"PmPuPuomBundle_manifest.xml", + TRUE /*fDefaultPlanPerMachine*/, + FALSE /*fDefaultRegistrationPerMachine*/, + TRUE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + FALSE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void PerUserAndPerMachineOrUserScopeTest() + { + ScopeTest( + L"PuPmouBundle_manifest.xml", + TRUE /*fDefaultPlanPerMachine*/, + FALSE /*fDefaultRegistrationPerMachine*/, + FALSE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + FALSE /*fPerMachineRegistrationPerMachine*/ + ); + } + + [Fact] + void PerUserAndPerUserOrMachineScopeTest() + { + ScopeTest( + L"PuPuomBundle_manifest.xml", + FALSE /*fDefaultPlanPerMachine*/, + FALSE /*fDefaultRegistrationPerMachine*/, + FALSE /*fPerUserPlanPerMachine*/, + FALSE /*fPerUserRegistrationPerMachine*/, + TRUE /*fPerMachinePlanPerMachine*/, + FALSE /*fPerMachineRegistrationPerMachine*/ + ); + } + [Fact] void ArpEntryExeInstallTest() { @@ -60,7 +366,7 @@ namespace Bootstrapper DetectAttachedContainerAsAttached(pEngineState); DetectPermanentPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -154,12 +460,13 @@ namespace Bootstrapper pEngineState->packages.rgPackages[1].currentState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleCode); NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleProviderKey); + Assert::Equal(FALSE, pPlan->fEnabledForwardCompatibleBundle); Assert::Equal(FALSE, pPlan->fPerMachine); Assert::Equal(TRUE, pPlan->fCanAffectMachineState); @@ -233,7 +540,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzArpEntryExeManifestFileName, pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -326,9 +633,11 @@ namespace Bootstrapper DetectPackagesAsAbsent(pEngineState); DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"1.0.0.0", BOOTSTRAPPER_RELATION_UPGRADE); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); + PlanDump(pPlan); + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); NativeAssert::StringEqual(L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", pPlan->wzBundleCode); NativeAssert::StringEqual(L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", pPlan->wzBundleProviderKey); @@ -486,7 +795,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzMsiTransactionManifestFileName, pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -627,7 +936,7 @@ namespace Bootstrapper DetectAttachedContainerAsAttached(pEngineState); DetectPermanentPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -742,7 +1051,7 @@ namespace Bootstrapper DetectAttachedContainerAsAttached(pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_REPAIR); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_REPAIR, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_REPAIR, pPlan->action); @@ -836,7 +1145,7 @@ namespace Bootstrapper DetectAttachedContainerAsAttached(pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -955,7 +1264,7 @@ namespace Bootstrapper DetectPackagesAsAbsent(pEngineState); DetectCompatibleMsiPackage(pEngineState, pEngineState->packages.rgPackages, L"{C24F3903-38E7-4D44-8037-D9856B3C5046}", L"2.0.0.0"); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -1055,7 +1364,7 @@ namespace Bootstrapper vfUseRelatedBundlePlanType = TRUE; vRelatedBundlePlanType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -1174,7 +1483,7 @@ namespace Bootstrapper BURN_RELATED_BUNDLE* pRelatedBundle = DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); pRelatedBundle->fPlannable = FALSE; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -1276,7 +1585,7 @@ namespace Bootstrapper DetectAttachedContainerAsAttached(pEngineState); DetectPermanentPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -1369,7 +1678,7 @@ namespace Bootstrapper DetectAttachedContainerAsAttached(pEngineState); DetectPermanentPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_LAYOUT); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_LAYOUT, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_LAYOUT, pPlan->action); @@ -1452,7 +1761,7 @@ namespace Bootstrapper DetectPackagesAsAbsent(pEngineState); DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_CACHE); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_CACHE, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_CACHE, pPlan->action); @@ -1541,7 +1850,7 @@ namespace Bootstrapper DetectPackagesAsAbsent(pEngineState); DetectRelatedBundle(pEngineState, L"{AF8355C9-CCDD-4D61-BF5F-EA5F948D8F01}", L"1.1.0.0", BOOTSTRAPPER_RELATION_UPGRADE); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -1616,7 +1925,7 @@ namespace Bootstrapper vfUseRelatedBundleRequestState = TRUE; vRelatedBundleRequestState = BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -1705,7 +2014,7 @@ namespace Bootstrapper vfUseRelatedBundleRequestState = TRUE; vRelatedBundleRequestState = BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -1798,7 +2107,7 @@ namespace Bootstrapper DetectPackagesAsAbsent(pEngineState); DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -1904,7 +2213,7 @@ namespace Bootstrapper pEngineState->registration.detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_FULL; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_MODIFY); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_MODIFY, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_MODIFY, pPlan->action); @@ -1983,7 +2292,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -2084,7 +2393,7 @@ namespace Bootstrapper DetectPackagesAsPresentAndCached(pEngineState); DetectBundleDependent(pEngineState, L"{29855EB1-724D-4285-A89C-5D37D8549DCD}"); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -2154,7 +2463,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectAsRelatedUpgradeBundle(&engineState, L"{02940F3E-C83E-452D-BFCF-C943777ACEAE}", L"2.0.0.0"); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -2240,7 +2549,7 @@ namespace Bootstrapper pEngineState->packages.rgPackages[0].currentState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED; pEngineState->packages.rgPackages[0].Msi.operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -2328,7 +2637,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL, pPlan->action); @@ -2430,7 +2739,7 @@ namespace Bootstrapper DetectAttachedContainerAsAttached(pEngineState); DetectPackagesAsAbsent(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); llPlannedAction = VariableGetNumericHelper(&engineState.variables, BURN_BUNDLE_ACTION); @@ -2523,7 +2832,7 @@ namespace Bootstrapper DetectPermanentPackagesAsPresentAndCached(pEngineState); PlanTestDetectPatchInitialize(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -2587,8 +2896,14 @@ namespace Bootstrapper ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", registerActions1, 1); + + pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_INSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, TRUE); + + ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1); @@ -2654,7 +2969,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSlipstreamManifestFileName, pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -2784,7 +3099,7 @@ namespace Bootstrapper vfUsePackageRequestState = TRUE; vPackageRequestState = BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT; - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); @@ -2885,7 +3200,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSlipstreamModifiedManifestFileName, pEngineState); DetectPackagesAsAbsent(pEngineState); - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); NativeAssert::Succeeded(hr, "CorePlan failed"); Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); @@ -3031,7 +3346,7 @@ namespace Bootstrapper Assert::True(FileExistsEx(sczFilePath, NULL), "Test file does not exist."); hr = ManifestLoadXmlFromFile(sczFilePath, pEngineState); - NativeAssert::Succeeded(hr, "Failed to load manifest."); + NativeAssert::Succeeded(hr, "Failed to load test manifest."); } finally { @@ -3222,7 +3537,7 @@ namespace Bootstrapper for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j) { BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[j].pMspPackage; - MspEngineAddDetectedTargetProduct(&pEngineState->packages, pMspPackage, j, pPackage->Msi.sczProductCode, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED); + MspEngineAddDetectedTargetProduct(&pEngineState->packages, pMspPackage, j, pPackage->Msi.sczProductCode, pPackage->scope == BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED); BURN_MSPTARGETPRODUCT* pTargetProduct = pMspPackage->Msp.rgTargetProducts + (pMspPackage->Msp.cTargetProductCodes - 1); pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; @@ -3759,8 +4074,8 @@ namespace Bootstrapper void ValidatePlannedProvider( __in BURN_PLAN* pPlan, __in UINT uIndex, - __in LPCWSTR wzKey, - __in LPCWSTR wzName + __in_z LPCWSTR wzKey, + __in_z_opt LPCWSTR wzName ) { Assert::InRange(uIndex + 1u, 1u, pPlan->cPlannedProviders); @@ -3811,8 +4126,6 @@ namespace Bootstrapper } } } -} -} #if TODO_REIMPLEMENT diff --git a/src/burn/test/BurnUnitTest/RegistrationTest.cpp b/src/burn/test/BurnUnitTest/RegistrationTest.cpp index 3068eb6a..1c43c442 100644 --- a/src/burn/test/BurnUnitTest/RegistrationTest.cpp +++ b/src/burn/test/BurnUnitTest/RegistrationTest.cpp @@ -9,11 +9,7 @@ #define TEST_BUNDLE_UPGRADE_CODE L"{89FDAE1F-8CC1-48B9-B930-3945E0D3E7F0}" -namespace Microsoft -{ -namespace Tools -{ -namespace WindowsInstallerXml +namespace WixToolset { namespace Test { @@ -73,7 +69,7 @@ namespace Bootstrapper L" " L" " L" " - L" " + L" " L" " L" " L""; @@ -93,6 +89,12 @@ namespace Bootstrapper hr = RegistrationParseFromXml(®istration, &cache, pixeBundle); TestThrowOnFailure(hr, L"Failed to parse registration from XML."); + hr = RegistrationSetPaths(®istration, &cache); + TestThrowOnFailure(hr, "Failed to set registration paths."); + + hr = RegistrationPlanInitialize(®istration); + TestThrowOnFailure(hr, "Failed to initialize registration for the plan."); + plan.action = BOOTSTRAPPER_ACTION_INSTALL; plan.pCommand = &command; plan.pInternalCommand = &internalCommand; @@ -173,7 +175,7 @@ namespace Bootstrapper L" " L" " L" " - L" " + L" " L" " L" " L""; @@ -193,6 +195,12 @@ namespace Bootstrapper hr = RegistrationParseFromXml(®istration, &cache, pixeBundle); TestThrowOnFailure(hr, L"Failed to parse registration from XML."); + hr = RegistrationSetPaths(®istration, &cache); + TestThrowOnFailure(hr, "Failed to set registration paths."); + + hr = RegistrationPlanInitialize(®istration); + TestThrowOnFailure(hr, "Failed to initialize registration for the plan."); + plan.action = BOOTSTRAPPER_ACTION_INSTALL; plan.pCommand = &command; plan.pInternalCommand = &internalCommand; @@ -294,7 +302,7 @@ namespace Bootstrapper L" " L" " L" " - L" " + L" " L" " L" " L""; @@ -314,6 +322,12 @@ namespace Bootstrapper hr = RegistrationParseFromXml(®istration, &cache, pixeBundle); TestThrowOnFailure(hr, L"Failed to parse registration from XML."); + hr = RegistrationSetPaths(®istration, &cache); + TestThrowOnFailure(hr, "Failed to set registration paths."); + + hr = RegistrationPlanInitialize(®istration); + TestThrowOnFailure(hr, "Failed to initialize registration for the plan."); + plan.action = BOOTSTRAPPER_ACTION_INSTALL; plan.pCommand = &command; plan.pInternalCommand = &internalCommand; @@ -415,7 +429,7 @@ namespace Bootstrapper L" " L" " L" " - L" " + L" " L" " @@ -437,6 +451,12 @@ namespace Bootstrapper hr = RegistrationParseFromXml(®istration, &cache, pixeBundle); TestThrowOnFailure(hr, L"Failed to parse registration from XML."); + hr = RegistrationSetPaths(®istration, &cache); + TestThrowOnFailure(hr, "Failed to set registration paths."); + + hr = RegistrationPlanInitialize(®istration); + TestThrowOnFailure(hr, "Failed to initialize registration for the plan."); + plan.action = BOOTSTRAPPER_ACTION_INSTALL; plan.pCommand = &command; plan.pInternalCommand = &internalCommand; @@ -554,7 +574,7 @@ namespace Bootstrapper L" " L" " L" " - L" " + L" " L" " L" " L"