public void Execute() { var requiredActionSymbols = new Dictionary <string, WixActionSymbol>(); // Get the standard actions required based on symbols in the section. var overridableActionSymbols = this.GetRequiredStandardActions(); // Index all the action symbols and look for collisions. foreach (var actionSymbol in this.Section.Symbols.OfType <WixActionSymbol>()) { if (actionSymbol.Overridable) // overridable action { if (overridableActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol)) { this.Messaging.Write(ErrorMessages.OverridableActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); if (null != collidingActionSymbol.SourceLineNumbers) { this.Messaging.Write(ErrorMessages.OverridableActionCollision2(collidingActionSymbol.SourceLineNumbers)); } } else { overridableActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); } } else // unsequenced or sequenced action. { // Unsequenced action (allowed for certain standard actions). if (null == actionSymbol.Before && null == actionSymbol.After && !actionSymbol.Sequence.HasValue) { if (WindowsInstallerStandard.TryGetStandardAction(actionSymbol.Id.Id, out var standardAction)) { // Populate the sequence from the standard action actionSymbol.Sequence = standardAction.Sequence; } else // not a supported unscheduled action. { throw new InvalidOperationException("Found an action with no Sequence, Before, or After column set."); } } if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol)) { this.Messaging.Write(ErrorMessages.ActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); if (null != collidingActionSymbol.SourceLineNumbers) { this.Messaging.Write(ErrorMessages.ActionCollision2(collidingActionSymbol.SourceLineNumbers)); } } else { requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); } } } // Add the overridable action symbols that are not overridden to the required action symbols. foreach (var actionSymbol in overridableActionSymbols.Values) { if (!requiredActionSymbols.ContainsKey(actionSymbol.Id.Id)) { requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); } } // Suppress the required actions that are overridable. foreach (var suppressActionSymbol in this.Section.Symbols.OfType <WixSuppressActionSymbol>()) { var key = suppressActionSymbol.Id.Id; // If there is an overridable symbol to suppress; suppress it. There is no warning if there // is no action to suppress because the action may be suppressed from a merge module in // the binder. if (requiredActionSymbols.TryGetValue(key, out var requiredActionSymbol)) { if (requiredActionSymbol.Overridable) { this.Messaging.Write(WarningMessages.SuppressAction(suppressActionSymbol.SourceLineNumbers, suppressActionSymbol.Action, suppressActionSymbol.SequenceTable.ToString())); if (null != requiredActionSymbol.SourceLineNumbers) { this.Messaging.Write(WarningMessages.SuppressAction2(requiredActionSymbol.SourceLineNumbers)); } requiredActionSymbols.Remove(key); } else // suppressing a non-overridable action symbol { this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction(suppressActionSymbol.SourceLineNumbers, suppressActionSymbol.SequenceTable.ToString(), suppressActionSymbol.Action)); if (null != requiredActionSymbol.SourceLineNumbers) { this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction2(requiredActionSymbol.SourceLineNumbers)); } } } } // Build up dependency trees of the relatively scheduled actions. // Use ToList() to create a copy of the required action symbols so that new symbols can // be added while enumerating. foreach (var actionSymbol in requiredActionSymbols.Values.ToList()) { if (!actionSymbol.Sequence.HasValue) { // check for standard actions that don't have a sequence number in a merge module if (SectionType.Module == this.Section.Type && WindowsInstallerStandard.IsStandardAction(actionSymbol.Action)) { this.Messaging.Write(ErrorMessages.StandardActionRelativelyScheduledInModule(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); } this.SequenceActionSymbol(actionSymbol, requiredActionSymbols); } else if (SectionType.Module == this.Section.Type && 0 < actionSymbol.Sequence && !WindowsInstallerStandard.IsStandardAction(actionSymbol.Action)) // check for custom actions and dialogs that have a sequence number { this.Messaging.Write(ErrorMessages.CustomActionSequencedInModule(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); } } // Look for standard actions with sequence restrictions that aren't necessarily scheduled based // on the presence of a particular table. if (requiredActionSymbols.ContainsKey("InstallExecuteSequence/DuplicateFiles") && !requiredActionSymbols.ContainsKey("InstallExecuteSequence/InstallFiles")) { WindowsInstallerStandard.TryGetStandardAction("InstallExecuteSequence/InstallFiles", out var standardAction); requiredActionSymbols.Add(standardAction.Id.Id, standardAction); } // Schedule actions. List <WixActionSymbol> scheduledActionSymbols; if (SectionType.Module == this.Section.Type) { scheduledActionSymbols = requiredActionSymbols.Values.ToList(); } else { scheduledActionSymbols = this.ScheduleActions(requiredActionSymbols); } // Remove all existing WixActionSymbols from the section then add the // scheduled actions back to the section. Note: we add the indices in // reverse order to make it easy to remove them from the list later. var removeIndices = new List <int>(); for (var i = this.Section.Symbols.Count - 1; i >= 0; --i) { var symbol = this.Section.Symbols[i]; if (symbol.Definition.Type == SymbolDefinitionType.WixAction) { removeIndices.Add(i); } } foreach (var removeIndex in removeIndices) { this.Section.Symbols.RemoveAt(removeIndex); } foreach (var action in scheduledActionSymbols) { this.Section.AddSymbol(action); } }