/// <summary> /// Sequence an action before or after a standard action. /// </summary> /// <param name="actionSymbol">The action symbol to be sequenced.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> private void SequenceActionSymbol(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols) { var after = false; if (actionSymbol.After != null) { after = true; } else if (actionSymbol.Before == null) { throw new InvalidOperationException("Found an action with no Sequence, Before, or After column set."); } var parentActionName = (after ? actionSymbol.After : actionSymbol.Before); var parentActionKey = actionSymbol.SequenceTable.ToString() + "/" + parentActionName; if (!requiredActionSymbols.TryGetValue(parentActionKey, out var parentActionSymbol)) { // If the missing parent action is a standard action (with a suggested sequence number), add it. if (WindowsInstallerStandard.TryGetStandardAction(parentActionKey, out parentActionSymbol)) { // Create a clone to avoid modifying the static copy of the object. // TODO: consider this: parentActionSymbol = parentActionSymbol.Clone(); requiredActionSymbols.Add(parentActionSymbol.Id.Id, parentActionSymbol); } else { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, "Found an action with a non-existent {0} action: {1}.", (after ? "After" : "Before"), parentActionName)); } } else if (actionSymbol == parentActionSymbol || this.ContainsChildActionSymbol(actionSymbol, parentActionSymbol)) // cycle detected { throw new WixException(ErrorMessages.ActionCircularDependency(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action, parentActionSymbol.Action)); } // Add this action to the appropriate list of dependent action symbols. var relativeActions = this.GetRelativeActions(parentActionSymbol); var relatedSymbols = (after ? relativeActions.NextActions : relativeActions.PreviousActions); relatedSymbols.Add(actionSymbol); }
/// <summary> /// Sequence an action before or after a standard action. /// </summary> /// <param name="actionRow">The action row to be sequenced.</param> /// <param name="requiredActionRows">Collection of actions which must be included.</param> private void SequenceActionRow(WixActionTuple actionRow, Dictionary <string, WixActionTuple> requiredActionRows) { var after = false; if (actionRow.After != null) { after = true; } else if (actionRow.Before == null) { throw new InvalidOperationException(WixStrings.EXP_FoundActionRowWithNoSequenceBeforeOrAfterColumnSet); } var parentActionName = (after ? actionRow.After : actionRow.Before); var parentActionKey = actionRow.SequenceTable.ToString() + "/" + parentActionName; if (!requiredActionRows.TryGetValue(parentActionKey, out var parentActionRow)) { // If the missing parent action is a standard action (with a suggested sequence number), add it. if (this.StandardActionsById.TryGetValue(parentActionKey, out parentActionRow)) { // Create a clone to avoid modifying the static copy of the object. // TODO: consider this: parentActionRow = parentActionRow.Clone(); requiredActionRows.Add(parentActionRow.Id.Id, parentActionRow); } else { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_FoundActionRowWinNonExistentAction, (after ? "After" : "Before"), parentActionName)); } } else if (actionRow == parentActionRow || this.ContainsChildActionRow(actionRow, parentActionRow)) // cycle detected { throw new WixException(ErrorMessages.ActionCircularDependency(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, parentActionRow.Action)); } // Add this action to the appropriate list of dependent action rows. var relativeActions = this.GetRelativeActions(parentActionRow); var relatedRows = (after ? relativeActions.NextActions : relativeActions.PreviousActions); relatedRows.Add(actionRow); }
/// <summary> /// Check the specified action symbol to see if it leads to a cycle. /// </summary> /// <para> Use the provided dictionary to note the initial action symbol that first led to each action /// symbol. Any action symbol encountered that has already been encountered starting from a different /// initial action symbol inherits the loop characteristics of that initial action symbol, and thus is /// also not part of a cycle. However, any action symbol encountered that has already been encountered /// starting from the same initial action symbol is an indication that the current action symbol is /// part of a cycle. /// </para> /// <param name="actionSymbol">The action symbol to be checked.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> /// <param name="firstReference">The first encountered action symbol that led to each action symbol.</param> private void CheckForCircularActionReference(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols, Dictionary <WixActionSymbol, WixActionSymbol> firstReference) { WixActionSymbol currentActionSymbol = null; var parentActionSymbol = actionSymbol; do { var previousActionSymbol = currentActionSymbol ?? parentActionSymbol; currentActionSymbol = parentActionSymbol; if (!firstReference.TryGetValue(currentActionSymbol, out var existingInitialActionSymbol)) { firstReference[currentActionSymbol] = actionSymbol; } else if (existingInitialActionSymbol == actionSymbol) { throw new WixException(ErrorMessages.ActionCircularDependency(currentActionSymbol.SourceLineNumbers, currentActionSymbol.SequenceTable.ToString(), currentActionSymbol.Action, previousActionSymbol.Action)); } parentActionSymbol = this.GetParentActionSymbol(currentActionSymbol, requiredActionSymbols); } while (null != parentActionSymbol); }