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)