aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Arnson <bob@firegiant.com>2025-03-20 21:14:12 -0400
committerBob Arnson <bob@firegiant.com>2025-03-21 17:00:29 -0400
commit5d532574b351d30a0ef91a8344265b7ff889f82e (patch)
treedbc1364bdf2a548ecd598fe2d3961ad2d6e9593b
parentbf13a0b67dd644eb7d74cb0cfb6876840f73d82b (diff)
downloadwix-5d532574b351d30a0ef91a8344265b7ff889f82e.tar.gz
wix-5d532574b351d30a0ef91a8344265b7ff889f82e.tar.bz2
wix-5d532574b351d30a0ef91a8344265b7ff889f82e.zip
Update registration disappears during upgrade.bob/UpdateRegistrationAcrossUpgrades
Update registration is stored in a shared registry key that Burn takes care to keep around across upgrades. The approach it used broke between WiX v3 and WiX v5. This change makes it work again by not rewriting update registration during upgrade uninstall.
-rw-r--r--src/burn/engine/registration.cpp2
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/Bundle.wxs58
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleA.props7
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wixproj12
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wxs10
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wixproj18
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wxs10
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageA.props9
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageAv1.wixproj4
-rw-r--r--src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv2/PackageAv2.wixproj7
-rw-r--r--src/test/burn/WixTestTools/BundleUpdateRegistration.cs57
-rw-r--r--src/test/burn/WixTestTools/BundleVerifier.cs37
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/OptionalUpdateRegistrationTests.cs40
13 files changed, 270 insertions, 1 deletions
diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp
index 85c006f7..7e00e305 100644
--- a/src/burn/engine/registration.cpp
+++ b/src/burn/engine/registration.cpp
@@ -809,7 +809,7 @@ extern "C" HRESULT RegistrationSessionBegin(
809 } 809 }
810 810
811 // Update registration. 811 // Update registration.
812 if (pRegistration->update.fRegisterUpdate) 812 if (pRegistration->update.fRegisterUpdate && BOOTSTRAPPER_REGISTRATION_TYPE_FULL == registrationType)
813 { 813 {
814 hr = WriteUpdateRegistration(pRegistration, pVariables); 814 hr = WriteUpdateRegistration(pRegistration, pVariables);
815 ExitOnFailure(hr, "Failed to write update registration."); 815 ExitOnFailure(hr, "Failed to write update registration.");
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/Bundle.wxs b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/Bundle.wxs
new file mode 100644
index 00000000..2e920297
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/Bundle.wxs
@@ -0,0 +1,58 @@
1<!-- 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. -->
2
3<?ifndef TestVersion?>
4<?define TestVersion = 1.0.0.0?>
5<?endif?>
6<?ifndef BundleLogDirectory?>
7<?define BundleLogDirectory = .?>
8<?endif?>
9
10<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
11 <Bundle Name="~$(TestGroupName)" Version="$(TestVersion)" Manufacturer="Acme" UpgradeCode="$(UpgradeCode)" Compressed="yes">
12 <Log Prefix="$(BundleLogDirectory)\~$(TestGroupName)_$(BundleName)" />
13
14 <Variable Name="TestGroupName" Value="$(TestGroupName)" />
15
16 <OptionalUpdateRegistration ProductFamily="GreetingsAndFelicitations" Department="Setup Geeks" Classification="Bundle" />
17
18 <?ifdef SoftwareTag?>
19 <SoftwareTag Regid="regid.1995-08.com.example" InstallPath="[CommonAppDataFolder]TestingSwidTags" />
20 <?endif?>
21
22 <?ifndef BA?>
23 <!-- pulled in through the PackageGroupRef below -->
24 <?elseif $(BA) = "TestBA_x64"?>
25 <!-- pulled in through the PackageGroupRef below -->
26 <?elseif $(BA) = "WixBA"?>
27 <!-- pulled in through the PackageGroupRef below -->
28 <?elseif $(BA) = "hyperlinkLicense"?>
29 <BootstrapperApplication>
30 <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" />
31 <PayloadGroupRef Id="ExtraPayloads" />
32 </BootstrapperApplication>
33 <?elseif $(BA) = "iui"?>
34 <BootstrapperApplication>
35 <bal:WixInternalUIBootstrapperApplication />
36 </BootstrapperApplication>
37 <?else?>
38 <BootstrapperApplicationRef Id="$(BA)" />
39 <?endif?>
40
41 <Chain>
42 <?ifndef BA?>
43 <PackageGroupRef Id="TestBA" />
44 <?elseif $(BA) = "TestBA_x64"?>
45 <PackageGroupRef Id="TestBA_x64" />
46 <?elseif $(BA) = "WixBA"?>
47 <PackageGroupRef Id="WixBA" />
48 <?endif?>
49
50 <PackageGroupRef Id="BundlePackages" />
51 </Chain>
52 </Bundle>
53
54 <Fragment>
55 <PayloadGroup Id="virtual ExtraPayloads" />
56 </Fragment>
57
58</Wix>
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleA.props b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleA.props
new file mode 100644
index 00000000..1887f94e
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleA.props
@@ -0,0 +1,7 @@
1<!-- 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. -->
2<Project>
3 <PropertyGroup>
4 <OutputType>Bundle</OutputType>
5 <UpgradeCode>{9510DDE7-CD4F-45B3-9D57-3F7EA04DB33D}</UpgradeCode>
6 </PropertyGroup>
7</Project>
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wixproj b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wixproj
new file mode 100644
index 00000000..0dea1e40
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wixproj
@@ -0,0 +1,12 @@
1<!-- 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. -->
2<Project Sdk="WixToolset.Sdk">
3 <Import Project="BundleA.props" />
4 <ItemGroup>
5 <ProjectReference Include="..\PackageAv1\PackageAv1.wixproj" />
6 <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
7 </ItemGroup>
8 <ItemGroup>
9 <PackageReference Include="WixToolset.BootstrapperApplications.wixext" />
10 <PackageReference Include="WixToolset.NetFx.wixext" />
11 </ItemGroup>
12</Project>
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wxs b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wxs
new file mode 100644
index 00000000..7bf16212
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv1/BundleAv1.wxs
@@ -0,0 +1,10 @@
1<!-- 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. -->
2
3
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <Fragment>
6 <PackageGroup Id="BundlePackages">
7 <MsiPackage Id="PackageA" SourceFile="$(var.PackageAv1.TargetPath)" />
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wixproj b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wixproj
new file mode 100644
index 00000000..271bf54b
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wixproj
@@ -0,0 +1,18 @@
1<!-- 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. -->
2<Project Sdk="WixToolset.Sdk">
3 <Import Project="..\BundleAv1\BundleA.props" />
4 <PropertyGroup>
5 <TestVersion>2.0.0.0</TestVersion>
6 </PropertyGroup>
7 <ItemGroup>
8 <Compile Include="..\BundleAv1\Bundle.wxs" />
9 </ItemGroup>
10 <ItemGroup>
11 <ProjectReference Include="..\PackageAv2\PackageAv2.wixproj" />
12 <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
13 </ItemGroup>
14 <ItemGroup>
15 <PackageReference Include="WixToolset.BootstrapperApplications.wixext" />
16 <PackageReference Include="WixToolset.NetFx.wixext" />
17 </ItemGroup>
18</Project>
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wxs b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wxs
new file mode 100644
index 00000000..5cbee5a8
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/BundleAv2/BundleAv2.wxs
@@ -0,0 +1,10 @@
1<!-- 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. -->
2
3
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <Fragment>
6 <PackageGroup Id="BundlePackages">
7 <MsiPackage Id="PackageA" SourceFile="$(var.PackageAv2.TargetPath)" />
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageA.props b/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageA.props
new file mode 100644
index 00000000..25ae3f42
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageA.props
@@ -0,0 +1,9 @@
1<!-- 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. -->
2<Project>
3 <PropertyGroup>
4 <UpgradeCode>{30746E93-9A4A-48EC-BAEA-3093A2530E73}</UpgradeCode>
5 </PropertyGroup>
6 <ItemGroup>
7 <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
8 </ItemGroup>
9</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageAv1.wixproj b/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageAv1.wixproj
new file mode 100644
index 00000000..45d3b2c8
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv1/PackageAv1.wixproj
@@ -0,0 +1,4 @@
1<!-- 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. -->
2<Project Sdk="WixToolset.Sdk">
3 <Import Project="PackageA.props" />
4</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv2/PackageAv2.wixproj b/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv2/PackageAv2.wixproj
new file mode 100644
index 00000000..d4455f2b
--- /dev/null
+++ b/src/test/burn/TestData/OptionalUpdateRegistrationTests/PackageAv2/PackageAv2.wixproj
@@ -0,0 +1,7 @@
1<!-- 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. -->
2<Project Sdk="WixToolset.Sdk">
3 <Import Project="..\PackageAv1\PackageA.props" />
4 <PropertyGroup>
5 <TestVersion>2.0.0.0</TestVersion>
6 </PropertyGroup>
7</Project>
diff --git a/src/test/burn/WixTestTools/BundleUpdateRegistration.cs b/src/test/burn/WixTestTools/BundleUpdateRegistration.cs
new file mode 100644
index 00000000..2ce68122
--- /dev/null
+++ b/src/test/burn/WixTestTools/BundleUpdateRegistration.cs
@@ -0,0 +1,57 @@
1// 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.
2
3namespace WixTestTools
4{
5 using System;
6 using Microsoft.Win32;
7
8 public class BundleUpdateRegistration
9 {
10 public const string BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PACKAGE_NAME = "PackageName";
11 public const string BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PACKAGE_VERSION = "PackageVersion";
12 public const string BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PUBLISHER = "Publisher";
13 public const string BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PUBLISHING_GROUP = "PublishingGroup";
14
15 public string PackageName { get; set; }
16
17 public string PackageVersion { get; set; }
18
19 public string Publisher { get; set; }
20
21 public string PublishingGroup { get; set; }
22
23 public static bool TryGetPerMachineBundleUpdateRegistration(string manufacturer, string productFamily, string name, bool x64, out BundleUpdateRegistration registration)
24 {
25 return TryGetUpdateRegistration(manufacturer, productFamily, name, x64, perUser: false, out registration);
26 }
27
28 public static bool TryGetPerUserBundleUpdateRegistration(string manufacturer, string productFamily, string name, out BundleUpdateRegistration registration)
29 {
30 return TryGetUpdateRegistration(manufacturer, productFamily, name, x64: true, perUser: true, out registration);
31 }
32
33 private static bool TryGetUpdateRegistration(string manufacturer, string productFamily, string name, bool x64, bool perUser, out BundleUpdateRegistration registration)
34 {
35 var baseKey = perUser ? Registry.CurrentUser : Registry.LocalMachine;
36 var baseKeyPath = x64 ? @$"SOFTWARE\{manufacturer}\Updates\{productFamily}\{name}"
37 : @$"SOFTWARE\WOW6432Node\{manufacturer}\Updates\{productFamily}\{name}";
38 using var idKey = baseKey.OpenSubKey(baseKeyPath);
39
40 if (idKey == null)
41 {
42 registration = null;
43 return false;
44 }
45
46 registration = new BundleUpdateRegistration()
47 {
48 PackageName = idKey.GetValue(BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PACKAGE_NAME) as string,
49 PackageVersion = idKey.GetValue(BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PACKAGE_VERSION) as string,
50 Publisher = idKey.GetValue(BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PUBLISHER) as string,
51 PublishingGroup = idKey.GetValue(BURN_UPDATE_REGISTRATION_REGISTRY_BUNDLE_PUBLISHING_GROUP) as string,
52 };
53
54 return true;
55 }
56 }
57}
diff --git a/src/test/burn/WixTestTools/BundleVerifier.cs b/src/test/burn/WixTestTools/BundleVerifier.cs
index da61d96e..b6181047 100644
--- a/src/test/burn/WixTestTools/BundleVerifier.cs
+++ b/src/test/burn/WixTestTools/BundleVerifier.cs
@@ -6,6 +6,7 @@ namespace WixTestTools
6 using System.IO; 6 using System.IO;
7 using System.Linq; 7 using System.Linq;
8 using System.Text; 8 using System.Text;
9 using System.Xml.Linq;
9 using Microsoft.Win32; 10 using Microsoft.Win32;
10 using WixInternal.TestSupport; 11 using WixInternal.TestSupport;
11 using WixToolset.Data; 12 using WixToolset.Data;
@@ -23,6 +24,8 @@ namespace WixTestTools
23 24
24 private WixBundleSymbol BundleSymbol { get; set; } 25 private WixBundleSymbol BundleSymbol { get; set; }
25 26
27 private WixUpdateRegistrationSymbol UpdateRegistrationSymbol { get; set; }
28
26 private WixBundleSymbol GetBundleSymbol() 29 private WixBundleSymbol GetBundleSymbol()
27 { 30 {
28 if (this.BundleSymbol == null) 31 if (this.BundleSymbol == null)
@@ -36,6 +39,19 @@ namespace WixTestTools
36 return this.BundleSymbol; 39 return this.BundleSymbol;
37 } 40 }
38 41
42 private WixUpdateRegistrationSymbol GetUpdateRegistrationSymbol()
43 {
44 if (this.UpdateRegistrationSymbol == null)
45 {
46 using var wixOutput = WixOutput.Read(this.BundlePdb);
47 var intermediate = Intermediate.Load(wixOutput);
48 var section = intermediate.Sections.Single();
49 this.UpdateRegistrationSymbol = section.Symbols.OfType<WixUpdateRegistrationSymbol>().Single();
50 }
51
52 return this.UpdateRegistrationSymbol;
53 }
54
39 public string GetFullBurnPolicyRegistryPath() 55 public string GetFullBurnPolicyRegistryPath()
40 { 56 {
41 var bundleSymbol = this.GetBundleSymbol(); 57 var bundleSymbol = this.GetBundleSymbol();
@@ -118,6 +134,27 @@ namespace WixTestTools
118 } 134 }
119 } 135 }
120 136
137 public bool TryGetUpdateRegistration(out BundleUpdateRegistration registration)
138 {
139 var bundleSymbol = this.GetBundleSymbol();
140 var x64 = bundleSymbol.Platform != Platform.X86;
141
142 var updateRegistrationSymbol = this.GetUpdateRegistrationSymbol();
143 var manufacturer = updateRegistrationSymbol.Manufacturer;
144 var productFamily = updateRegistrationSymbol.ProductFamily;
145 var name = updateRegistrationSymbol.Name;
146
147
148 if (bundleSymbol.PerMachine)
149 {
150 return BundleUpdateRegistration.TryGetPerMachineBundleUpdateRegistration(manufacturer, productFamily, name, x64, out registration);
151 }
152 else
153 {
154 return BundleUpdateRegistration.TryGetPerUserBundleUpdateRegistration(manufacturer, productFamily, name, out registration);
155 }
156 }
157
121 public BundleRegistration VerifyRegisteredAndInPackageCache(int? expectedSystemComponent = null) 158 public BundleRegistration VerifyRegisteredAndInPackageCache(int? expectedSystemComponent = null)
122 { 159 {
123 Assert.True(this.TryGetRegistration(out var registration)); 160 Assert.True(this.TryGetRegistration(out var registration));
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/OptionalUpdateRegistrationTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/OptionalUpdateRegistrationTests.cs
new file mode 100644
index 00000000..a26a49e5
--- /dev/null
+++ b/src/test/burn/WixToolsetTest.BurnE2E/OptionalUpdateRegistrationTests.cs
@@ -0,0 +1,40 @@
1// 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.
2
3namespace WixToolsetTest.BurnE2E
4{
5 using WixTestTools;
6 using Xunit;
7 using Xunit.Abstractions;
8
9 public class OptionalUpdateRegistrationTests : BurnE2ETests
10 {
11 public OptionalUpdateRegistrationTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
12
13 [RuntimeFact]
14 public void BundleUpdateRegistrationIsStickyAndAccurateAcrossUpgrades()
15 {
16 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
17 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
18 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
19 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
20
21 bundleAv1.Install();
22 bundleAv1.VerifyRegisteredAndInPackageCache();
23 var gotV1Registration = bundleAv1.TryGetUpdateRegistration(out var v1Registration);
24
25 bundleAv2.Install();
26 bundleAv2.VerifyRegisteredAndInPackageCache();
27 var gotV2Registration = bundleAv2.TryGetUpdateRegistration(out var v2Registration);
28
29 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
30
31 Assert.True(gotV1Registration, "Missing v1 update registration.");
32 Assert.True(gotV2Registration, "Missing v2 update registration.");
33
34 Assert.Equal(v1Registration?.Publisher, v2Registration?.Publisher);
35 Assert.Equal(v1Registration?.PublishingGroup, v2Registration?.PublishingGroup);
36 Assert.Equal(v1Registration?.PackageName, v2Registration?.PackageName);
37 Assert.NotEqual(v1Registration?.PackageVersion, v2Registration?.PackageVersion);
38 }
39 }
40}