@joebigelow / wix / commits / 5f744a8c

Remove extension data after extensions get PreDecompileTables callback

Also update Util.wixext decompiler extension to handle the new elements that compile into CustomActions with no additional table data. These exposed the weakness in the decompiler where extension data was removed before extensions got a chance to pre-decompile. Fixes 7151

Rob Mensching committed Jan 14, 2023 at 17:29 UTC 5f744a8c7da649721f7022dc174febd79e7e3e14
5 files changed +104 -17
src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.wxs
+5 -5
@@ -1,4 +1,4 @@
1 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
@@ -13,10 +13,10 @@
13 </Package>
14
15 <Fragment><util:BroadcastSettingChange />
16 -
17 -
18 -
19 - <StandardDirectory Id="ProgramFilesFolder">
16 + <util:QueryNativeMachine />
17 +
18 +
19 + <StandardDirectory Id="ProgramFilesFolder">
20 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
21 </StandardDirectory>
22 </Fragment>
src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs
+41 -2
@@ -9,6 +9,7 @@ namespace WixToolsetTest.Util
9 using WixInternal.Core.TestPackage;
10 using WixToolset.Util;
11 using Xunit;
12 + using System.Xml.Linq;
13
14 public class UtilExtensionFixture
15 {
@@ -62,9 +63,20 @@ namespace WixToolsetTest.Util
63 var output = Path.Combine(folder, "decompile.xml");
64
65 build.BuildAndDecompileAndBuild(Build, Decompile, output);
65 - File.Exists(output);
66 - }
66
67 + var doc = XDocument.Load(output);
68 + var utilElementNames = doc.Descendants()
69 + .Where(e => e.Name.Namespace == "http://wixtoolset.org/schemas/v4/wxs/util")
70 + .Select(e => e.Name.LocalName)
71 + .OrderBy(s => s)
72 + .ToArray();
73 + WixAssert.CompareLineByLine(new[]
74 + {
75 + "FileShare",
76 + "FileSharePermission",
77 + "User",
78 + }, utilElementNames);
79 + }
80
81 [Fact]
82 public void CanBuildCloseApplication()
@@ -225,11 +237,38 @@ namespace WixToolsetTest.Util
237 "CustomAction:Wix4BroadcastEnvironmentChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastEnvironmentChange\t",
238 "CustomAction:Wix4BroadcastSettingChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastSettingChange\t",
239 "CustomAction:Wix4CheckRebootRequired_A64\t65\tWix4UtilCA_A64\tWixCheckRebootRequired\t",
240 + "CustomAction:Wix4QueryNativeMachine_A64\t257\tWix4UtilCA_A64\tWixQueryNativeMachine\t",
241 "CustomAction:Wix4QueryOsDriverInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsDriverInfo\t",
242 "CustomAction:Wix4QueryOsInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsInfo\t",
243 }, results.OrderBy(s => s).ToArray());
244 }
245
246 + [Fact]
247 + public void CanBuildAndDecompiileQueries()
248 + {
249 + var folder = TestData.Get(@"TestData\Queries");
250 + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
251 + var output = Path.Combine(folder, "decompile.xml");
252 +
253 + build.BuildAndDecompileAndBuild(Build, Decompile, output);
254 +
255 + var doc = XDocument.Load(output);
256 + var utilElementNames = doc.Descendants()
257 + .Where(e => e.Name.Namespace == "http://wixtoolset.org/schemas/v4/wxs/util")
258 + .Select(e => e.Name.LocalName)
259 + .OrderBy(s => s)
260 + .ToArray();
261 + WixAssert.CompareLineByLine(new[]
262 + {
263 + "BroadcastEnvironmentChange",
264 + "BroadcastSettingChange",
265 + "CheckRebootRequired",
266 + "QueryNativeMachine",
267 + "QueryWindowsDriverInfo",
268 + "QueryWindowsSuiteInfo",
269 + }, utilElementNames);
270 + }
271 +
272 [Fact]
273 public void CanBuildWithXmlConfig()
274 {
src/ext/Util/wixext/UtilConstants.cs
+6
@@ -11,6 +11,9 @@ namespace WixToolset.Util
11 {
12 internal static readonly XNamespace Namespace = "http://wixtoolset.org/schemas/v4/wxs/util";
13
14 + internal static readonly XName BroadcastEnvironmentChange = Namespace + "BroadcastEnvironmentChange";
15 + internal static readonly XName BroadcastSettingChange = Namespace + "BroadcastSettingChange";
16 + internal static readonly XName CheckRebootRequired = Namespace + "CheckRebootRequired";
17 internal static readonly XName CloseApplicationName = Namespace + "CloseApplication";
18 internal static readonly XName EventManifestName = Namespace + "EventManifest";
19 internal static readonly XName FileShareName = Namespace + "FileShare";
@@ -21,6 +24,9 @@ namespace WixToolset.Util
24 internal static readonly XName PerfCounterName = Namespace + "PerfCounter";
25 internal static readonly XName PerfCounterManifestName = Namespace + "PerfCounterManifest";
26 internal static readonly XName PermissionExName = Namespace + "PermissionEx";
27 + internal static readonly XName QueryNativeMachine = Namespace + "QueryNativeMachine";
28 + internal static readonly XName QueryWindowsDriverInfo = Namespace + "QueryWindowsDriverInfo";
29 + internal static readonly XName QueryWindowsSuiteInfo = Namespace + "QueryWindowsSuiteInfo";
30 internal static readonly XName RemoveFolderExName = Namespace + "RemoveFolderEx";
31 internal static readonly XName RestartResourceName = Namespace + "RestartResource";
32 internal static readonly XName ServiceConfigName = Namespace + "ServiceConfig";
src/ext/Util/wixext/UtilDecompiler.cs
+50 -8
@@ -3,16 +3,15 @@
3 namespace WixToolset.Util
4 {
5 using System;
6 + using System.Collections;
7 + using System.Collections.Generic;
8 using System.IO;
9 + using System.Linq;
10 using System.Text;
8 - using System.Collections;
9 - using System.Diagnostics;
10 -
11 + using System.Xml.Linq;
12 using WixToolset.Data;
12 - using WixToolset.Extensibility;
13 using WixToolset.Data.WindowsInstaller;
14 - using System.Collections.Generic;
15 - using System.Xml.Linq;
14 + using WixToolset.Extensibility;
15 using WixToolset.Util.Symbols;
16
17 /// <summary>
@@ -22,16 +21,47 @@ namespace WixToolset.Util
21 {
22 public override IReadOnlyCollection<TableDefinition> TableDefinitions => UtilTableDefinitions.All;
23
24 + private static readonly Dictionary<string, XName> CustomActionMapping = new Dictionary<string, XName>()
25 + {
26 + { "Wix4BroadcastEnvironmentChange_X86", UtilConstants.BroadcastEnvironmentChange },
27 + { "Wix4BroadcastEnvironmentChange_X64", UtilConstants.BroadcastEnvironmentChange },
28 + { "Wix4BroadcastEnvironmentChange_ARM64", UtilConstants.BroadcastEnvironmentChange },
29 + { "Wix4BroadcastSettingChange_X86", UtilConstants.BroadcastSettingChange },
30 + { "Wix4BroadcastSettingChange_X64", UtilConstants.BroadcastSettingChange },
31 + { "Wix4BroadcastSettingChange_ARM64", UtilConstants.BroadcastSettingChange },
32 + { "Wix4CheckRebootRequired_X86", UtilConstants.CheckRebootRequired },
33 + { "Wix4CheckRebootRequired_X64", UtilConstants.CheckRebootRequired },
34 + { "Wix4CheckRebootRequired_ARM64", UtilConstants.CheckRebootRequired },
35 + { "Wix4QueryNativeMachine_X86", UtilConstants.QueryNativeMachine },
36 + { "Wix4QueryNativeMachine_X64", UtilConstants.QueryNativeMachine },
37 + { "Wix4QueryNativeMachine_ARM64", UtilConstants.QueryNativeMachine },
38 + { "Wix4QueryOsDriverInfo_X86", UtilConstants.QueryWindowsDriverInfo },
39 + { "Wix4QueryOsDriverInfo_X64", UtilConstants.QueryWindowsDriverInfo },
40 + { "Wix4QueryOsDriverInfo_ARM64", UtilConstants.QueryWindowsDriverInfo },
41 + { "Wix4QueryOsInfo_X86", UtilConstants.QueryWindowsSuiteInfo },
42 + { "Wix4QueryOsInfo_X64", UtilConstants.QueryWindowsSuiteInfo },
43 + { "Wix4QueryOsInfo_ARM64", UtilConstants.QueryWindowsSuiteInfo },
44 + };
45 +
46 + private IReadOnlyCollection<string> customActionNames;
47 +
48 /// <summary>
49 /// Called at the beginning of the decompilation of a database.
50 /// </summary>
51 /// <param name="tables">The collection of all tables.</param>
52 public override void PreDecompileTables(TableIndexedCollection tables)
53 {
54 + this.RememberCustomActionNames(tables);
55 this.CleanupSecureCustomProperties(tables);
56 this.CleanupInternetShortcutRemoveFileTables(tables);
57 }
58
59 + private void RememberCustomActionNames(TableIndexedCollection tables)
60 + {
61 + var customActionTable = tables["CustomAction"];
62 + this.customActionNames = customActionTable?.Rows.Select(r => r.GetPrimaryKey()).Distinct().ToList() ?? (IReadOnlyCollection<string>)Array.Empty<string>();
63 + }
64 +
65 /// <summary>
66 /// Decompile the SecureCustomProperties field to PropertyRefs for known extension properties.
67 /// </summary>
@@ -195,6 +225,7 @@ namespace WixToolset.Util
225 /// <param name="tables">The collection of all tables.</param>
226 public override void PostDecompileTables(TableIndexedCollection tables)
227 {
228 + this.FinalizeCustomActions();
229 this.FinalizePerfmonTable(tables);
230 this.FinalizePerfmonManifestTable(tables);
231 this.FinalizeSecureObjectsTable(tables);
@@ -223,7 +254,7 @@ namespace WixToolset.Util
254 AttributeIfNotNull("RebootPrompt", 0x2 == (attribute & 0x2)),
255 AttributeIfNotNull("ElevatedCloseMessage", 0x4 == (attribute & 0x4)),
256 NumericAttributeIfNotNull("Sequence", row, 5),
226 - NumericAttributeIfNotNull("Property", row, 6)
257 + AttributeIfNotNull("Property", row, 6)
258 );
259 }
260 }
@@ -379,7 +410,7 @@ namespace WixToolset.Util
410 if (this.DecompilerHelper.TryGetIndexedElement("Wix4FileShare", row.FieldAsString(0), out var fileShare) ||
411 this.DecompilerHelper.TryGetIndexedElement("FileShare", row.FieldAsString(0), out fileShare))
412 {
382 - fileShare.Add(fileSharePermission);
413 + fileShare.Add(fileSharePermission);
414 }
415 else
416 {
@@ -695,6 +726,17 @@ namespace WixToolset.Util
726 }
727 }
728
729 + private void FinalizeCustomActions()
730 + {
731 + foreach (var customActionName in this.customActionNames)
732 + {
733 + if (CustomActionMapping.TryGetValue(customActionName, out var elementName))
734 + {
735 + this.DecompilerHelper.AddElementToRoot(elementName);
736 + }
737 + }
738 + }
739 +
740 /// <summary>
741 /// Finalize the Perfmon table.
742 /// </summary>
src/wix/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
+2 -2
@@ -2384,12 +2384,12 @@ namespace WixToolset.Core.WindowsInstaller.Decompile
2384 this.DecompilerHelper.RootElement.SetAttributeValue("Guid", this.ModularizationGuid);
2385 }
2386
2387 - this.RemoveExtensionDataFromTables(tables);
2388 -
2387 foreach (var extension in this.Extensions)
2388 {
2389 extension.PreDecompileTables(tables);
2390 }
2391 +
2392 + this.RemoveExtensionDataFromTables(tables);
2393 }
2394
2395 private void RemoveExtensionDataFromTables(TableIndexedCollection tables)