@joebigelow / wix / commits / 733886e7

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>