diff --git a/src/wix/WixToolset.Core/Compiler_Package.cs b/src/wix/WixToolset.Core/Compiler_Package.cs
index 4b934fa9f..74b3aae26 100644
--- a/src/wix/WixToolset.Core/Compiler_Package.cs
+++ b/src/wix/WixToolset.Core/Compiler_Package.cs
@@ -2504,8 +2504,8 @@ private void ParseSequenceElement(XElement node, SequenceTable sequenceTable)
var exitSequence = CompilerConstants.IntegerNotSet;
var sequence = CompilerConstants.IntegerNotSet;
var showDialog = "Show" == actionName;
- var specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName;
- var specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName;
+ 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.
+ 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.
var suppress = false;
foreach (var attrib in child.Attributes())
@@ -2608,6 +2608,8 @@ private void ParseSequenceElement(XElement node, SequenceTable sequenceTable)
}
}
+ var standardAction = WindowsInstallerStandard.IsStandardAction(actionName);
+
if (customAction && "Custom" == actionName)
{
this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Action"));
@@ -2653,7 +2655,7 @@ private void ParseSequenceElement(XElement node, SequenceTable sequenceTable)
}
// normal standard actions cannot be set overridable by the user (since they are overridable by default)
- if (overridable && WindowsInstallerStandard.IsStandardAction(actionName) && !specialAction)
+ if (overridable && standardAction && !specialAction)
{
this.Core.Write(ErrorMessages.UnexpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Overridable"));
}
@@ -2688,6 +2690,10 @@ private void ParseSequenceElement(XElement node, SequenceTable sequenceTable)
{
access = actionIdentifier.Access;
}
+ else if (standardAction)
+ {
+ access = AccessModifier.Override;
+ }
var symbol = this.Core.AddSymbol(new WixActionSymbol(childSourceLineNumbers, new Identifier(access, sequenceTable, actionName))
{
diff --git a/src/wix/WixToolset.Core/Link/ProcessConflictingSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/ProcessConflictingSymbolsCommand.cs
index 556a24d74..805dbce4d 100644
--- a/src/wix/WixToolset.Core/Link/ProcessConflictingSymbolsCommand.cs
+++ b/src/wix/WixToolset.Core/Link/ProcessConflictingSymbolsCommand.cs
@@ -131,9 +131,16 @@ public void Execute()
// Ensure referenced override symbols actually overrode a virtual symbol.
foreach (var referencedOverrideSymbol in this.OverrideSymbols.Where(s => this.ResolvedSections.Contains(s.Section)))
{
+ // The easiest check is to see if the symbol overrode a virtual symbol. If not, check to see if there were any possible
+ // virtual symbols that could have been overridden. If not, then we have an error.
if (referencedOverrideSymbol.Overrides is null)
{
- this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(referencedOverrideSymbol.Symbol));
+ var otherVirtualsCount = referencedOverrideSymbol.PossiblyConflicts.Count(s => s.Access == AccessModifier.Virtual);
+
+ if (otherVirtualsCount == 0)
+ {
+ this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(referencedOverrideSymbol.Symbol));
+ }
}
}
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/StandardActionFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/StandardActionFixture.cs
new file mode 100644
index 000000000..23cf30ae4
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/StandardActionFixture.cs
@@ -0,0 +1,124 @@
+// 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.
+
+namespace WixToolsetTest.CoreIntegration
+{
+ using System.IO;
+ using System.Linq;
+ using WixInternal.Core.TestPackage;
+ using WixInternal.TestSupport;
+ using Xunit;
+
+ public class StandardActionFixture
+ {
+ [Fact]
+ public void CanCompileSpecialActionWithOverride()
+ {
+ using var fs = new DisposableFileSystem();
+
+ var results = BuildAndQueryMsi(fs, "SpecialActionOverride.wxs");
+
+ WixAssert.CompareLineByLine(new[]
+ {
+ "InstallExecuteSequence:AppSearch\t\t99",
+ "InstallExecuteSequence:CostFinalize\t\t1000",
+ "InstallExecuteSequence:CostInitialize\t\t800",
+ "InstallExecuteSequence:CreateFolders\t\t3700",
+ "InstallExecuteSequence:FileCost\t\t900",
+ "InstallExecuteSequence:FindRelatedProducts\t\t98",
+ "InstallExecuteSequence:InstallFiles\t\t4000",
+ "InstallExecuteSequence:InstallFinalize\t\t6600",
+ "InstallExecuteSequence:InstallInitialize\t\t1500",
+ "InstallExecuteSequence:InstallValidate\t\t1400",
+ "InstallExecuteSequence:LaunchConditions\t\t100",
+ "InstallExecuteSequence:MigrateFeatureStates\t\t1200",
+ "InstallExecuteSequence:ProcessComponents\t\t1600",
+ "InstallExecuteSequence:PublishFeatures\t\t6300",
+ "InstallExecuteSequence:PublishProduct\t\t6400",
+ "InstallExecuteSequence:RegisterProduct\t\t6100",
+ "InstallExecuteSequence:RegisterUser\t\t6000",
+ "InstallExecuteSequence:RemoveExistingProducts\t\t1401",
+ "InstallExecuteSequence:RemoveFiles\t\t3500",
+ "InstallExecuteSequence:RemoveFolders\t\t3600",
+ "InstallExecuteSequence:UnpublishFeatures\t\t1800",
+ "InstallExecuteSequence:ValidateProductID\t\t700",
+ "InstallUISequence:CostFinalize\t\t1000",
+ "InstallUISequence:CostInitialize\t\t800",
+ "InstallUISequence:ExecuteAction\t\t1300",
+ "InstallUISequence:FileCost\t\t900",
+ "InstallUISequence:FindRelatedProducts\t\t25",
+ "InstallUISequence:LaunchConditions\t\t100",
+ "InstallUISequence:MigrateFeatureStates\t\t1200",
+ "InstallUISequence:ValidateProductID\t\t700",
+ }, results);
+ }
+
+ [Fact]
+ public void CanCompileStandardActionWithOverride()
+ {
+ using var fs = new DisposableFileSystem();
+
+ var results = BuildAndQueryMsi(fs, "StandardActionOverride.wxs");
+
+ WixAssert.CompareLineByLine(new[]
+ {
+ "InstallExecuteSequence:CostFinalize\t\t1000",
+ "InstallExecuteSequence:CostInitialize\t\t800",
+ "InstallExecuteSequence:CreateFolders\t\t3700",
+ "InstallExecuteSequence:FileCost\t\t900",
+ "InstallExecuteSequence:FindRelatedProducts\t\t25",
+ "InstallExecuteSequence:InstallFiles\tTEST_CONDITION\t4000",
+ "InstallExecuteSequence:InstallFinalize\t\t6600",
+ "InstallExecuteSequence:InstallInitialize\t\t1500",
+ "InstallExecuteSequence:InstallValidate\t\t1400",
+ "InstallExecuteSequence:LaunchConditions\t\t100",
+ "InstallExecuteSequence:MigrateFeatureStates\t\t1200",
+ "InstallExecuteSequence:ProcessComponents\t\t1600",
+ "InstallExecuteSequence:PublishFeatures\t\t6300",
+ "InstallExecuteSequence:PublishProduct\t\t6400",
+ "InstallExecuteSequence:RegisterProduct\t\t6100",
+ "InstallExecuteSequence:RegisterUser\t\t6000",
+ "InstallExecuteSequence:RemoveExistingProducts\t\t1401",
+ "InstallExecuteSequence:RemoveFiles\t\t3500",
+ "InstallExecuteSequence:RemoveFolders\t\t3600",
+ "InstallExecuteSequence:UnpublishFeatures\t\t1800",
+ "InstallExecuteSequence:ValidateProductID\t\t700",
+ "InstallUISequence:CostFinalize\t\t1000",
+ "InstallUISequence:CostInitialize\t\t800",
+ "InstallUISequence:ExecuteAction\t\t1300",
+ "InstallUISequence:FileCost\t\t900",
+ "InstallUISequence:FindRelatedProducts\t\t25",
+ "InstallUISequence:LaunchConditions\t\t100",
+ "InstallUISequence:MigrateFeatureStates\t\t1200",
+ "InstallUISequence:ValidateProductID\t\t700",
+ }, results);
+ }
+
+ private static string[] BuildAndQueryMsi(DisposableFileSystem fs, string sourceFile)
+ {
+ var folder = TestData.Get(@"TestData");
+
+ var baseFolder = fs.GetFolder();
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
+ var msiPath = Path.Combine(baseFolder, "bin", "test.msi");
+
+ var result = WixRunner.Execute(new[]
+ {
+ "build",
+ Path.Combine(folder, "StandardAction", sourceFile),
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
+ "-intermediateFolder", intermediateFolder,
+ "-o", msiPath
+ });
+
+ result.AssertSuccess();
+
+ var results = Query.QueryDatabase(msiPath, new[]
+ {
+ "InstallExecuteSequence",
+ "InstallUISequence"
+ }).ToArray();
+
+ return results;
+ }
+ }
+}
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/SpecialActionOverride.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/SpecialActionOverride.wxs
new file mode 100644
index 000000000..e10538c18
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/SpecialActionOverride.wxs
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/StandardActionOverride.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/StandardActionOverride.wxs
new file mode 100644
index 000000000..2965014ea
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/StandardAction/StandardActionOverride.wxs
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+