Scheduling standard actions must override virtual definitions from stdlib
Fixes 8115
Rob Mensching committed
Jul 12, 2024 at 23:23 UTC
733886e73a5dab7da37515d98b611cdae1632c2d
5 files changed
+162
-4
src/wix/WixToolset.Core/Compiler_Package.cs
+9
-3
@@ -2504,8 +2504,8 @@ namespace WixToolset.Core
2504
var exitSequence = CompilerConstants.IntegerNotSet;
2505
var sequence = CompilerConstants.IntegerNotSet;
2506
var showDialog = "Show" == actionName;
2507
- var specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName;
2508
- var specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName;
2507
+ var specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName; // these actions do NOT have default sequence numbers and MUST be scheduled.
2508
+ var specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName; // these standard actions have default sequence numbers so they do NOT have to be scheduled.
2509
var suppress = false;
2510
2511
foreach (var attrib in child.Attributes())
@@ -2608,6 +2608,8 @@ namespace WixToolset.Core
2608
}
2609
}
2610
2611
+ var standardAction = WindowsInstallerStandard.IsStandardAction(actionName);
2612
+
2613
if (customAction && "Custom" == actionName)
2614
{
2615
this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Action"));
@@ -2653,7 +2655,7 @@ namespace WixToolset.Core
2655
}
2656
2657
// normal standard actions cannot be set overridable by the user (since they are overridable by default)
2656
- if (overridable && WindowsInstallerStandard.IsStandardAction(actionName) && !specialAction)
2658
+ if (overridable && standardAction && !specialAction)
2659
{
2660
this.Core.Write(ErrorMessages.UnexpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Overridable"));
2661
}
@@ -2688,6 +2690,10 @@ namespace WixToolset.Core
2690
{
2691
access = actionIdentifier.Access;
2692
}
2693
+ else if (standardAction)
2694
+ {
2695
+ access = AccessModifier.Override;
2696
+ }
2697
2698
var symbol = this.Core.AddSymbol(new WixActionSymbol(childSourceLineNumbers, new Identifier(access, sequenceTable, actionName))
2699
{
src/wix/WixToolset.Core/Link/ProcessConflictingSymbolsCommand.cs
+8
-1
@@ -131,9 +131,16 @@ namespace WixToolset.Core.Link
131
// Ensure referenced override symbols actually overrode a virtual symbol.
132
foreach (var referencedOverrideSymbol in this.OverrideSymbols.Where(s => this.ResolvedSections.Contains(s.Section)))
133
{
134
+ // The easiest check is to see if the symbol overrode a virtual symbol. If not, check to see if there were any possible
135
+ // virtual symbols that could have been overridden. If not, then we have an error.
136
if (referencedOverrideSymbol.Overrides is null)
137
{
136
- this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(referencedOverrideSymbol.Symbol));
138
+ var otherVirtualsCount = referencedOverrideSymbol.PossiblyConflicts.Count(s => s.Access == AccessModifier.Virtual);
139
+
140
+ if (otherVirtualsCount == 0)
141
+ {
142
+ this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(referencedOverrideSymbol.Symbol));
143
+ }
144
}
145
}
146
src/wix/test/WixToolsetTest.CoreIntegration/StandardActionFixture.cs
new
+124
@@ -0,0 +1,124 @@
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
+namespace WixToolsetTest.CoreIntegration
4
+{
5
+ using System.IO;
6
+ using System.Linq;
7
+ using WixInternal.Core.TestPackage;
8
+ using WixInternal.TestSupport;
9
+ using Xunit;
10
+
11
+ public class StandardActionFixture
12
+ {
13
+ [Fact]
14
+ public void CanCompileSpecialActionWithOverride()
15
+ {
16
+ using var fs = new DisposableFileSystem();
17
+
18
+ var results = BuildAndQueryMsi(fs, "SpecialActionOverride.wxs");
19
+
20
+ WixAssert.CompareLineByLine(new[]
21
+ {
22
+ "InstallExecuteSequence:AppSearch\t\t99",
23
+ "InstallExecuteSequence:CostFinalize\t\t1000",
24
+ "InstallExecuteSequence:CostInitialize\t\t800",
25
+ "InstallExecuteSequence:CreateFolders\t\t3700",
26
+ "InstallExecuteSequence:FileCost\t\t900",
27
+ "InstallExecuteSequence:FindRelatedProducts\t\t98",
28
+ "InstallExecuteSequence:InstallFiles\t\t4000",
29
+ "InstallExecuteSequence:InstallFinalize\t\t6600",
30
+ "InstallExecuteSequence:InstallInitialize\t\t1500",
31
+ "InstallExecuteSequence:InstallValidate\t\t1400",
32
+ "InstallExecuteSequence:LaunchConditions\t\t100",
33
+ "InstallExecuteSequence:MigrateFeatureStates\t\t1200",
34
+ "InstallExecuteSequence:ProcessComponents\t\t1600",
35
+ "InstallExecuteSequence:PublishFeatures\t\t6300",
36
+ "InstallExecuteSequence:PublishProduct\t\t6400",
37
+ "InstallExecuteSequence:RegisterProduct\t\t6100",
38
+ "InstallExecuteSequence:RegisterUser\t\t6000",
39
+ "InstallExecuteSequence:RemoveExistingProducts\t\t1401",
40
+ "InstallExecuteSequence:RemoveFiles\t\t3500",
41
+ "InstallExecuteSequence:RemoveFolders\t\t3600",
42
+ "InstallExecuteSequence:UnpublishFeatures\t\t1800",
43
+ "InstallExecuteSequence:ValidateProductID\t\t700",
44
+ "InstallUISequence:CostFinalize\t\t1000",
45
+ "InstallUISequence:CostInitialize\t\t800",
46
+ "InstallUISequence:ExecuteAction\t\t1300",
47
+ "InstallUISequence:FileCost\t\t900",
48
+ "InstallUISequence:FindRelatedProducts\t\t25",
49
+ "InstallUISequence:LaunchConditions\t\t100",
50
+ "InstallUISequence:MigrateFeatureStates\t\t1200",
51
+ "InstallUISequence:ValidateProductID\t\t700",
52
+ }, results);
53
+ }
54
+
55
+ [Fact]
56
+ public void CanCompileStandardActionWithOverride()
57
+ {
58
+ using var fs = new DisposableFileSystem();
59
+
60
+ var results = BuildAndQueryMsi(fs, "StandardActionOverride.wxs");
61
+
62
+ WixAssert.CompareLineByLine(new[]
63
+ {
64
+ "InstallExecuteSequence:CostFinalize\t\t1000",
65
+ "InstallExecuteSequence:CostInitialize\t\t800",
66
+ "InstallExecuteSequence:CreateFolders\t\t3700",
67
+ "InstallExecuteSequence:FileCost\t\t900",
68
+ "InstallExecuteSequence:FindRelatedProducts\t\t25",
69
+ "InstallExecuteSequence:InstallFiles\tTEST_CONDITION\t4000",
70
+ "InstallExecuteSequence:InstallFinalize\t\t6600",
71
+ "InstallExecuteSequence:InstallInitialize\t\t1500",
72
+ "InstallExecuteSequence:InstallValidate\t\t1400",
73
+ "InstallExecuteSequence:LaunchConditions\t\t100",
74
+ "InstallExecuteSequence:MigrateFeatureStates\t\t1200",
75
+ "InstallExecuteSequence:ProcessComponents\t\t1600",
76
+ "InstallExecuteSequence:PublishFeatures\t\t6300",
77
+ "InstallExecuteSequence:PublishProduct\t\t6400",
78
+ "InstallExecuteSequence:RegisterProduct\t\t6100",
79
+ "InstallExecuteSequence:RegisterUser\t\t6000",
80
+ "InstallExecuteSequence:RemoveExistingProducts\t\t1401",
81
+ "InstallExecuteSequence:RemoveFiles\t\t3500",
82
+ "InstallExecuteSequence:RemoveFolders\t\t3600",
83
+ "InstallExecuteSequence:UnpublishFeatures\t\t1800",
84
+ "InstallExecuteSequence:ValidateProductID\t\t700",
85
+ "InstallUISequence:CostFinalize\t\t1000",
86
+ "InstallUISequence:CostInitialize\t\t800",
87
+ "InstallUISequence:ExecuteAction\t\t1300",
88
+ "InstallUISequence:FileCost\t\t900",
89
+ "InstallUISequence:FindRelatedProducts\t\t25",
90
+ "InstallUISequence:LaunchConditions\t\t100",
91
+ "InstallUISequence:MigrateFeatureStates\t\t1200",
92
+ "InstallUISequence:ValidateProductID\t\t700",
93
+ }, results);
94
+ }
95
+
96
+ private static string[] BuildAndQueryMsi(DisposableFileSystem fs, string sourceFile)
97
+ {
98
+ var folder = TestData.Get(@"TestData");
99
+
100
+ var baseFolder = fs.GetFolder();
101
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
102
+ var msiPath = Path.Combine(baseFolder, "bin", "test.msi");
103
+
104
+ var result = WixRunner.Execute(new[]
105
+ {
106
+ "build",
107
+ Path.Combine(folder, "StandardAction", sourceFile),
108
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
109
+ "-intermediateFolder", intermediateFolder,
110
+ "-o", msiPath
111
+ });
112
+
113
+ result.AssertSuccess();
114
+
115
+ var results = Query.QueryDatabase(msiPath, new[]
116
+ {
117
+ "InstallExecuteSequence",
118
+ "InstallUISequence"
119
+ }).ToArray();
120
+
121
+ return results;
122
+ }
123
+ }
124
+}
src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/SpecialActionOverride.wxs
new
+11
@@ -0,0 +1,11 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Package Name="~SpecialActionOverride" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"
3
+ Compressed="no">
4
+ <File Source="test.txt" />
5
+
6
+ <InstallExecuteSequence>
7
+ <FindRelatedProducts Before="LaunchConditions" />
8
+ <AppSearch After="FindRelatedProducts" />
9
+ </InstallExecuteSequence>
10
+ </Package>
11
+</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/StandardActionOverride.wxs
new
+10
@@ -0,0 +1,10 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Package Name="~StandardActionOverride" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"
3
+ Compressed="no">
4
+ <File Source="test.txt" />
5
+
6
+ <InstallExecuteSequence>
7
+ <InstallFiles Condition="TEST_CONDITION" />
8
+ </InstallExecuteSequence>
9
+ </Package>
10
+</Wix>