diff --git a/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs b/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs
index 9df57cd3b..4b1c4b52a 100644
--- a/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs
+++ b/src/api/burn/WixToolset.BootstrapperApplicationApi/IBootstrapperEngine.cs
@@ -345,23 +345,24 @@ public enum LaunchAction
}
///
- /// The scope of the bundle when the chain contains per-user-or-machine or per-machone-or-user packages.
+ /// The scope of the bundle when the chain contains dual-purpose (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-user packages. Per-machine-or-user packages will be
/// planned as per-machine packages.
///
Default,
///
- /// Set per-machine scope for per-user-or-machine packages.
+ /// Set per-machine scope for dual-purpose packages.
///
PerMachine,
///
- /// Set per-user scope for per-user-or-machine packages.
+ /// Set per-user scope for dual-purpose packages.
///
PerUser,
}
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index dc0af8ce9..5483e46f9 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -469,7 +469,7 @@ 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->registration.detectedScope, &pEngineState->plan.plannedScope, &pEngineState->registration.fPerMachine);
+ hr = PlanPackagesAndBundleScope(pEngineState->packages.rgPackages, pEngineState->packages.cPackages, pEngineState->registration.sczPrimaryUpgradeCode, pEngineState->registration.relatedBundles.rgRelatedBundles, pEngineState->registration.relatedBundles.cRelatedBundles, pEngineState->plan.plannedScope, pEngineState->registration.scope, pEngineState->command.commandLineScope, pEngineState->registration.detectedScope, &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)
diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h
index 520fdcd57..2ad9111ff 100644
--- a/src/burn/engine/core.h
+++ b/src/burn/engine/core.h
@@ -235,11 +235,6 @@ HRESULT CoreSerializeEngineState(
HRESULT CoreQueryRegistration(
__in BURN_ENGINE_STATE* pEngineState
);
-//HRESULT CoreDeserializeEngineState(
-// __in BURN_ENGINE_STATE* pEngineState,
-// __in_bcount(cbBuffer) BYTE* pbBuffer,
-// __in SIZE_T cbBuffer
-// );
HRESULT CoreDetect(
__in BURN_ENGINE_STATE* pEngineState,
__in_opt HWND hwndParent
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index f7ec03590..edafef970 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -418,7 +418,14 @@ MessageId=227
Severity=Success
SymbolicName=MSG_PLAN_INSTALLED_SCOPE
Language=English
-Bundle was already installed with scope: %1!hs!
+Bundle was already installed with scope: %1!hs!. Scope cannot change during maintenance.
+.
+
+MessageId=228
+Severity=Success
+SymbolicName=MSG_PLAN_UPGRADE_SCOPE
+Language=English
+Upgraded bundle %1!ls! was already installed with scope: %2!hs!. Scope cannot change during upgrade.
.
MessageId=201
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index 889ad68c5..2257b28c8 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -144,6 +144,12 @@ static BOOL ForceCache(
__in BURN_PLAN* pPlan,
__in BURN_PACKAGE* pPackage
);
+static HRESULT GetUpgradedBundleScope(
+ __in DWORD cRelatedBundles,
+ __in BURN_RELATED_BUNDLE* rgRelatedBundles,
+ __in_z LPCWSTR wzUpgradeCode,
+ __inout BOOTSTRAPPER_SCOPE* pScope
+);
// function definitions
@@ -823,6 +829,9 @@ extern "C" HRESULT PlanUpdateBundle(
extern "C" HRESULT PlanPackagesAndBundleScope(
__in BURN_PACKAGE* rgPackages,
__in DWORD cPackages,
+ __in_z LPCWSTR wzUpgradeCode,
+ __in BURN_RELATED_BUNDLE* rgRelatedBundles,
+ __in DWORD cRelatedBundles,
__in BOOTSTRAPPER_SCOPE scope,
__in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope,
__in BOOTSTRAPPER_SCOPE commandLineScope,
@@ -855,7 +864,11 @@ extern "C" HRESULT PlanPackagesAndBundleScope(
}
}
- if (BOOTSTRAPPER_SCOPE_DEFAULT != detectedScope)
+ // If we're upgrading, lock the scope to that of the upgraded bundle.
+ hr = GetUpgradedBundleScope(cRelatedBundles, rgRelatedBundles, wzUpgradeCode, &scope);
+
+ // If we're in maintenance mode instead, lock the scope to the original scope.
+ if (S_FALSE == hr && BOOTSTRAPPER_SCOPE_DEFAULT != detectedScope)
{
scope = detectedScope;
@@ -888,6 +901,48 @@ extern "C" HRESULT PlanPackagesAndBundleScope(
}
+static HRESULT GetUpgradedBundleScope(
+ __in DWORD cRelatedBundles,
+ __in BURN_RELATED_BUNDLE* rgRelatedBundles,
+ __in_z LPCWSTR wzUpgradeCode,
+ __inout BOOTSTRAPPER_SCOPE* pScope
+ )
+{
+ HRESULT hr = S_OK;
+
+ for (DWORD i = 0; i < cRelatedBundles; ++i)
+ {
+ BURN_RELATED_BUNDLE* pRelatedBundle = rgRelatedBundles + i;
+
+ if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->detectRelationType)
+ {
+ for (DWORD j = 0; j < pRelatedBundle->package.Bundle.cUpgradeCodes; ++j)
+ {
+ LPCWSTR wzRelatedUpgradeCode = *(pRelatedBundle->package.Bundle.rgsczUpgradeCodes + j);
+
+ // Is the related bundle's upgrade code the same as ours?
+ // If so, lock our scope to the "original" bundle's scope.
+ if (CSTR_EQUAL == ::CompareStringOrdinal(wzRelatedUpgradeCode, -1, wzUpgradeCode, -1, FALSE))
+ if (CSTR_EQUAL == ::CompareStringOrdinal(wzRelatedUpgradeCode, -1, wzUpgradeCode, -1, TRUE))
+ {
+ *pScope = pRelatedBundle->detectedScope;
+
+ LogId(REPORT_STANDARD, MSG_PLAN_UPGRADE_SCOPE, pRelatedBundle->package.Bundle.sczBundleCode, LoggingBundleScopeToString(*pScope));
+
+ ExitFunction();
+ }
+ }
+ }
+ }
+
+ // No upgrade codes or none match, which is fine. But note it via S_FALSE
+ // so we can distinguish the upgrade case from the maintenance case.
+ hr = S_FALSE;
+
+LExit:
+ return hr;
+}
+
static HRESULT PlanPackagesHelper(
__in BURN_PACKAGE* rgPackages,
__in DWORD cPackages,
diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h
index f9996ac0c..09918440c 100644
--- a/src/burn/engine/plan.h
+++ b/src/burn/engine/plan.h
@@ -485,6 +485,9 @@ void PlanDump(
HRESULT PlanPackagesAndBundleScope(
__in BURN_PACKAGE* rgPackages,
__in DWORD cPackages,
+ __in_z LPCWSTR wzUpgradeCode,
+ __in BURN_RELATED_BUNDLE* rgRelatedBundles,
+ __in DWORD cRelatedBundles,
__in BOOTSTRAPPER_SCOPE scope,
__in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope,
__in BOOTSTRAPPER_SCOPE commandLineScope,
diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp
index e588bef0f..7c9ca1826 100644
--- a/src/burn/engine/registration.cpp
+++ b/src/burn/engine/registration.cpp
@@ -29,9 +29,10 @@ const LPCWSTR REGISTRY_BUNDLE_UNINSTALL_STRING = L"UninstallString";
const LPCWSTR REGISTRY_BUNDLE_RESUME_COMMAND_LINE = L"BundleResumeCommandLine";
const LPCWSTR REGISTRY_BUNDLE_VERSION_MAJOR = L"VersionMajor";
const LPCWSTR REGISTRY_BUNDLE_VERSION_MINOR = L"VersionMinor";
-const LPCWSTR REGISTRY_BUNDLE_SCOPE = L"BundleScope";
const LPCWSTR SWIDTAG_FOLDER = L"swidtag";
const LPCWSTR REGISTRY_BUNDLE_VARIABLE_KEY = L"variables";
+const LPCWSTR REGISTRY_BUNDLE_INSTALLED = L"Installed";
+
// internal function declarations
@@ -146,6 +147,10 @@ extern "C" HRESULT RegistrationParseFromXml(
hr = XmlGetAttributeEx(pixnRegistrationNode, L"Tag", &pRegistration->sczTag);
ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Tag.");
+ // @PrimaryUpgradeCode
+ hr = XmlGetAttributeEx(pixnRegistrationNode, L"PrimaryUpgradeCode", &pRegistration->sczPrimaryUpgradeCode);
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @PrimaryUpgradeCode.");
+
hr = BundlePackageEngineParseRelatedCodes(pixnBundle, &pRegistration->rgsczDetectCodes, &pRegistration->cDetectCodes, &pRegistration->rgsczUpgradeCodes, &pRegistration->cUpgradeCodes, &pRegistration->rgsczAddonCodes, &pRegistration->cAddonCodes, &pRegistration->rgsczPatchCodes, &pRegistration->cPatchCodes);
ExitOnFailure(hr, "Failed to parse related bundles");
@@ -327,7 +332,8 @@ extern "C" void RegistrationUninitialize(
{
ReleaseStr(pRegistration->sczCode);
ReleaseStr(pRegistration->sczTag);
-
+ ReleaseStr(pRegistration->sczPrimaryUpgradeCode);
+
for (DWORD i = 0; i < pRegistration->cDetectCodes; ++i)
{
ReleaseStr(pRegistration->rgsczDetectCodes[i]);
@@ -666,8 +672,8 @@ extern "C" HRESULT RegistrationSessionBegin(
hr = RegWriteStringFormatted(hkRegistration, REGISTRY_BUNDLE_DISPLAY_ICON, L"%s,0", pRegistration->sczCacheExecutablePath);
ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_DISPLAY_ICON);
- hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_SCOPE, pRegistration->fPerMachine ? BOOTSTRAPPER_SCOPE_PER_MACHINE : BOOTSTRAPPER_SCOPE_PER_USER);
- ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_SCOPE);
+ hr = RegWriteNumber(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE, pRegistration->fPerMachine ? BOOTSTRAPPER_SCOPE_PER_MACHINE : BOOTSTRAPPER_SCOPE_PER_USER);
+ ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE);
// update display name
hr = UpdateBundleNameRegistration(pRegistration, pVariables, hkRegistration, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS == registrationType);
@@ -1780,8 +1786,8 @@ static HRESULT DetectInstalled(
pRegistration->detectedRegistrationType = (1 == dwInstalled) ? BOOTSTRAPPER_REGISTRATION_TYPE_FULL : BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS;
- hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_SCOPE, &dwScope);
- ExitOnFailure(hr, "Failed to read registration %ls@%ls.", pRegistration->sczRegistrationKey, REGISTRY_BUNDLE_SCOPE);
+ hr = RegReadNumber(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE, &dwScope);
+ ExitOnFailure(hr, "Failed to read registration %ls@%ls.", pRegistration->sczRegistrationKey, BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE);
pRegistration->detectedScope = static_cast(dwScope);
}
diff --git a/src/burn/engine/registration.h b/src/burn/engine/registration.h
index f340999a4..97c6951b1 100644
--- a/src/burn/engine/registration.h
+++ b/src/burn/engine/registration.h
@@ -21,8 +21,7 @@ const LPCWSTR BURN_REGISTRATION_REGISTRY_ENGINE_VERSION = L"EngineVersion";
const LPCWSTR BURN_REGISTRATION_REGISTRY_ENGINE_PROTOCOL_VERSION = L"EngineProtocolVersion";
const LPCWSTR BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY = L"BundleProviderKey";
const LPCWSTR BURN_REGISTRATION_REGISTRY_BUNDLE_TAG = L"BundleTag";
-
-const LPCWSTR REGISTRY_BUNDLE_INSTALLED = L"Installed";
+const LPCWSTR BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE = L"BundleScope";
enum BURN_RESUME_MODE
{
@@ -69,6 +68,7 @@ typedef struct _BURN_RELATED_BUNDLE
BOOTSTRAPPER_REQUEST_STATE defaultRequestedRestore;
BOOTSTRAPPER_REQUEST_STATE requestedRestore;
BOOTSTRAPPER_ACTION_STATE restore;
+ BOOTSTRAPPER_SCOPE detectedScope;
} BURN_RELATED_BUNDLE;
typedef struct _BURN_RELATED_BUNDLES
@@ -106,6 +106,7 @@ typedef struct _BURN_REGISTRATION
BOOTSTRAPPER_PACKAGE_SCOPE scope;
LPWSTR sczCode;
LPWSTR sczTag;
+ LPWSTR sczPrimaryUpgradeCode;
LPWSTR *rgsczDetectCodes;
DWORD cDetectCodes;
diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp
index d0b97af0a..166c4ae83 100644
--- a/src/burn/engine/relatedbundle.cpp
+++ b/src/burn/engine/relatedbundle.cpp
@@ -325,6 +325,7 @@ static HRESULT LoadRelatedBundleFromKey(
BOOL fExists = FALSE;
BURN_DEPENDENCY_PROVIDER dependencyProvider = { };
BURN_DEPENDENCY_PROVIDER* pBundleDependencyProvider = NULL;
+ DWORD dwScope = 0;
// Only support progress from engines that are compatible.
hr = RegReadNumber(hkBundleCode, BURN_REGISTRATION_REGISTRY_ENGINE_PROTOCOL_VERSION, &dwEngineProtocolVersion);
@@ -355,6 +356,11 @@ static HRESULT LoadRelatedBundleFromKey(
LogId(REPORT_WARNING, MSG_RELATED_PACKAGE_INVALID_VERSION, wzRelatedBundleCode, sczBundleVersion);
}
+ hr = RegReadNumber(hkBundleCode, BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE, &dwScope);
+ ExitOnFailure(hr, "Failed to read registration %ls for bundle %ls.", wzRelatedBundleCode, BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE);
+
+ pRelatedBundle->detectedScope = static_cast(dwScope);
+
hr = RegReadString(hkBundleCode, BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH, &sczCachePath);
ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleCode);
@@ -390,6 +396,12 @@ static HRESULT LoadRelatedBundleFromKey(
pRelatedBundle->detectRelationType = relationType;
+ hr = StrAllocString(&pRelatedBundle->package.Bundle.sczBundleCode, wzRelatedBundleCode, 0);
+ ExitOnFailure(hr, "Failed to bundle code to related bundle.");
+
+ hr = RegReadStringArray(hkBundleCode, BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &pRelatedBundle->package.Bundle.rgsczUpgradeCodes, &pRelatedBundle->package.Bundle.cUpgradeCodes);
+ ExitOnFailure(hr, "Failed to read upgrade codes.");
+
hr = PseudoBundleInitializeRelated(&pRelatedBundle->package, fSupportsBurnProtocol, fPerMachine, wzRelatedBundleCode,
#ifdef DEBUG
pRelatedBundle->detectRelationType,
diff --git a/src/burn/test/BurnUnitTest/RelatedBundleTest.cpp b/src/burn/test/BurnUnitTest/RelatedBundleTest.cpp
index dcccc5890..38c991217 100644
--- a/src/burn/test/BurnUnitTest/RelatedBundleTest.cpp
+++ b/src/burn/test/BurnUnitTest/RelatedBundleTest.cpp
@@ -178,6 +178,9 @@ namespace Bootstrapper
hr = RegWriteString(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, wzVersion);
NativeAssert::Succeeded(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION);
+
+ hr = RegWriteNumber(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE, fPerMachine ? BOOTSTRAPPER_SCOPE_PER_MACHINE : BOOTSTRAPPER_SCOPE_PER_USER);
+ NativeAssert::Succeeded(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_SCOPE);
}
finally
{
diff --git a/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBA.wixproj b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBA.wixproj
index 30d850d42..258d7b424 100644
--- a/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBA.wixproj
+++ b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBA.wixproj
@@ -1,6 +1,7 @@
TestBA
+ $(DefineConstants);Version=1.0.0.0
diff --git a/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBAv2.wixproj b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBAv2.wixproj
new file mode 100644
index 000000000..0daacca88
--- /dev/null
+++ b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleTestBAv2.wixproj
@@ -0,0 +1,8 @@
+
+
+ TestBA
+ $(DefineConstants);Version=2.0.0.0
+
+
+
+
\ No newline at end of file
diff --git a/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleWixStdBA.wixproj b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleWixStdBA.wixproj
index 56db1fdca..9ca5f8a3f 100644
--- a/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleWixStdBA.wixproj
+++ b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/AllPuomBundleWixStdBA.wixproj
@@ -1,6 +1,7 @@
WixStdBA
+ $(DefineConstants);Version=1.0.0.0
diff --git a/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/Bundle.wxs b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/Bundle.wxs
index 4cb11a984..8e1a881af 100644
--- a/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/Bundle.wxs
+++ b/src/test/burn/TestData/ConfigurableScopeTests/AllPuomBundle/Bundle.wxs
@@ -1,5 +1,5 @@
-
+
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs
index 8b31ac001..bb1381b39 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/ConfigurableScopeTests.cs
@@ -95,6 +95,54 @@ public void CommandLineScopeTestPerMachine()
pkg2.VerifyInstalled(false);
}
+ [RuntimeFact]
+ public void BundleUpgradeIsLockedToFirstBundlesScope()
+ {
+ var testBAController = this.CreateTestBAController();
+ testBAController.SetBundleScope(BundleScope.Default);
+
+ var bundle = this.CreateBundleInstaller("AllPuomBundleTestBA");
+ var log = bundle.Install();
+
+ bundle.VerifyRegisteredAndInPackageCache(plannedPerMachine: false);
+
+ Assert.True(LogVerifier.MessageInLogFile(log, "Plan begin, 3 packages, action: Install, planned scope: Default"));
+
+ log = bundle.Repair();
+ Assert.True(LogVerifier.MessageInLogFile(log, "Bundle was already installed with scope: PerUser. Scope cannot change during maintenance."));
+
+ var bundleV2 = this.CreateBundleInstaller("AllPuomBundleTestBAv2");
+ testBAController.SetBundleScope(BundleScope.PerMachine);
+ log = bundleV2.Install();
+ Assert.True(LogVerifier.MessageInLogFileRegex(log, @"Upgraded bundle [{][0-9A-Fa-f\-]{36}[}] was already installed with scope: PerUser\. Scope cannot change during upgrade\."));
+
+ bundleV2.Uninstall();
+ bundleV2.VerifyUnregisteredAndRemovedFromPackageCache(plannedPerMachine: false);
+ bundle.VerifyUnregisteredAndRemovedFromPackageCache(plannedPerMachine: false);
+ }
+
+ [RuntimeFact]
+ public void BundleUpgradeWithSameScopeSucceeds()
+ {
+ var bundle = this.CreateBundleInstaller("AllPuomBundleTestBA");
+ var log = bundle.Install();
+
+ bundle.VerifyRegisteredAndInPackageCache(plannedPerMachine: false);
+
+ Assert.True(LogVerifier.MessageInLogFile(log, "Plan begin, 3 packages, action: Install, planned scope: Default"));
+
+ log = bundle.Repair();
+ Assert.True(LogVerifier.MessageInLogFile(log, "Bundle was already installed with scope: PerUser. Scope cannot change during maintenance."));
+
+ var bundleV2 = this.CreateBundleInstaller("AllPuomBundleTestBAv2");
+ log = bundleV2.Install();
+ Assert.True(LogVerifier.MessageInLogFileRegex(log, @"Upgraded bundle [{][0-9A-Fa-f\-]{36}[}] was already installed with scope: PerUser\. Scope cannot change during upgrade\."));
+
+ bundleV2.Uninstall();
+ bundleV2.VerifyUnregisteredAndRemovedFromPackageCache(plannedPerMachine: false);
+ bundle.VerifyUnregisteredAndRemovedFromPackageCache(plannedPerMachine: false);
+ }
+
[RuntimeFact]
public void PMOU_Bundle_Default_Plan_Installs_PerMachine()
{
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
index a1ca32aca..d7f90f1ec 100644
--- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
@@ -227,6 +227,7 @@ public void Execute()
writer.WriteAttributeString("Tag", this.BundleSymbol.Tag);
writer.WriteAttributeString("Version", this.BundleSymbol.Version);
writer.WriteAttributeString("ProviderKey", this.BundleSymbol.ProviderKey);
+ writer.WriteAttributeString("PrimaryUpgradeCode", this.BundleSymbol.UpgradeCode);
writer.WriteStartElement("Arp");
writer.WriteAttributeString("DisplayName", this.BundleSymbol.Name);
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs
index 93aae7be6..ef168f88e 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs
@@ -170,7 +170,7 @@ public void CanBuildSimpleBundle()
var registrationElements = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
"",
}, registrationElements);
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
index 51fdac6f1..fa787977e 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
@@ -50,7 +50,7 @@ public void CanBuildBundleWithBundlePackage()
Assert.True(File.Exists(chainBundlePath));
- var chainBundleId = GetBundleCodeFromWixpdb(chainPdbPath);
+ var (chainBundleId, _) = GetBundleCodesFromWixpdb(chainPdbPath);
// parent.exe
result = WixRunner.Execute(new[]
@@ -68,7 +68,7 @@ public void CanBuildBundleWithBundlePackage()
Assert.True(File.Exists(parentBundlePath));
- var parentBundleId = GetBundleCodeFromWixpdb(parentPdbPath);
+ var (parentBundleId, parentUpgradeCode) = GetBundleCodesFromWixpdb(parentPdbPath);
var extractResult = BundleExtractor.ExtractBAContainer(null, parentBundlePath, parentBaFolderPath, extractFolderPath);
extractResult.AssertSuccess();
@@ -91,7 +91,7 @@ public void CanBuildBundleWithBundlePackage()
var registrations = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -121,7 +121,7 @@ public void CanBuildBundleWithBundlePackage()
Assert.True(File.Exists(grandparentBundlePath));
- var grandparentBundleId = GetBundleCodeFromWixpdb(grandparentPdbPath);
+ var (grandparentBundleId, grandparentUpgradeCode) = GetBundleCodesFromWixpdb(grandparentPdbPath);
var grandparentExtractResult = BundleExtractor.ExtractBAContainer(null, grandparentBundlePath, grandparentBaFolderPath, extractFolderPath);
grandparentExtractResult.AssertSuccess();
@@ -154,7 +154,7 @@ public void CanBuildBundleWithBundlePackage()
registrations = grandparentExtractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -202,7 +202,7 @@ public void CanBuildBundleWithRemoteBundlePackage()
var chainBundleId = "{216BDA7F-74BD-45E8-957B-500552F05629}";
- var parentBundleId = GetBundleCodeFromWixpdb(parentPdbPath);
+ var (parentBundleId, parentUpgradeCode) = GetBundleCodesFromWixpdb(parentPdbPath);
var extractResult = BundleExtractor.ExtractBAContainer(null, parentBundlePath, parentBaFolderPath, extractFolderPath);
extractResult.AssertSuccess();
@@ -224,7 +224,7 @@ public void CanBuildBundleWithRemoteBundlePackage()
var registrations = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -280,7 +280,7 @@ public void CanBuildBundleWithV3BundlePackage()
Assert.True(File.Exists(parentBundlePath));
- var parentBundleId = GetBundleCodeFromWixpdb(parentPdbPath);
+ var (parentBundleId, parentUpgradeCode) = GetBundleCodesFromWixpdb(parentPdbPath);
var extractResult = BundleExtractor.ExtractBAContainer(null, parentBundlePath, baFolderPath, extractFolderPath);
extractResult.AssertSuccess();
@@ -302,7 +302,7 @@ public void CanBuildBundleWithV3BundlePackage()
var registrations = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -364,7 +364,7 @@ public void CanBuildBundleWithPerUserOrMachineBundlePackage()
result.AssertSuccess();
- var bundleId = GetBundleCodeFromWixpdb(bundlePdbPath);
+ var (bundleId, _) = GetBundleCodesFromWixpdb(bundlePdbPath);
var consumingBundleIntermediateFolder = Path.Combine(baseFolder, "obj", "bundle2");
var consumingBundleBinFolder = Path.Combine(baseFolder, "bin", "bundle2");
@@ -383,7 +383,7 @@ public void CanBuildBundleWithPerUserOrMachineBundlePackage()
result.AssertSuccess();
- var bundle2Id = GetBundleCodeFromWixpdb(consumingBundlePdbPath);
+ var (bundle2Id, bundle2UpgradeCode) = GetBundleCodesFromWixpdb(consumingBundlePdbPath);
var parentBaFolderPath = Path.Combine(baseFolder, "parentba");
var grandparentBaFolderPath = Path.Combine(baseFolder, "grandparentba");
@@ -409,7 +409,7 @@ public void CanBuildBundleWithPerUserOrMachineBundlePackage()
var registrations = bundle2ExtractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -461,7 +461,7 @@ public void CanBuildBundleWithAllUsersPackage()
result.AssertSuccess();
- var parentBundleId = GetBundleCodeFromWixpdb(bundlePdbPath);
+ var (parentBundleId, parentUpgradeCode) = GetBundleCodesFromWixpdb(bundlePdbPath);
var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
extractResult.AssertSuccess();
@@ -469,7 +469,7 @@ public void CanBuildBundleWithAllUsersPackage()
var registrations = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -532,7 +532,7 @@ public void CanBuildBundleWithPerUserPackage()
result.AssertSuccess();
- var parentBundleId = GetBundleCodeFromWixpdb(bundlePdbPath);
+ var (parentBundleId, parentUpgradeCode) = GetBundleCodesFromWixpdb(bundlePdbPath);
var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
extractResult.AssertSuccess();
@@ -540,7 +540,7 @@ public void CanBuildBundleWithPerUserPackage()
var registrations = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -603,7 +603,7 @@ public void CanBuildBundleWithPerUserOrMachinePackage()
result.AssertSuccess();
- var parentBundleId = GetBundleCodeFromWixpdb(bundlePdbPath);
+ var (parentBundleId, parentUpgradeCode) = GetBundleCodesFromWixpdb(bundlePdbPath);
var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
extractResult.AssertSuccess();
@@ -611,7 +611,7 @@ public void CanBuildBundleWithPerUserOrMachinePackage()
var registrations = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration");
WixAssert.CompareLineByLine(new[]
{
- $"" +
+ $"" +
"" +
""
}, registrations);
@@ -629,16 +629,15 @@ public void CanBuildBundleWithPerUserOrMachinePackage()
}
}
- private static string GetBundleCodeFromWixpdb(string bundlePdbPath)
+ private static (string, string) GetBundleCodesFromWixpdb(string bundlePdbPath)
{
using (var wixOutput = WixOutput.Read(bundlePdbPath))
{
-
var intermediate = Intermediate.Load(wixOutput);
var section = intermediate.Sections.Single();
var bundleSymbol = section.Symbols.OfType().Single();
- return bundleSymbol.BundleCode;
+ return (bundleSymbol.BundleCode, bundleSymbol.UpgradeCode);
}
}
}
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/DependencyExtensionFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/DependencyExtensionFixture.cs
index e26fda711..e684b7d9e 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/DependencyExtensionFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/DependencyExtensionFixture.cs
@@ -144,7 +144,7 @@ public void CanBuildBundleWithCustomProviderKey()
var registration = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Registration", ignoreAttributesByElementName);
WixAssert.CompareLineByLine(new string[]
{
- "",
+ "",
}, registration);
}
}