/// <summary> /// Finalize the sequence tables. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Creates the sequence elements. Occurs during finalization because its /// not known if sequences refer to custom actions or dialogs during decompilation. /// </remarks> private void FinalizeSequenceTables(TableCollection tables) { // finalize the normal sequence tables if (OutputType.Product == this.outputType && !this.treatProductAsModule) { foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) { // if suppressing UI elements, skip UI-related sequence tables if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString())) { continue; } Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]); Table table = tables[sequenceTable.ToString()]; if (null != table) { ArrayList actionRows = new ArrayList(); bool needAbsoluteScheduling = this.suppressRelativeActionSequencing; WixActionRowCollection nonSequencedActionRows = new WixActionRowCollection(); WixActionRowCollection suppressedRelativeActionRows = new WixActionRowCollection(); // create a sorted array of actions in this table foreach (Row row in table.Rows) { WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null); actionRow.Action = Convert.ToString(row[0]); if (null != row[1]) { actionRow.Condition = Convert.ToString(row[1]); } actionRow.Sequence = Convert.ToInt32(row[2]); actionRow.SequenceTable = sequenceTable; actionRows.Add(actionRow); } actionRows.Sort(); for (int i = 0; i < actionRows.Count && !needAbsoluteScheduling; i++) { WixActionRow actionRow = (WixActionRow)actionRows[i]; WixActionRow standardActionRow = this.standardActions[actionRow.SequenceTable, actionRow.Action]; // create actions for custom actions, dialogs, AppSearch when its moved, and standard actions with non-standard conditions if ("AppSearch" == actionRow.Action || null == standardActionRow || actionRow.Condition != standardActionRow.Condition) { WixActionRow previousActionRow = null; WixActionRow nextActionRow = null; // find the previous action row if there is one if (0 <= i - 1) { previousActionRow = (WixActionRow)actionRows[i - 1]; } // find the next action row if there is one if (actionRows.Count > i + 1) { nextActionRow = (WixActionRow)actionRows[i + 1]; } // the logic for setting the before or after attribute for an action: // 1. If more than one action shares the same sequence number, everything must be absolutely sequenced. // 2. If the next action is a standard action and is 1 sequence number higher, this action occurs before it. // 3. If the previous action is a standard action and is 1 sequence number lower, this action occurs after it. // 4. If this action is not standard and the previous action is 1 sequence number lower and does not occur before this action, this action occurs after it. // 5. If this action is not standard and the previous action does not have the same sequence number and the next action is 1 sequence number higher, this action occurs before it. // 6. If this action is AppSearch and has all standard information, ignore it. // 7. If this action is standard and has a non-standard condition, create the action without any scheduling information. // 8. Everything must be absolutely sequenced. if ((null != previousActionRow && actionRow.Sequence == previousActionRow.Sequence) || (null != nextActionRow && actionRow.Sequence == nextActionRow.Sequence)) { needAbsoluteScheduling = true; } else if (null != nextActionRow && null != this.standardActions[sequenceTable, nextActionRow.Action] && actionRow.Sequence + 1 == nextActionRow.Sequence) { actionRow.Before = nextActionRow.Action; } else if (null != previousActionRow && null != this.standardActions[sequenceTable, previousActionRow.Action] && actionRow.Sequence - 1 == previousActionRow.Sequence) { actionRow.After = previousActionRow.Action; } else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence - 1 == previousActionRow.Sequence && previousActionRow.Before != actionRow.Action) { actionRow.After = previousActionRow.Action; } else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence != previousActionRow.Sequence && null != nextActionRow && actionRow.Sequence + 1 == nextActionRow.Sequence) { actionRow.Before = nextActionRow.Action; } else if ("AppSearch" == actionRow.Action && null != standardActionRow && actionRow.Sequence == standardActionRow.Sequence && actionRow.Condition == standardActionRow.Condition) { // ignore an AppSearch row which has the WiX standard sequence and a standard condition } else if (null != standardActionRow && actionRow.Condition != standardActionRow.Condition) // standard actions get their standard sequence numbers { nonSequencedActionRows.Add(actionRow); } else if (0 < actionRow.Sequence) { needAbsoluteScheduling = true; } } else { suppressedRelativeActionRows.Add(actionRow); } } // create the actions now that we know if they must be absolutely or relatively scheduled foreach (WixActionRow actionRow in actionRows) { if (needAbsoluteScheduling) { // remove any before/after information to ensure this is absolutely sequenced actionRow.Before = null; actionRow.After = null; } else if (nonSequencedActionRows.Contains(actionRow.SequenceTable, actionRow.Action)) { // clear the sequence attribute to ensure this action is scheduled without a sequence number (or before/after) actionRow.Sequence = 0; } else if (suppressedRelativeActionRows.Contains(actionRow.SequenceTable, actionRow.Action)) { // skip the suppressed relatively scheduled action rows continue; } // create the action element this.CreateActionElement(actionRow); } } } } else if (OutputType.Module == this.outputType || this.treatProductAsModule) // finalize the Module sequence tables { foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) { // if suppressing UI elements, skip UI-related sequence tables if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString())) { continue; } Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]); Table table = tables[String.Concat("Module", sequenceTable.ToString())]; if (null != table) { foreach (Row row in table.Rows) { WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null); actionRow.Action = Convert.ToString(row[0]); if (null != row[1]) { actionRow.Sequence = Convert.ToInt32(row[1]); } if (null != row[2] && null != row[3]) { switch (Convert.ToInt32(row[3])) { case 0: actionRow.Before = Convert.ToString(row[2]); break; case 1: actionRow.After = Convert.ToString(row[2]); break; default: this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3])); break; } } if (null != row[4]) { actionRow.Condition = Convert.ToString(row[4]); } actionRow.SequenceTable = sequenceTable; // create action elements for non-standard actions if (null == this.standardActions[actionRow.SequenceTable, actionRow.Action] || null != actionRow.After || null != actionRow.Before) { this.CreateActionElement(actionRow); } } } } } }
/// <summary> /// Set sequence numbers for all the actions and create rows in the output object. /// </summary> /// <param name="actionRows">Collection of actions to schedule.</param> /// <param name="suppressActionRows">Collection of actions to suppress.</param> private void SequenceActions(RowCollection actionRows, RowCollection suppressActionRows) { WixActionRowCollection overridableActionRows = new WixActionRowCollection(); WixActionRowCollection requiredActionRows = new WixActionRowCollection(); ArrayList scheduledActionRows = new ArrayList(); // gather the required actions for the output type if (OutputType.Product == this.activeOutput.Type) { // AdminExecuteSequence table overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "CostFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "CostInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "FileCost"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "InstallAdminPackage"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "InstallFiles"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "InstallFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "InstallInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminExecuteSequence, "InstallValidate"]); // AdminUISequence table overridableActionRows.Add(this.standardActions[SequenceTable.AdminUISequence, "CostFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminUISequence, "CostInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminUISequence, "ExecuteAction"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdminUISequence, "FileCost"]); // AdvtExecuteSequence table overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "CostFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "CostInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "InstallFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "InstallInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "InstallValidate"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "PublishFeatures"]); overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "PublishProduct"]); // InstallExecuteSequence table overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "CostFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "CostInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "FileCost"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "InstallFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "InstallInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "InstallValidate"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "ProcessComponents"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "PublishFeatures"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "PublishProduct"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterProduct"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterUser"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnpublishFeatures"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "ValidateProductID"]); // InstallUISequence table overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "CostFinalize"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "CostInitialize"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "ExecuteAction"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "FileCost"]); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "ValidateProductID"]); } // gather the required actions for each table foreach (Table table in this.activeOutput.Tables) { switch (table.Name) { case "AppSearch": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "AppSearch"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "AppSearch"], true); break; case "BindImage": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "BindImage"], true); break; case "CCPSearch": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "AppSearch"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "CCPSearch"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RMCCPSearch"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "AppSearch"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "CCPSearch"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "RMCCPSearch"], true); break; case "Class": overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "RegisterClassInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterClassInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnregisterClassInfo"], true); break; case "Complus": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterComPlus"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnregisterComPlus"], true); break; case "CreateFolder": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "CreateFolders"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveFolders"], true); break; case "DuplicateFile": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "DuplicateFiles"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveDuplicateFiles"], true); break; case "Environment": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "WriteEnvironmentStrings"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveEnvironmentStrings"], true); break; case "Extension": overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "RegisterExtensionInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterExtensionInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnregisterExtensionInfo"], true); break; case "File": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "InstallFiles"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveFiles"], true); break; case "Font": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterFonts"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnregisterFonts"], true); break; case "IniFile": case "RemoveIniFile": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "WriteIniValues"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveIniValues"], true); break; case "IsolatedComponent": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "IsolateComponents"], true); break; case "LaunchCondition": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "LaunchConditions"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "LaunchConditions"], true); break; case "MIME": overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "RegisterMIMEInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterMIMEInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnregisterMIMEInfo"], true); break; case "MoveFile": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "MoveFiles"], true); break; case "MsiAssembly": overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "MsiPublishAssemblies"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "MsiPublishAssemblies"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "MsiUnpublishAssemblies"], true); break; case "MsiServiceConfig": case "MsiServiceConfigFailureActions": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "MsiConfigureServices"], true); break; case "ODBCDataSource": case "ODBCTranslator": case "ODBCDriver": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "SetODBCFolders"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "InstallODBC"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveODBC"], true); break; case "ProgId": overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "RegisterProgIdInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterProgIdInfo"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnregisterProgIdInfo"], true); break; case "PublishComponent": overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "PublishComponents"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "PublishComponents"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnpublishComponents"], true); break; case "Registry": case "RemoveRegistry": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "WriteRegistryValues"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveRegistryValues"], true); break; case "RemoveFile": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveFiles"], true); break; case "SelfReg": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "SelfRegModules"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "SelfUnregModules"], true); break; case "ServiceControl": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "StartServices"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "StopServices"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "DeleteServices"], true); break; case "ServiceInstall": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "InstallServices"], true); break; case "Shortcut": overridableActionRows.Add(this.standardActions[SequenceTable.AdvtExecuteSequence, "CreateShortcuts"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "CreateShortcuts"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RemoveShortcuts"], true); break; case "TypeLib": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "RegisterTypeLibraries"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "UnregisterTypeLibraries"], true); break; case "Upgrade": overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "FindRelatedProducts"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "FindRelatedProducts"], true); // Only add the MigrateFeatureStates action if MigrateFeature attribute is set to yes on at least one UpgradeVersion element. foreach (Row row in table.Rows) { int options = (int)row[4]; if (MsiInterop.MsidbUpgradeAttributesMigrateFeatures == (options & MsiInterop.MsidbUpgradeAttributesMigrateFeatures)) { overridableActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "MigrateFeatureStates"], true); overridableActionRows.Add(this.standardActions[SequenceTable.InstallUISequence, "MigrateFeatureStates"], true); break; } } break; } } // index all the action rows (look for collisions) foreach (WixActionRow actionRow in actionRows) { if (actionRow.Overridable) // overridable action { WixActionRow collidingActionRow = overridableActionRows[actionRow.SequenceTable, actionRow.Action]; if (null != collidingActionRow) { this.OnMessage(WixErrors.OverridableActionCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); if (null != collidingActionRow.SourceLineNumbers) { this.OnMessage(WixErrors.OverridableActionCollision2(collidingActionRow.SourceLineNumbers)); } } else { overridableActionRows.Add(actionRow); } } else // unscheduled/scheduled action { // unscheduled action (allowed for certain standard actions) if (null == actionRow.Before && null == actionRow.After && 0 == actionRow.Sequence) { WixActionRow standardAction = this.standardActions[actionRow.SequenceTable, actionRow.Action]; if (null != standardAction) { // populate the sequence from the standard action actionRow.Sequence = standardAction.Sequence; } else // not a supported unscheduled action { throw new InvalidOperationException(WixStrings.EXP_FoundActionRowWithNoSequenceBeforeOrAfterColumnSet); } } WixActionRow collidingActionRow = requiredActionRows[actionRow.SequenceTable, actionRow.Action]; if (null != collidingActionRow) { this.OnMessage(WixErrors.ActionCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); if (null != collidingActionRow.SourceLineNumbers) { this.OnMessage(WixErrors.ActionCollision2(collidingActionRow.SourceLineNumbers)); } } else { requiredActionRows.Add(actionRow.Clone()); } } } // add the overridable action rows that are not overridden to the required action rows foreach (WixActionRow actionRow in overridableActionRows) { if (null == requiredActionRows[actionRow.SequenceTable, actionRow.Action]) { requiredActionRows.Add(actionRow.Clone()); } } // suppress the required actions that are overridable foreach (Row suppressActionRow in suppressActionRows) { SequenceTable sequenceTable = (SequenceTable)Enum.Parse(typeof(SequenceTable), (string)suppressActionRow[0]); string action = (string)suppressActionRow[1]; // get the action being suppressed (if it exists) WixActionRow requiredActionRow = requiredActionRows[sequenceTable, action]; // if there is an overridable row 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 (null != requiredActionRow) { if (requiredActionRow.Overridable) { this.OnMessage(WixWarnings.SuppressAction(suppressActionRow.SourceLineNumbers, action, sequenceTable.ToString())); if (null != requiredActionRow.SourceLineNumbers) { this.OnMessage(WixWarnings.SuppressAction2(requiredActionRow.SourceLineNumbers)); } requiredActionRows.Remove(sequenceTable, action); } else // suppressing a non-overridable action row { this.OnMessage(WixErrors.SuppressNonoverridableAction(suppressActionRow.SourceLineNumbers, sequenceTable.ToString(), action)); if (null != requiredActionRow.SourceLineNumbers) { this.OnMessage(WixErrors.SuppressNonoverridableAction2(requiredActionRow.SourceLineNumbers)); } } } } // create a copy of the required action rows so that new rows can be added while enumerating WixActionRow[] copyOfRequiredActionRows = new WixActionRow[requiredActionRows.Count]; requiredActionRows.CopyTo(copyOfRequiredActionRows, 0); // build up dependency trees of the relatively scheduled actions foreach (WixActionRow actionRow in copyOfRequiredActionRows) { if (0 == actionRow.Sequence) { // check for standard actions that don't have a sequence number in a merge module if (OutputType.Module == this.activeOutput.Type && Util.IsStandardAction(actionRow.Action)) { this.OnMessage(WixErrors.StandardActionRelativelyScheduledInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); } this.SequenceActionRow(actionRow, requiredActionRows); } else if (OutputType.Module == this.activeOutput.Type && 0 < actionRow.Sequence && !Util.IsStandardAction(actionRow.Action)) // check for custom actions and dialogs that have a sequence number { this.OnMessage(WixErrors.CustomActionSequencedInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); } } // look for standard actions with sequence restrictions that aren't necessarily scheduled based on the presence of a particular table if (requiredActionRows.Contains(SequenceTable.InstallExecuteSequence, "DuplicateFiles") && !requiredActionRows.Contains(SequenceTable.InstallExecuteSequence, "InstallFiles")) { requiredActionRows.Add(this.standardActions[SequenceTable.InstallExecuteSequence, "InstallFiles"], true); } // schedule actions if (OutputType.Module == this.activeOutput.Type) { // add the action row to the list of scheduled action rows scheduledActionRows.AddRange(requiredActionRows); } else { // process each sequence table individually foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) { // create a collection of just the action rows in this sequence WixActionRowCollection sequenceActionRows = new WixActionRowCollection(); foreach (WixActionRow actionRow in requiredActionRows) { if (sequenceTable == actionRow.SequenceTable) { sequenceActionRows.Add(actionRow); } } // schedule the absolutely scheduled actions (by sorting them by their sequence numbers) ArrayList absoluteActionRows = new ArrayList(); foreach (WixActionRow actionRow in sequenceActionRows) { if (0 != actionRow.Sequence) { // look for sequence number collisions foreach (WixActionRow sequenceScheduledActionRow in absoluteActionRows) { if (sequenceScheduledActionRow.Sequence == actionRow.Sequence) { this.OnMessage(WixWarnings.ActionSequenceCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, sequenceScheduledActionRow.Action, actionRow.Sequence)); if (null != sequenceScheduledActionRow.SourceLineNumbers) { this.OnMessage(WixWarnings.ActionSequenceCollision2(sequenceScheduledActionRow.SourceLineNumbers)); } } } absoluteActionRows.Add(actionRow); } } absoluteActionRows.Sort(); // schedule the relatively scheduled actions (by resolving the dependency trees) int previousUsedSequence = 0; ArrayList relativeActionRows = new ArrayList(); for (int j = 0; j < absoluteActionRows.Count; j++) { WixActionRow absoluteActionRow = (WixActionRow)absoluteActionRows[j]; int unusedSequence; // get all the relatively scheduled action rows occuring before this absolutely scheduled action row RowCollection allPreviousActionRows = new RowCollection(); absoluteActionRow.GetAllPreviousActionRows(sequenceTable, allPreviousActionRows); // get all the relatively scheduled action rows occuring after this absolutely scheduled action row RowCollection allNextActionRows = new RowCollection(); absoluteActionRow.GetAllNextActionRows(sequenceTable, allNextActionRows); // check for relatively scheduled actions occuring before/after a special action (these have a negative sequence number) if (0 > absoluteActionRow.Sequence && (0 < allPreviousActionRows.Count || 0 < allNextActionRows.Count)) { // create errors for all the before actions foreach (WixActionRow actionRow in allPreviousActionRows) { this.OnMessage(WixErrors.ActionScheduledRelativeToTerminationAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, absoluteActionRow.Action)); } // create errors for all the after actions foreach (WixActionRow actionRow in allNextActionRows) { this.OnMessage(WixErrors.ActionScheduledRelativeToTerminationAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, absoluteActionRow.Action)); } // if there is source line information for the absolutely scheduled action display it if (null != absoluteActionRow.SourceLineNumbers) { this.OnMessage(WixErrors.ActionScheduledRelativeToTerminationAction2(absoluteActionRow.SourceLineNumbers)); } continue; } // schedule the action rows before this one unusedSequence = absoluteActionRow.Sequence - 1; for (int i = allPreviousActionRows.Count - 1; i >= 0; i--) { WixActionRow relativeActionRow = (WixActionRow)allPreviousActionRows[i]; // look for collisions if (unusedSequence == previousUsedSequence) { this.OnMessage(WixErrors.NoUniqueActionSequenceNumber(relativeActionRow.SourceLineNumbers, relativeActionRow.SequenceTable.ToString(), relativeActionRow.Action, absoluteActionRow.Action)); if (null != absoluteActionRow.SourceLineNumbers) { this.OnMessage(WixErrors.NoUniqueActionSequenceNumber2(absoluteActionRow.SourceLineNumbers)); } unusedSequence++; } relativeActionRow.Sequence = unusedSequence; relativeActionRows.Add(relativeActionRow); unusedSequence--; } // determine the next used action sequence number int nextUsedSequence; if (absoluteActionRows.Count > j + 1) { nextUsedSequence = ((WixActionRow)absoluteActionRows[j + 1]).Sequence; } else { nextUsedSequence = short.MaxValue + 1; } // schedule the action rows after this one unusedSequence = absoluteActionRow.Sequence + 1; for (int i = 0; i < allNextActionRows.Count; i++) { WixActionRow relativeActionRow = (WixActionRow)allNextActionRows[i]; if (unusedSequence == nextUsedSequence) { this.OnMessage(WixErrors.NoUniqueActionSequenceNumber(relativeActionRow.SourceLineNumbers, relativeActionRow.SequenceTable.ToString(), relativeActionRow.Action, absoluteActionRow.Action)); if (null != absoluteActionRow.SourceLineNumbers) { this.OnMessage(WixErrors.NoUniqueActionSequenceNumber2(absoluteActionRow.SourceLineNumbers)); } unusedSequence--; } relativeActionRow.Sequence = unusedSequence; relativeActionRows.Add(relativeActionRow); unusedSequence++; } // keep track of this sequence number as the previous used sequence number for the next iteration previousUsedSequence = absoluteActionRow.Sequence; } // add the absolutely and relatively scheduled actions to the list of scheduled actions scheduledActionRows.AddRange(absoluteActionRows); scheduledActionRows.AddRange(relativeActionRows); } } // create the action rows for sequences that are not suppressed foreach (WixActionRow actionRow in scheduledActionRows) { // skip actions in suppressed sequences if ((this.suppressAdminSequence && (SequenceTable.AdminExecuteSequence == actionRow.SequenceTable || SequenceTable.AdminUISequence == actionRow.SequenceTable)) || (this.suppressAdvertiseSequence && SequenceTable.AdvtExecuteSequence == actionRow.SequenceTable) || (this.suppressUISequence && (SequenceTable.AdminUISequence == actionRow.SequenceTable || SequenceTable.InstallUISequence == actionRow.SequenceTable))) { continue; } // get the table definition for the action (and ensure the proper table exists for a module) TableDefinition sequenceTableDefinition = null; switch (actionRow.SequenceTable) { case SequenceTable.AdminExecuteSequence: if (OutputType.Module == this.activeOutput.Type) { this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]); sequenceTableDefinition = this.tableDefinitions["ModuleAdminExecuteSequence"]; } else { sequenceTableDefinition = this.tableDefinitions["AdminExecuteSequence"]; } break; case SequenceTable.AdminUISequence: if (OutputType.Module == this.activeOutput.Type) { this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]); sequenceTableDefinition = this.tableDefinitions["ModuleAdminUISequence"]; } else { sequenceTableDefinition = this.tableDefinitions["AdminUISequence"]; } break; case SequenceTable.AdvtExecuteSequence: if (OutputType.Module == this.activeOutput.Type) { this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]); sequenceTableDefinition = this.tableDefinitions["ModuleAdvtExecuteSequence"]; } else { sequenceTableDefinition = this.tableDefinitions["AdvtExecuteSequence"]; } break; case SequenceTable.InstallExecuteSequence: if (OutputType.Module == this.activeOutput.Type) { this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]); sequenceTableDefinition = this.tableDefinitions["ModuleInstallExecuteSequence"]; } else { sequenceTableDefinition = this.tableDefinitions["InstallExecuteSequence"]; } break; case SequenceTable.InstallUISequence: if (OutputType.Module == this.activeOutput.Type) { this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]); sequenceTableDefinition = this.tableDefinitions["ModuleInstallUISequence"]; } else { sequenceTableDefinition = this.tableDefinitions["InstallUISequence"]; } break; } // create the action sequence row in the output Table sequenceTable = this.activeOutput.EnsureTable(sequenceTableDefinition); Row row = sequenceTable.CreateRow(actionRow.SourceLineNumbers); if (this.sectionIdOnRows) { row.SectionId = actionRow.SectionId; } if (OutputType.Module == this.activeOutput.Type) { row[0] = actionRow.Action; if (0 != actionRow.Sequence) { row[1] = actionRow.Sequence; } else { bool after = (null == actionRow.Before); row[2] = after ? actionRow.After : actionRow.Before; row[3] = after ? 1 : 0; } row[4] = actionRow.Condition; } else { row[0] = actionRow.Action; row[1] = actionRow.Condition; row[2] = actionRow.Sequence; } } }