/// <summary> /// Links an array of intermediates into an output. /// </summary> /// <param name="intermediates">Array of intermediates to link together.</param> /// <returns>Output object from the linking.</returns> public Output Link(Intermediate[] intermediates) { Output output = null; try { SymbolCollection allSymbols; Section entrySection; bool containsModuleSubstitution = false; bool containsModuleConfiguration = false; StringCollection referencedSymbols = new StringCollection(); ArrayList unresolvedReferences = new ArrayList(); ConnectToFeatureCollection componentGroupsToFeatures = new ConnectToFeatureCollection(); ConnectToModuleCollection componentGroupsToModules = new ConnectToModuleCollection(); ComplexReferenceCollection componentsToComponentGroupsComplexReferences = new ComplexReferenceCollection(); ConnectToFeatureCollection componentsToFeatures = new ConnectToFeatureCollection(); ConnectToFeatureCollection featuresToFeatures = new ConnectToFeatureCollection(); this.activeOutput = null; this.foundError = false; SortedList adminProperties = new SortedList(); SortedList secureProperties = new SortedList(); SortedList hiddenProperties = new SortedList(); ActionTable requiredActions = new ActionTable(); RowCollection suppressActionRows = new RowCollection(); TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection(); RowCollection customRows = new RowCollection(); foreach (SchemaExtension extension in this.extensions.Values) { extension.Messages = this.extensionMessages; } // first find the entry section and create the symbols hash for all // the sections in all the intermediates Common.FindEntrySectionAndLoadSymbols(intermediates, this.allowIdenticalRows, this, out entrySection, out allSymbols); // should have found an entry section by now if (null == entrySection) { this.OnMessage(WixErrors.MissingEntrySection()); return null; } // add the standard action symbols to the entry section's symbol table this.LoadStandardActionSymbols(allSymbols, entrySection, this.standardActions); // now that we know where we're starting from, create the output object output = new Output(entrySection); // Note: this entry section will get added to the output section collection later if (null != this.localizer && -1 != this.localizer.Codepage) { output.Codepage = this.localizer.Codepage; } this.activeOutput = output; // resolve the symbol references to find the set of sections we // care about then resolve complex references in those sections Common.ResolveReferences(output.Type, output.Sections, output.EntrySection, allSymbols, referencedSymbols, unresolvedReferences, this); this.ProcessComplexReferences(output, output.Sections, referencedSymbols, componentsToComponentGroupsComplexReferences, componentGroupsToFeatures, componentGroupsToModules, componentsToFeatures, featuresToFeatures); for (int i = 0; i < unresolvedReferences.Count; ++i) { Common.ReferenceSection referenceSection = (Common.ReferenceSection)unresolvedReferences[i]; if (this.allowUnresolvedReferences) { this.OnMessage(WixWarnings.UnresolvedReferenceWarning(SourceLineNumberCollection.FromFileName(referenceSection.section.Intermediate.SourcePath), referenceSection.section.Type.ToString(), referenceSection.section.Id, referenceSection.reference.SymbolicName)); } else { this.OnMessage(WixErrors.UnresolvedReference(SourceLineNumberCollection.FromFileName(referenceSection.section.Intermediate.SourcePath), referenceSection.section.Type.ToString(), referenceSection.section.Id, referenceSection.reference.SymbolicName)); } } if (this.foundError) { return null; } this.ResolveComponentGroups(output, referencedSymbols, componentsToComponentGroupsComplexReferences, componentGroupsToFeatures, componentGroupsToModules, componentsToFeatures); this.FindOrphanedSymbols(referencedSymbols); // resolve the feature backlink for each section then update the feature to feature connects this.ResolveFeatureBacklinks(output, componentsToFeatures, allSymbols, referencedSymbols, unresolvedReferences); this.ResolveFeatureToFeatureConnects(featuresToFeatures, allSymbols, referencedSymbols, unresolvedReferences); // create a Hashtable of all the suppressed sequence types Hashtable suppressedSequenceTypes = new Hashtable(); // create a Hashtable of all the suppressed standard actions Hashtable suppressedStandardActions = new Hashtable(); if (this.suppressAdminSequence) { suppressedSequenceTypes[SequenceType.adminExecute] = null; suppressedSequenceTypes[SequenceType.adminUI] = null; } if (this.suppressAdvertiseSequence) { suppressedSequenceTypes[SequenceType.advertiseExecute] = null; } if (this.suppressUISequence) { suppressedSequenceTypes[SequenceType.adminUI] = null; suppressedSequenceTypes[SequenceType.installUI] = null; } // start generating OutputTables and OutputRows for all the sections in the output RowCollection ensureTableRows = new RowCollection(); foreach (Section section in this.activeOutput.Sections) { // add this sections list of identifiers to ignore modularization this.activeOutput.IgnoreModularizations.Add(section.IgnoreModularizations); foreach (Table table in section.Tables) { bool copyRows = !table.Definition.IsUnreal; // by default, copy rows if the table is not unreal // handle special tables switch (table.Name) { case "Actions": foreach (Row row in table.Rows) { SequenceType sequenceType; string seqType = (string)row[0]; string id = (string)row[1]; int sequence = null == row[3] ? 0 : Convert.ToInt32(row[3]); bool suppress = 1 == Convert.ToInt32(row[6]); switch (seqType) { case "AdminUISequence": sequenceType = SequenceType.adminUI; break; case "AdminExecuteSequence": sequenceType = SequenceType.adminExecute; break; case "AdvertiseExecuteSequence": sequenceType = SequenceType.advertiseExecute; break; case "InstallExecuteSequence": sequenceType = SequenceType.installExecute; break; case "InstallUISequence": sequenceType = SequenceType.installUI; break; default: throw new WixInvalidSequenceTypeException(null, seqType); } if (suppressedSequenceTypes.Contains(sequenceType)) { this.OnMessage(WixWarnings.SuppressAction(id, Action.SequenceTypeToString(sequenceType))); continue; } // create a SuppressAction row to allow suppressing the action from a merge module if (suppress) { Row suppressActionRow = new Row(row.SourceLineNumbers, this.tableDefinitions["SuppressAction"]); if ("AdvertiseExecuteSequence" == (string)row[0]) { suppressActionRow[0] = "AdvtExecuteSequence"; } else { suppressActionRow[0] = row[0]; } suppressActionRow[1] = row[1]; suppressActionRows.Add(suppressActionRow); } Action action = this.standardActions[sequenceType, id]; string beforeAction = (string)row[4]; string afterAction = (string)row[5]; // if this is not a standard action or there is a before or after action specified if (null == action || null != beforeAction || null != afterAction) { action = new Action(sequenceType, id, (string)row[2], sequence, beforeAction, afterAction); requiredActions.Add(action, true); // add the action and overwrite even if it already exists since this is a customization // if the parent action is a standard action add it to the required list string parentActionName = null != beforeAction ? beforeAction : afterAction; Action parentAction = this.standardActions[sequenceType, parentActionName]; if (null != parentAction) { requiredActions.Add(parentAction); } } else if (!suppress) // must have a standard action that is being overriden (when not suppressed) { action.Condition = (string)row[2]; if (0 != sequence) // if the user specified a sequence number, override the default { action.SequenceNumber = sequence; } requiredActions.Add(action, true); // ensure this action is in the required list } // action was suppressed by user if (suppress && null != action) { suppressedStandardActions[String.Concat(action.SequenceType.ToString(), id)] = action; } } break; case "AppSearch": Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Signature"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "AppSearch"]); break; case "Binary": case "Icon": case "MsiDigitalCertificate": foreach (Row row in table.Rows) { ImportStreamType importStreamType = ImportStreamType.Unknown; switch (table.Name) { case "Binary": importStreamType = ImportStreamType.Binary; break; case "Icon": importStreamType = ImportStreamType.Icon; break; case "MsiDigitalCertificate": importStreamType = ImportStreamType.DigitalCertificate; break; } ImportStream importStream = new ImportStream(importStreamType, row[0].ToString(), row[1].ToString()); if (this.activeOutput.ImportStreams.Contains(importStream.Name)) { this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, String.Format("{0} element with Id='{1}' is defined multiple times.", table.Name, row.Symbol.Name))); } this.activeOutput.ImportStreams.Add(importStream); } Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions[table.Name]); copyRows = false; break; case "BindImage": requiredActions.Add(this.standardActions[SequenceType.installExecute, "BindImage"]); break; case "CCPSearch": requiredActions.Add(this.standardActions[SequenceType.installExecute, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "CCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RMCCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "CCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "RMCCPSearch"]); break; case "Class": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterClassInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterClassInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterClassInfo"]); break; case "Complus": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterComPlus"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterComPlus"]); break; case "CreateFolder": requiredActions.Add(this.standardActions[SequenceType.installExecute, "CreateFolders"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFolders"]); break; case "CustomAction": if (OutputType.Module == this.activeOutput.Type) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); } break; case "CustomTables": foreach (Row row in table.Rows) { TableDefinition customTable = new TableDefinition((string)row[0], false); if (null == row[4]) { this.OnMessage(WixErrors.ExpectedAttribute(row.SourceLineNumbers, "CustomTable/Column", "PrimaryKey")); } string[] columnNames = row[2].ToString().Split(tabCharacter); string[] columnTypes = row[3].ToString().Split(tabCharacter); string[] primaryKeys = row[4].ToString().Split(tabCharacter); string[] minValues = row[5] == null ? null : row[5].ToString().Split(tabCharacter); string[] maxValues = row[6] == null ? null : row[6].ToString().Split(tabCharacter); string[] keyTables = row[7] == null ? null : row[7].ToString().Split(tabCharacter); string[] keyColumns = row[8] == null ? null : row[8].ToString().Split(tabCharacter); string[] categories = row[9] == null ? null : row[9].ToString().Split(tabCharacter); string[] sets = row[10] == null ? null : row[10].ToString().Split(tabCharacter); string[] descriptions = row[11] == null ? null : row[11].ToString().Split(tabCharacter); string[] modularizations = row[12] == null ? null : row[12].ToString().Split(tabCharacter); int currentPrimaryKey = 0; for (int i = 0; i < columnNames.Length; ++i) { string name = columnNames[i]; ColumnType type = ColumnType.Unknown; switch (columnTypes[i].Substring(0, 1).ToLower(CultureInfo.InvariantCulture)) { case "s": type = ColumnType.String; break; case "l": type = ColumnType.Localized; break; case "i": type = ColumnType.Number; break; case "g": type = ColumnType.Object; break; default: throw new ApplicationException(String.Format("Unknown custom table column type: {0}", columnTypes[i])); } bool nullable = columnTypes[i].Substring(0, 1) == columnTypes[i].Substring(0, 1).ToUpper(CultureInfo.InvariantCulture); int length = Convert.ToInt32(columnTypes[i].Substring(1)); bool primaryKey = false; if (currentPrimaryKey < primaryKeys.Length && primaryKeys[currentPrimaryKey] == columnNames[i]) { primaryKey = true; currentPrimaryKey++; } bool minValSet = null != minValues && null != minValues[i] && 0 < minValues[i].Length; int minValue = 0; if (minValSet) { minValue = Convert.ToInt32(minValues[i]); } bool maxValSet = null != maxValues && null != maxValues[i] && 0 < maxValues[i].Length; int maxValue = 0; if (maxValSet) { maxValue = Convert.ToInt32(maxValues[i]); } bool keyColumnSet = null != keyColumns && null != keyColumns[i] && 0 < keyColumns[i].Length; int keyColumn = 0; if (keyColumnSet) { keyColumn = Convert.ToInt32(keyColumns[i]); } ColumnCategory category = ColumnCategory.Unknown; if (null != categories && null != categories[i] && 0 < categories[i].Length) { switch (categories[i]) { case "Text": category = ColumnCategory.Text; break; case "UpperCase": category = ColumnCategory.UpperCase; break; case "LowerCase": category = ColumnCategory.LowerCase; break; case "Integer": category = ColumnCategory.Integer; break; case "DoubleInteger": category = ColumnCategory.DoubleInteger; break; case "TimeDate": category = ColumnCategory.TimeDate; break; case "Identifier": category = ColumnCategory.Identifier; break; case "Property": category = ColumnCategory.Property; break; case "Filename": category = ColumnCategory.Filename; break; case "WildCardFilename": category = ColumnCategory.WildCardFilename; break; case "Path": category = ColumnCategory.Path; break; case "Paths": category = ColumnCategory.Paths; break; case "AnyPath": category = ColumnCategory.AnyPath; break; case "DefaultDir": category = ColumnCategory.DefaultDir; break; case "RegPath": category = ColumnCategory.RegPath; break; case "Formatted": category = ColumnCategory.Formatted; break; case "Template": category = ColumnCategory.Template; break; case "Condition": category = ColumnCategory.Condition; break; case "Guid": category = ColumnCategory.Guid; break; case "Version": category = ColumnCategory.Version; break; case "Language": category = ColumnCategory.Language; break; case "Binary": category = ColumnCategory.Binary; break; case "CustomSource": category = ColumnCategory.CustomSource; break; case "Cabinet": category = ColumnCategory.Cabinet; break; case "Shortcut": category = ColumnCategory.Shortcut; break; default: break; } } string keyTable = keyTables != null ? keyTables[i] : null; string setValue = sets != null ? sets[i] : null; string description = descriptions != null ? descriptions[i] : null; string modString = modularizations != null ? modularizations[i] : null; ColumnModularizeType modularization = ColumnModularizeType.None; if (modString != null) { switch (modString) { case "None": modularization = ColumnModularizeType.None; break; case "Column": modularization = ColumnModularizeType.Column; break; case "Property": modularization = ColumnModularizeType.Property; break; case "Condition": modularization = ColumnModularizeType.Condition; break; case "CompanionFile": modularization = ColumnModularizeType.CompanionFile; break; case "SemicolonDelimited": modularization = ColumnModularizeType.SemicolonDelimited; break; } } ColumnDefinition columnDefinition = new ColumnDefinition(name, type, length, primaryKey, false, nullable, modularization, false, ColumnType.Localized == type, minValSet, minValue, maxValSet, maxValue, keyTable, keyColumnSet, keyColumn, category, setValue, description, true, true); customTable.Columns.Add(columnDefinition); } customTableDefinitions.Add(customTable); } copyRows = false; // we've created table definitions from these rows, no need to process them any longer break; case "RowData": foreach (Row row in table.Rows) { customRows.Add(row); } copyRows = false; break; case "Dialog": Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ListBox"]); break; case "Directory": foreach (Row row in table.Rows) { if (OutputType.Module == this.activeOutput.Type && Common.IsStandardDirectory(row[0].ToString())) { // if the directory table contains references to standard windows folders // mergemod.dll will add customactions to set the MSM directory to // the same directory as the standard windows folder and will add references to // custom action to all the standard sequence tables. A problem will occur // if the MSI does not have these tables as mergemod.dll does not add these // tables to the MSI if absent. This code adds the tables in case mergemod.dll // needs them. Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["CustomAction"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); break; // no need to look here any more, we already found all that we needed to } } break; case "DuplicateFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "DuplicateFiles"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveDuplicateFiles"]); break; case "EnsureTables": foreach (Row row in table.Rows) { ensureTableRows.Add(row); } break; case "Environment": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteEnvironmentStrings"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveEnvironmentStrings"]); break; case "Extension": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterExtensionInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterExtensionInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterExtensionInfo"]); break; case "File": foreach (FileRow row in table.Rows) { // DiskId is not valid when creating a module, so set it to // 0 for all files to ensure proper sorting in the binder if (OutputType.Module == this.activeOutput.Type) { row.DiskId = 0; } // if we have an assembly, insert the MsiAssembly row and assembly actions if (FileAssemblyType.NotAnAssembly != row.AssemblyType) { string feature; if (OutputType.Module == output.Type) { feature = Guid.Empty.ToString("B"); } else { ConnectToFeature connect = componentsToFeatures[row.Component]; if (null == connect) { throw new WixMissingFeatureException(row.SourceLineNumbers, new FeatureBacklink(row.Component, FeatureBacklinkType.Assembly, row.File)); } feature = connect.PrimaryFeature; } OutputTable assemblyOutputTable = Common.EnsureOutputTable(output, this.tableDefinitions["MsiAssembly"]); Row assemblyRow = new Row(assemblyOutputTable.TableDefinition); assemblyRow[0] = row.Component; assemblyRow[1] = feature; assemblyRow[2] = row.AssemblyManifest; assemblyRow[3] = row.AssemblyApplication; assemblyRow[4] = Convert.ToInt32(row.AssemblyType); assemblyOutputTable.OutputRows.Add(new OutputRow(assemblyRow, this.sectionIdOnTuples ? section.Id : null)); requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiUnpublishAssemblies"]); } if (null == row.Source) // source to the file must be provided { this.OnMessage(WixErrors.FileSourceRequired(row.SourceLineNumbers, row.File)); } this.activeOutput.FileMediaInformationCollection.Add(new FileMediaInformation(row)); } requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallFiles"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFiles"]); break; case "Font": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterFonts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterFonts"]); break; case "IniFile": case "RemoveIniFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteIniValues"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveIniValues"]); break; case "IsolatedComponent": requiredActions.Add(this.standardActions[SequenceType.installExecute, "IsolateComponents"]); break; case "LaunchCondition": requiredActions.Add(this.standardActions[SequenceType.installExecute, "LaunchConditions"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "LaunchConditions"]); break; case "Media": foreach (MediaRow row in table.Rows) { this.activeOutput.MediaRows.Add(row); } copyRows = false; break; case "Merge": // just copy the rows to the output copyRows = true; break; case "MIME": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterMIMEInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterMIMEInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterMIMEInfo"]); break; case "ModuleSignature": if (OutputType.Module == this.activeOutput.Type) { foreach (Row row in table.Rows) { if (null != this.activeOutput.ModularizationGuid) { throw new ArgumentOutOfRangeException("Unexpected number of rows found in table", "ModuleSignature"); } this.activeOutput.ModularizationGuid = row[3].ToString(); } } break; case "ModuleSubstitution": containsModuleSubstitution = true; break; case "ModuleConfiguration": containsModuleConfiguration = true; break; case "MoveFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "MoveFiles"]); break; case "MsiAssembly": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiUnpublishAssemblies"]); break; case "ODBCDataSource": case "ODBCTranslator": case "ODBCDriver": requiredActions.Add(this.standardActions[SequenceType.installExecute, "SetODBCFolders"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallODBC"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveODBC"]); break; case "ProgId": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterProgIdInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterProgIdInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterProgIdInfo"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Extension"]); // Extension table is required with a ProgId table break; case "Property": foreach (PropertyRow row in table.Rows) { // if there is no value in the property, then it must be virtual if (null == row.Value || 0 == row.Value.Length) { row.IsUnreal = true; } if (row.Admin) { adminProperties[row.Id] = null; } if (row.Secure) { secureProperties[row.Id] = null; } if (row.Hidden) { hiddenProperties[row.Id] = null; } } break; case "PublishComponent": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "PublishComponents"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "PublishComponents"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnpublishComponents"]); break; case "Registry": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteRegistryValues"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveRegistryValues"]); break; case "RemoveFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFiles"]); break; case "SelfReg": requiredActions.Add(this.standardActions[SequenceType.installExecute, "SelfRegModules"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "SelfUnregModules"]); break; case "ServiceControl": requiredActions.Add(this.standardActions[SequenceType.installExecute, "StartServices"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "StopServices"]); break; case "ServiceInstall": requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallServices"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "DeleteServices"]); break; case "Shortcut": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "CreateShortcuts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "CreateShortcuts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveShortcuts"]); break; case "TypeLib": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterTypeLibraries"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterTypeLibraries"]); break; case "Upgrade": { requiredActions.Add(this.standardActions[SequenceType.installExecute, "FindRelatedProducts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MigrateFeatureStates"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "FindRelatedProducts"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "MigrateFeatureStates"]); foreach (UpgradeRow row in table.Rows) { // this should never happen because candle will make sure that all UpgradeVersion(s) have an ActionProperty...but still don't let it slide if (null == row.ActionProperty) { this.OnMessage(WixErrors.ExpectedAttribute(row.SourceLineNumbers, "UpgradeVersion", "ActionProperty")); } secureProperties[row.ActionProperty] = null; } break; } case "_SummaryInformation": // if we are processing a product, reach into the summary // information and pull out the bits that say if the layout // image is supposed to have long file names and is compressed if (OutputType.Product == output.Type) { foreach (Row row in table.Rows) { // we're looking for the "Word Count" property which happens to // be number 15 (and I thought the answer to the universe was 42, heh). if ("15" == row[0].ToString()) { output.LongFileNames = (0 == (Convert.ToInt32(row[1]) & 1)); output.Compressed = (2 == (Convert.ToInt32(row[1]) & 2)); break; // we're done looking for what we came looking for } } } break; } if (copyRows) { OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions[table.Name]); this.CopyTableRowsToOutputTable(table, outputTable, section.Id); } } } if (0 < ensureTableRows.Count) { foreach (Row row in ensureTableRows) { string tableId = (string)row[0]; TableDefinition tableDef = null; try { tableDef = this.tableDefinitions[tableId]; } catch (WixMissingTableDefinitionException) { tableDef = customTableDefinitions[tableId]; } Common.EnsureOutputTable(this.activeOutput, tableDef); } } // copy all the suppress action rows to the output to suppress actions from merge modules if (0 < suppressActionRows.Count) { OutputTable suppressActionOutputTable = new OutputTable(this.tableDefinitions["SuppressAction"]); this.activeOutput.OutputTables.Add(suppressActionOutputTable); foreach (Row suppressActionRow in suppressActionRows) { suppressActionOutputTable.OutputRows.Add(new OutputRow(suppressActionRow)); } } foreach (Action suppressedAction in suppressedStandardActions.Values) { if (requiredActions.Contains(suppressedAction)) { // We thought they really ought to have a standard action // that they wanted to suppress, so warn them and remove it this.OnMessage(WixWarnings.SuppressAction(suppressedAction.Id, Action.SequenceTypeToString(suppressedAction.SequenceType))); requiredActions.Remove(suppressedAction); } } // check for missing table and add them or display an error as appropriate switch (this.activeOutput.Type) { case OutputType.Module: Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Component"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Directory"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["FeatureComponents"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["File"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleComponents"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleSignature"]); break; case OutputType.PatchCreation: OutputTable imageFamiliesTable = this.activeOutput.OutputTables["ImageFamilies"]; OutputTable targetImagesTable = this.activeOutput.OutputTables["TargetImages"]; OutputTable upgradedImagesTable = this.activeOutput.OutputTables["UpgradedImages"]; if (null == imageFamiliesTable || 1 > imageFamiliesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("ImageFamilies")); } if (null == targetImagesTable || 1 > targetImagesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("TargetImages")); } if (null == upgradedImagesTable || 1 > upgradedImagesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("UpgradedImages")); } Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Properties"]); break; case OutputType.Product: // AdminExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallFiles"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallAdminPackage"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallFinalize"]); // AdminUISequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "ExecuteAction"]); // AdvtExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "PublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "PublishProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallFinalize"]); // InstallExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "ValidateProductID"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "ProcessComponents"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "UnpublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "RegisterUser"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "RegisterProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "PublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "PublishProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallFinalize"]); // InstallUISequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "ValidateProductID"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "ExecuteAction"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["File"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Media"]); break; } // check for illegal tables foreach (OutputTable table in this.activeOutput.OutputTables) { switch (this.activeOutput.Type) { case OutputType.Module: if ("BBControl" == table.Name || "Billboard" == table.Name || "CCPSearch" == table.Name || "Feature" == table.Name || "LaunchCondition" == table.Name || "Media" == table.Name || "Merge" == table.Name || "Patch" == table.Name || "Upgrade" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixErrors.UnexpectedTableInMergeModule(outputRow.Row.SourceLineNumbers, table.Name)); } } else if ("Error" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixWarnings.DangerousTableInMergeModule(outputRow.Row.SourceLineNumbers, table.Name)); } } break; case OutputType.PatchCreation: if ("_SummaryInformation" != table.Name && "ExternalFiles" != table.Name && "FamilyFileRanges" != table.Name && "ImageFamilies" != table.Name && "PatchMetadata" != table.Name && "PatchSequence" != table.Name && "Properties" != table.Name && "TargetFiles_OptionalData" != table.Name && "TargetImages" != table.Name && "UpgradedFiles_OptionalData" != table.Name && "UpgradedFilesToIgnore" != table.Name && "UpgradedImages" != table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixErrors.UnexpectedTableInPatchCreationPackage(outputRow.Row.SourceLineNumbers, table.Name)); } } break; case OutputType.Product: if ("ModuleAdminExecuteSequence" == table.Name || "ModuleAdminUISequence" == table.Name || "ModuleAdvtExecuteSequence" == table.Name || "ModuleAdvtUISequence" == table.Name || "ModuleComponents" == table.Name || "ModuleConfiguration" == table.Name || "ModuleDependency" == table.Name || "ModuleExclusion" == table.Name || "ModuleIgnoreTable" == table.Name || "ModuleInstallExecuteSequence" == table.Name || "ModuleInstallUISequence" == table.Name || "ModuleSignature" == table.Name || "ModuleSubstitution" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixWarnings.UnexpectedTableInProduct(outputRow.Row.SourceLineNumbers, table.Name)); } } break; } } // add the custom row data foreach (Row row in customRows) { TableDefinition customTable = (TableDefinition)customTableDefinitions[row[0].ToString()]; string[] data = row[2].ToString().Split(tabCharacter); Row customRow = new Row(customTable); for (int i = 0; i < data.Length; ++i) { string[] item = data[i].Split(colonCharacter, 2); customRow.SetData(item[0], item[1]); } bool dataErrors = false; for (int i = 0; i < customTable.Columns.Count; ++i) { if (!customTable.Columns[i].IsNullable && customRow.IsColumnEmpty(i)) { this.OnMessage(WixErrors.NoDataForColumn(row.SourceLineNumbers, customTable.Columns[i].Name, customTable.Name)); dataErrors = true; } } if (!dataErrors) { OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, customTable); outputTable.OutputRows.Add(new OutputRow(customRow)); } } // update the special properties if (0 < adminProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "AdminProperties"; newRow[1] = GetPropertyListString(adminProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (0 < secureProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "SecureCustomProperties"; newRow[1] = GetPropertyListString(secureProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (0 < hiddenProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "MsiHiddenProperties"; newRow[1] = GetPropertyListString(hiddenProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (containsModuleSubstitution) { Row newRow = new Row(this.tableDefinitions["ModuleIgnoreTable"]); newRow[0] = "ModuleSubstitution"; OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleIgnoreTable"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (containsModuleConfiguration) { Row newRow = new Row(this.tableDefinitions["ModuleIgnoreTable"]); newRow[0] = "ModuleConfiguration"; OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleIgnoreTable"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } // process the actions foreach (Action action in requiredActions) { // skip actions in suppressed sequences if (suppressedSequenceTypes.Contains(action.SequenceType)) { continue; } if (OutputType.Product == this.activeOutput.Type) { this.ResolveActionSequence(action, requiredActions); } TableDefinition sequenceTableDef = null; bool module = OutputType.Module == this.activeOutput.Type; switch (action.SequenceType) { case SequenceType.adminExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdminExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["AdminExecuteSequence"]; } break; case SequenceType.adminUI: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdminUISequence"]; } else { sequenceTableDef = this.tableDefinitions["AdminUISequence"]; } break; case SequenceType.advertiseExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdvtExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["AdvtExecuteSequence"]; } break; case SequenceType.installExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleInstallExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["InstallExecuteSequence"]; } break; case SequenceType.installUI: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); sequenceTableDef = this.tableDefinitions["ModuleInstallUISequence"]; } else { sequenceTableDef = this.tableDefinitions["InstallUISequence"]; } break; } Row row = new Row(sequenceTableDef); if (module) { row[0] = action.Id; if (0 != action.SequenceNumber) { row[1] = action.SequenceNumber; } else { bool after = null == action.Before; row[2] = after ? action.After : action.Before; row[3] = after ? 1 : 0; } row[4] = action.Condition; } else // add the row to the sequence table { row[0] = action.Id; row[1] = action.Condition; row[2] = action.SequenceNumber; } OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, sequenceTableDef); outputTable.OutputRows.Add(new OutputRow(row)); } // set the suppressed action sequences if (this.suppressAdminSequence) { this.activeOutput.SuppressAdminSequence = true; } if (this.suppressAdvertiseSequence) { this.activeOutput.SuppressAdvertiseSequence = true; } if (this.suppressUISequence) { this.activeOutput.SuppressUISequence = true; } } finally { this.activeOutput = null; } return (this.foundError ? null : output); }
/// <summary> /// Creates a table in a section. /// </summary> /// <param name="section">Section to add table to.</param> /// <param name="tableDefinition">Definition of the table.</param> public Table(Section section, TableDefinition tableDefinition) { this.section = section; this.tableDefinition = tableDefinition; this.rows = new RowCollection(); }
private RowCollection CompareTables(Output targetOutput, Table targetTable, Table updatedTable, out TableOperation operation) { RowCollection rows = new RowCollection(); operation = TableOperation.None; // dropped tables if (null == updatedTable ^ null == targetTable) { if (null == targetTable) { operation = TableOperation.Add; rows.AddRange(updatedTable.Rows); } else if (null == updatedTable) { operation = TableOperation.Drop; } } else // possibly modified tables { SortedList updatedPrimaryKeys = new SortedList(); SortedList targetPrimaryKeys = new SortedList(); // compare the table definitions if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) { // continue to the next table; may be more mismatches this.OnMessage(WixErrors.DatabaseSchemaMismatch(targetOutput.SourceLineNumbers, targetTable.Name)); } else { this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); // diff the target and updated rows foreach (DictionaryEntry targetPrimaryKeyEntry in targetPrimaryKeys) { string targetPrimaryKey = (string)targetPrimaryKeyEntry.Key; bool keepRow = false; RowOperation rowOperation = RowOperation.None; Row compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value as Row, updatedPrimaryKeys[targetPrimaryKey] as Row, out rowOperation, out keepRow); if (keepRow) { rows.Add(compared); } } // find the inserted rows foreach (DictionaryEntry updatedPrimaryKeyEntry in updatedPrimaryKeys) { string updatedPrimaryKey = (string)updatedPrimaryKeyEntry.Key; if (!targetPrimaryKeys.Contains(updatedPrimaryKey)) { Row updatedRow = (Row)updatedPrimaryKeyEntry.Value; updatedRow.Operation = RowOperation.Add; updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; rows.Add(updatedRow); } } } } return rows; }
/// <summary> /// Clone the RowCollection. /// </summary> /// <returns>The cloned RowCollection.</returns> public RowCollection Clone() { RowCollection rowCollection = new RowCollection(); rowCollection.collection.AddRange(this.collection); return rowCollection; }
/// <summary> /// Adds the rows in the RowCollection to the end of this collection. /// </summary> /// <param name="rowCollection">The RowCollection to add.</param> public void AddRange(RowCollection rowCollection) { this.collection.AddRange(rowCollection); }
/// <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; } } }
public Output Link(SectionCollection sections, ArrayList transforms, OutputType expectedOutputType) { Output output = null; try { SymbolCollection allSymbols; Section entrySection; bool containsModuleSubstitution = false; bool containsModuleConfiguration = false; StringCollection referencedSymbols = new StringCollection(); ArrayList unresolvedReferences = new ArrayList(); ConnectToFeatureCollection componentsToFeatures = new ConnectToFeatureCollection(); ConnectToFeatureCollection featuresToFeatures = new ConnectToFeatureCollection(); ConnectToFeatureCollection modulesToFeatures = new ConnectToFeatureCollection(); this.activeOutput = null; this.encounteredError = false; SortedList adminProperties = new SortedList(); SortedList secureProperties = new SortedList(); SortedList hiddenProperties = new SortedList(); RowCollection actionRows = new RowCollection(); RowCollection suppressActionRows = new RowCollection(); TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection(); RowCollection customRows = new RowCollection(); StringCollection generatedShortFileNameIdentifiers = new StringCollection(); Hashtable generatedShortFileNames = new Hashtable(); Hashtable multipleFeatureComponents = new Hashtable(); Hashtable wixVariables = new Hashtable(); // verify that modularization types match for foreign key relationships foreach (TableDefinition tableDefinition in this.tableDefinitions) { foreach (ColumnDefinition columnDefinition in tableDefinition.Columns) { if (null != columnDefinition.KeyTable && 0 > columnDefinition.KeyTable.IndexOf(';') && columnDefinition.IsKeyColumnSet) { try { TableDefinition keyTableDefinition = this.tableDefinitions[columnDefinition.KeyTable]; if (0 >= columnDefinition.KeyColumn || keyTableDefinition.Columns.Count < columnDefinition.KeyColumn) { this.OnMessage(WixErrors.InvalidKeyColumn(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn)); } else if (keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType != columnDefinition.ModularizeType && ColumnModularizeType.CompanionFile != columnDefinition.ModularizeType) { this.OnMessage(WixErrors.CollidingModularizationTypes(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn, columnDefinition.ModularizeType.ToString(), keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType.ToString())); } } catch (WixMissingTableDefinitionException) { // ignore missing table definitions - this error is caught in other places } } } } // add in the extension sections foreach (WixExtension extension in this.extensions) { Library library = extension.GetLibrary(this.tableDefinitions); if (null != library) { sections.AddRange(library.Sections); } } // first find the entry section and create the symbols hash for all the sections sections.FindEntrySectionAndLoadSymbols(this.allowIdenticalRows, this, expectedOutputType, out entrySection, out allSymbols); // should have found an entry section by now if (null == entrySection) { throw new WixException(WixErrors.MissingEntrySection(expectedOutputType.ToString())); } // add the missing standard action symbols this.LoadStandardActionSymbols(allSymbols); // now that we know where we're starting from, create the output object output = new Output(null); output.EntrySection = entrySection; // Note: this entry section will get added to the Output.Sections collection later if (null != this.localizer && -1 != this.localizer.Codepage) { output.Codepage = this.localizer.Codepage; } this.activeOutput = output; // Resolve the symbol references to find the set of sections we // care about for linking. Of course, we start with the entry // section (that's how it got its name after all). output.Sections.AddRange(output.EntrySection.ResolveReferences(output.Type, allSymbols, referencedSymbols, unresolvedReferences, this)); // Flattening the complex references that participate in groups. this.FlattenSectionsComplexReferences(output.Sections); if (this.encounteredError) { return null; } // The hard part in linking is processing the complex references. this.ProcessComplexReferences(output, output.Sections, referencedSymbols, componentsToFeatures, featuresToFeatures, modulesToFeatures); for (int i = 0; i < unresolvedReferences.Count; ++i) { Section.SimpleReferenceSection referenceSection = (Section.SimpleReferenceSection)unresolvedReferences[i]; if (this.allowUnresolvedReferences) { this.OnMessage(WixWarnings.UnresolvedReferenceWarning(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName)); } else { this.OnMessage(WixErrors.UnresolvedReference(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName)); } } if (this.encounteredError) { return null; } SymbolCollection unreferencedSymbols = output.Sections.GetOrphanedSymbols(referencedSymbols, this); // Display a warning message for Components that were never referenced by a Feature. foreach (Symbol symbol in unreferencedSymbols) { if ("Component" == symbol.Row.Table.Name) { this.OnMessage(WixErrors.OrphanedComponent(symbol.Row.SourceLineNumbers, (string)symbol.Row[0])); } } Dictionary<string, List<Symbol>> duplicatedSymbols = output.Sections.GetDuplicateSymbols(this); // Display a warning message for Components that were never referenced by a Feature. foreach (List<Symbol> duplicatedSymbolList in duplicatedSymbols.Values) { Symbol symbol = duplicatedSymbolList[0]; // Certain tables allow duplicates because they allow overrides. if (symbol.Row.Table.Name != "WixAction" && symbol.Row.Table.Name != "WixVariable") { this.OnMessage(WixErrors.DuplicateSymbol(symbol.Row.SourceLineNumbers, symbol.Name)); for (int i = 1; i < duplicatedSymbolList.Count; i++) { Symbol duplicateSymbol = duplicatedSymbolList[i]; this.OnMessage(WixErrors.DuplicateSymbol2(duplicateSymbol.Row.SourceLineNumbers)); } } } if (this.encounteredError) { return null; } if (null != this.unreferencedSymbolsFile) { sections.GetOrphanedSymbols(referencedSymbols, this).OutputSymbols(this.unreferencedSymbolsFile); } // resolve the feature to feature connects this.ResolveFeatureToFeatureConnects(featuresToFeatures, allSymbols); // start generating OutputTables and OutputRows for all the sections in the output RowCollection ensureTableRows = new RowCollection(); int sectionCount = 0; foreach (Section section in output.Sections) { sectionCount++; string sectionId = section.Id; if (null == sectionId && this.sectionIdOnRows) { sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture); } foreach (Table table in section.Tables) { // By default, copy rows unless we've been asked to drop unreal tables from // the output and it's an unreal table and *not* a UX Manifest table. bool copyRows = true; if (this.dropUnrealTables && table.Definition.IsUnreal && !table.Definition.IsBootstrapperApplicationData) { copyRows = false; } // handle special tables switch (table.Name) { case "AppSearch": this.activeOutput.EnsureTable(this.tableDefinitions["Signature"]); break; case "Class": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 2, 11, componentsToFeatures, multipleFeatureComponents); } break; case "ChainPackage": case "ChainPackageGroup": case "MsiProperty": copyRows = true; break; case "CustomAction": if (OutputType.Module == this.activeOutput.Type) { this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]); } foreach (Row row in table.Rows) { // For script CAs that specify HideTarget we should also hide the CA data property for the action. int bits = Convert.ToInt32(row[1]); if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) && MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript)) { hiddenProperties[Convert.ToString(row[0])] = null; } } break; case "Dialog": this.activeOutput.EnsureTable(this.tableDefinitions["ListBox"]); break; case "Directory": foreach (Row row in table.Rows) { if (OutputType.Module == this.activeOutput.Type) { string directory = row[0].ToString(); if (Util.IsStandardDirectory(directory)) { // if the directory table contains references to standard windows folders // mergemod.dll will add customactions to set the MSM directory to // the same directory as the standard windows folder and will add references to // custom action to all the standard sequence tables. A problem will occur // if the MSI does not have these tables as mergemod.dll does not add these // tables to the MSI if absent. This code adds the tables in case mergemod.dll // needs them. this.activeOutput.EnsureTable(this.tableDefinitions["CustomAction"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]); } else { foreach (string standardDirectory in Util.StandardDirectories.Keys) { if (directory.StartsWith(standardDirectory, StringComparison.Ordinal)) { this.OnMessage(WixWarnings.StandardDirectoryConflictInMergeModule(row.SourceLineNumbers, directory, standardDirectory)); } } } } } break; case "Extension": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 1, 4, componentsToFeatures, multipleFeatureComponents); } break; case "ModuleSubstitution": containsModuleSubstitution = true; break; case "ModuleConfiguration": containsModuleConfiguration = true; break; case "MsiAssembly": if (this.suppressMsiAssemblyTable) { copyRows = false; } else if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 0, 1, componentsToFeatures, multipleFeatureComponents); } break; case "ProgId": // the Extension table is required with a ProgId table this.activeOutput.EnsureTable(this.tableDefinitions["Extension"]); break; case "Property": for (int i = 0; i < table.Rows.Count; i++) { if (null == table.Rows[i][1]) { table.Rows.RemoveAt(i); i--; } } break; case "PublishComponent": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 2, 4, componentsToFeatures, multipleFeatureComponents); } break; case "Shortcut": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 3, 4, componentsToFeatures, multipleFeatureComponents); } break; case "TypeLib": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 2, 6, componentsToFeatures, multipleFeatureComponents); } break; case "Upgrade": foreach (UpgradeRow row in table.Rows) { secureProperties[row.ActionProperty] = null; } break; case "Variable": copyRows = true; break; case "WixAction": if (this.sectionIdOnRows) { foreach (Row row in table.Rows) { row.SectionId = sectionId; } } actionRows.AddRange(table.Rows); break; case "WixBBControl": case "WixControl": copyRows = true; break; case "WixCustomTable": this.LinkCustomTable(table, customTableDefinitions); copyRows = false; // we've created table definitions from these rows, no need to process them any longer break; case "WixCustomRow": foreach (Row row in table.Rows) { row.SectionId = (this.sectionIdOnRows ? sectionId : null); customRows.Add(row); } copyRows = false; break; case "WixEnsureTable": ensureTableRows.AddRange(table.Rows); break; case "WixFile": foreach (Row row in table.Rows) { // DiskId is not valid when creating a module, so set it to // 0 for all files to ensure proper sorting in the binder if (OutputType.Module == this.activeOutput.Type) { row[5] = 0; } // if the short file name was generated, check for collisions if (0x1 == (int)row[9]) { generatedShortFileNameIdentifiers.Add((string)row[0]); } } copyRows = true; break; case "WixFragment": copyRows = true; break; case "WixGroup": copyRows = true; break; case "WixInstanceTransforms": copyRows = true; break; case "WixMedia": copyRows = true; break; case "WixMerge": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 0, 7, modulesToFeatures, null); } copyRows = true; break; case "WixOrdering": copyRows = true; break; case "WixProperty": foreach (WixPropertyRow wixPropertyRow in table.Rows) { if (wixPropertyRow.Admin) { adminProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Hidden) { hiddenProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Secure) { secureProperties[wixPropertyRow.Id] = null; } } break; case "WixSuppressAction": suppressActionRows.AddRange(table.Rows); break; case "WixSuppressModularization": // just copy the rows to the output copyRows = true; break; case "WixVariable": // check for colliding values and collect the wix variable rows foreach (WixVariableRow row in table.Rows) { WixVariableRow collidingRow = (WixVariableRow)wixVariables[row.Id]; if (null == collidingRow || (collidingRow.Overridable && !row.Overridable)) { wixVariables[row.Id] = row; } else if (!row.Overridable || (collidingRow.Overridable && row.Overridable)) { this.OnMessage(WixErrors.WixVariableCollision(row.SourceLineNumbers, row.Id)); } } copyRows = false; break; case "WixPatchRef": case "WixPatchBaseline": case "WixPatchId": copyRows = true; break; } if (copyRows) { Table outputTable = this.activeOutput.EnsureTable(this.tableDefinitions[table.Name]); this.CopyTableRowsToOutputTable(table, outputTable, sectionId); } } } // Verify that there were no duplicate fragment Id's. Table wixFragmentTable = this.activeOutput.Tables["WixFragment"]; Hashtable fragmentIdIndex = new Hashtable(); if (null != wixFragmentTable) { foreach (Row row in wixFragmentTable.Rows) { string fragmentId = row.Fields[0].Data.ToString(); if (!fragmentIdIndex.ContainsKey(fragmentId)) { fragmentIdIndex.Add(fragmentId, row.SourceLineNumbers); } else { this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, fragmentId)); if (null != fragmentIdIndex[fragmentId]) { this.OnMessage(WixErrors.DuplicateSymbol2((SourceLineNumberCollection)fragmentIdIndex[fragmentId])); } } } } // copy the module to feature connections into the output if (0 < modulesToFeatures.Count) { Table wixFeatureModulesTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixFeatureModules"]); foreach (ConnectToFeature connectToFeature in modulesToFeatures) { foreach (string feature in connectToFeature.ConnectFeatures) { Row row = wixFeatureModulesTable.CreateRow(null); row[0] = feature; row[1] = connectToFeature.ChildId; } } } // ensure the creation of tables that need to exist if (0 < ensureTableRows.Count) { foreach (Row row in ensureTableRows) { string tableId = (string)row[0]; TableDefinition tableDef = null; try { tableDef = this.tableDefinitions[tableId]; } catch (WixMissingTableDefinitionException) { tableDef = customTableDefinitions[tableId]; } this.activeOutput.EnsureTable(tableDef); } } // copy all the suppress action rows to the output to suppress actions from merge modules if (0 < suppressActionRows.Count) { Table suppressActionTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixSuppressAction"]); suppressActionTable.Rows.AddRange(suppressActionRows); } // sequence all the actions this.SequenceActions(actionRows, suppressActionRows); // check for missing table and add them or display an error as appropriate switch (this.activeOutput.Type) { case OutputType.Module: this.activeOutput.EnsureTable(this.tableDefinitions["Component"]); this.activeOutput.EnsureTable(this.tableDefinitions["Directory"]); this.activeOutput.EnsureTable(this.tableDefinitions["FeatureComponents"]); this.activeOutput.EnsureTable(this.tableDefinitions["File"]); this.activeOutput.EnsureTable(this.tableDefinitions["ModuleComponents"]); this.activeOutput.EnsureTable(this.tableDefinitions["ModuleSignature"]); break; case OutputType.PatchCreation: Table imageFamiliesTable = this.activeOutput.Tables["ImageFamilies"]; Table targetImagesTable = this.activeOutput.Tables["TargetImages"]; Table upgradedImagesTable = this.activeOutput.Tables["UpgradedImages"]; if (null == imageFamiliesTable || 1 > imageFamiliesTable.Rows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("ImageFamilies")); } if (null == targetImagesTable || 1 > targetImagesTable.Rows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("TargetImages")); } if (null == upgradedImagesTable || 1 > upgradedImagesTable.Rows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("UpgradedImages")); } this.activeOutput.EnsureTable(this.tableDefinitions["Properties"]); break; case OutputType.Product: this.activeOutput.EnsureTable(this.tableDefinitions["File"]); this.activeOutput.EnsureTable(this.tableDefinitions["Media"]); break; } this.CheckForIllegalTables(this.activeOutput); // add the custom row data foreach (Row row in customRows) { TableDefinition customTableDefinition = (TableDefinition)customTableDefinitions[row[0].ToString()]; Table customTable = this.activeOutput.EnsureTable(customTableDefinition); Row customRow = customTable.CreateRow(row.SourceLineNumbers); customRow.SectionId = row.SectionId; string[] data = row[1].ToString().Split(Common.CustomRowFieldSeparator); for (int i = 0; i < data.Length; ++i) { bool foundColumn = false; string[] item = data[i].Split(colonCharacter, 2); for (int j = 0; j < customRow.Fields.Length; ++j) { if (customRow.Fields[j].Column.Name == item[0]) { if (0 < item[1].Length) { if (ColumnType.Number == customRow.Fields[j].Column.Type) { try { customRow.Fields[j].Data = Convert.ToInt32(item[1], CultureInfo.InvariantCulture); } catch (FormatException) { this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1])); } catch (OverflowException) { this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1])); } } else if (ColumnCategory.Identifier == customRow.Fields[j].Column.Category) { if (CompilerCore.IsIdentifier(item[1]) || Common.IsValidBinderVariable(item[1]) || ColumnCategory.Formatted == customRow.Fields[j].Column.Category) { customRow.Fields[j].Data = item[1]; } else { this.OnMessage(WixErrors.IllegalIdentifier(row.SourceLineNumbers, "Data", item[1])); } } else { customRow.Fields[j].Data = item[1]; } } foundColumn = true; break; } } if (!foundColumn) { this.OnMessage(WixErrors.UnexpectedCustomTableColumn(row.SourceLineNumbers, item[0])); } } for (int i = 0; i < customTableDefinition.Columns.Count; ++i) { if (!customTableDefinition.Columns[i].IsNullable && (null == customRow.Fields[i].Data || 0 == customRow.Fields[i].Data.ToString().Length)) { this.OnMessage(WixErrors.NoDataForColumn(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name)); } } } //correct the section Id in FeatureComponents table if (this.sectionIdOnRows) { Hashtable componentSectionIds = new Hashtable(); Table componentTable = output.Tables["Component"]; if (null != componentTable) { foreach (Row componentRow in componentTable.Rows) { componentSectionIds.Add(componentRow.Fields[0].Data.ToString(), componentRow.SectionId); } } Table featureComponentsTable = output.Tables["FeatureComponents"]; if (null != featureComponentsTable) { foreach (Row featureComponentsRow in featureComponentsTable.Rows) { if (componentSectionIds.Contains(featureComponentsRow.Fields[1].Data.ToString())) { featureComponentsRow.SectionId = (string)componentSectionIds[featureComponentsRow.Fields[1].Data.ToString()]; } } } } // update the special properties if (0 < adminProperties.Count) { Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]); Row row = propertyTable.CreateRow(null); row[0] = "AdminProperties"; row[1] = GetPropertyListString(adminProperties); } if (0 < secureProperties.Count) { Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]); Row row = propertyTable.CreateRow(null); row[0] = "SecureCustomProperties"; row[1] = GetPropertyListString(secureProperties); } if (0 < hiddenProperties.Count) { Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]); Row row = propertyTable.CreateRow(null); row[0] = "MsiHiddenProperties"; row[1] = GetPropertyListString(hiddenProperties); } // add the ModuleSubstitution table to the ModuleIgnoreTable if (containsModuleSubstitution) { Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]); Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null); moduleIgnoreTableRow[0] = "ModuleSubstitution"; } // add the ModuleConfiguration table to the ModuleIgnoreTable if (containsModuleConfiguration) { Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]); Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null); moduleIgnoreTableRow[0] = "ModuleConfiguration"; } // index all the file rows FileRowCollection indexedFileRows = new FileRowCollection(); Table fileTable = this.activeOutput.Tables["File"]; if (null != fileTable) { indexedFileRows.AddRange(fileTable.Rows); } // flag all the generated short file name collisions foreach (string fileId in generatedShortFileNameIdentifiers) { FileRow fileRow = indexedFileRows[fileId]; string[] names = fileRow.FileName.Split('|'); string shortFileName = names[0]; // create lists of conflicting generated short file names if (!generatedShortFileNames.Contains(shortFileName)) { generatedShortFileNames.Add(shortFileName, new ArrayList()); } ((ArrayList)generatedShortFileNames[shortFileName]).Add(fileRow); } // check for generated short file name collisions foreach (DictionaryEntry entry in generatedShortFileNames) { string shortFileName = (string)entry.Key; ArrayList fileRows = (ArrayList)entry.Value; if (1 < fileRows.Count) { // sort the rows by DiskId fileRows.Sort(); this.OnMessage(WixWarnings.GeneratedShortFileNameConflict(((FileRow)fileRows[0]).SourceLineNumbers, shortFileName)); for (int i = 1; i < fileRows.Count; i++) { FileRow fileRow = (FileRow)fileRows[i]; if (null != fileRow.SourceLineNumbers) { this.OnMessage(WixWarnings.GeneratedShortFileNameConflict2(fileRow.SourceLineNumbers)); } } } } // copy the wix variable rows to the output after all overriding has been accounted for. if (0 < wixVariables.Count) { Table wixVariableTable = output.EnsureTable(this.tableDefinitions["WixVariable"]); foreach (WixVariableRow row in wixVariables.Values) { wixVariableTable.Rows.Add(row); } } // Bundles have groups of data that must be flattened in a way different from other types. this.FlattenBundleTables(output); if (this.encounteredError) { return null; } this.CheckOutputConsistency(output); // inspect the output InspectorCore inspectorCore = new InspectorCore(this.Message); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectOutput(output); // reset inspectorExtension.Core = null; } if (inspectorCore.EncounteredError) { this.encounteredError = true; } } finally { this.activeOutput = null; } return (this.encounteredError ? null : output); }
/// <summary> /// Adds the rows in the RowCollection to the end of this collection. /// </summary> /// <param name="rowCollection">The RowCollection to add.</param> public void AddRange(RowCollection rowCollection) { if (null != this.hashedCollection && this.hashedCollection.Count == 0) { this.hashedCollection = new Hashtable(rowCollection.Count); } foreach (FileRow fileRow in rowCollection) { this.Add(fileRow); } }
/// <summary> /// Resolve features for columns that have null guid placeholders. /// </summary> /// <param name="rows">Rows to resolve.</param> /// <param name="connectionColumn">Number of the column containing the connection identifier.</param> /// <param name="featureColumn">Number of the column containing the feature.</param> /// <param name="connectToFeatures">Connect to feature complex references.</param> /// <param name="multipleFeatureComponents">Hashtable of known components under multiple features.</param> private void ResolveFeatures(RowCollection rows, int connectionColumn, int featureColumn, ConnectToFeatureCollection connectToFeatures, Hashtable multipleFeatureComponents) { foreach (Row row in rows) { string connectionId = (string)row[connectionColumn]; string featureId = (string)row[featureColumn]; if (emptyGuid == featureId) { ConnectToFeature connection = connectToFeatures[connectionId]; if (null == connection) { // display an error for the component or merge module as approrpriate if (null != multipleFeatureComponents) { this.OnMessage(WixErrors.ComponentExpectedFeature(row.SourceLineNumbers, connectionId, row.Table.Name, row.GetPrimaryKey('/'))); } else { this.OnMessage(WixErrors.MergeModuleExpectedFeature(row.SourceLineNumbers, connectionId)); } } else { // check for unique, implicit, primary feature parents with multiple possible parent features if (this.showPedanticMessages && !connection.IsExplicitPrimaryFeature && 0 < connection.ConnectFeatures.Count) { // display a warning for the component or merge module as approrpriate if (null != multipleFeatureComponents) { if (!multipleFeatureComponents.Contains(connectionId)) { this.OnMessage(WixWarnings.ImplicitComponentPrimaryFeature(connectionId)); // remember this component so only one warning is generated for it multipleFeatureComponents[connectionId] = null; } } else { this.OnMessage(WixWarnings.ImplicitMergeModulePrimaryFeature(connectionId)); } } // set the feature row[featureColumn] = connection.PrimaryFeature; } } } }
/// <summary> /// Get all the actions scheduled before this one in a particular sequence table. /// </summary> /// <param name="sequenceTable">The sequence table.</param> /// <param name="allPreviousActionRows">A RowCollection which will contain all the previous actions.</param> internal void GetAllPreviousActionRows(SequenceTable sequenceTable, RowCollection allPreviousActionRows) { if (null != this.previousActionRows) { foreach (WixActionRow actionRow in this.previousActionRows) { if (sequenceTable == actionRow.SequenceTable) { actionRow.GetAllPreviousActionRows(sequenceTable, allPreviousActionRows); allPreviousActionRows.Add(actionRow); actionRow.GetAllNextActionRows(sequenceTable, allPreviousActionRows); } } } }
/// <summary> /// Adds the rows in the RowCollection to the end of this collection. /// </summary> /// <param name="rowCollection">The RowCollection to add.</param> public void AddRange(RowCollection rowCollection) { if (0 == this.collection.Count) { this.collection = new Hashtable(rowCollection.Count); } foreach (MediaRow mediaRow in rowCollection) { this.collection.Add(mediaRow.DiskId, mediaRow); } }
/// <summary> /// Adds the rows in the RowCollection to the end of this collection. /// </summary> /// <param name="rowCollection">The RowCollection to add.</param> public void AddRange(RowCollection rowCollection) { this.collection.AddRange(rowCollection); }
/// <summary> /// Creates a table in a section. /// </summary> /// <param name="section">Section to add table to.</param> /// <param name="tableDefinition">Definition of the table.</param> public Table(Section section, TableDefinition tableDefinition) { this.section = section; this.tableDefinition = tableDefinition; this.rows = new RowCollection(); }
/// <summary> /// Creates a new empty output object. /// </summary> internal Output() { this.componentsToFeatures = new ConnectToFeatureCollection(); this.modulesToFeatures = new ConnectToFeatureCollection(); this.featuresToFeatures = new ConnectToFeatureCollection(); this.ignoreModularizations = new IgnoreModularizationCollection(); this.outputTables = new OutputTableCollection(); this.importStreams = new ImportStreamCollection(); this.modules = new RowCollection(); this.fileMediaInfoCollection = new FileMediaInformationCollection(); this.mediaRows = new MediaRowCollection(); this.suppressAdminSequence = false; this.suppressAdvertiseSequence = false; this.suppressUISequence = false; }
private RowCollection CompareTables(Output targetOutput, Table targetTable, Table updatedTable, out TableOperation operation) { RowCollection rows = new RowCollection(); operation = TableOperation.None; // dropped tables if (null == updatedTable ^ null == targetTable) { if (null == targetTable) { operation = TableOperation.Add; rows.AddRange(updatedTable.Rows); } else if (null == updatedTable) { operation = TableOperation.Drop; } } else // possibly modified tables { SortedList updatedPrimaryKeys = new SortedList(); SortedList targetPrimaryKeys = new SortedList(); // compare the table definitions if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) { // continue to the next table; may be more mismatches this.OnMessage(WixErrors.DatabaseSchemaMismatch(targetOutput.SourceLineNumbers, targetTable.Name)); } else { this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); // diff the target and updated rows foreach (DictionaryEntry targetPrimaryKeyEntry in targetPrimaryKeys) { string targetPrimaryKey = (string)targetPrimaryKeyEntry.Key; bool keepRow = false; RowOperation rowOperation = RowOperation.None; Row compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value as Row, updatedPrimaryKeys[targetPrimaryKey] as Row, out rowOperation, out keepRow); if (keepRow) { rows.Add(compared); } } // find the inserted rows foreach (DictionaryEntry updatedPrimaryKeyEntry in updatedPrimaryKeys) { string updatedPrimaryKey = (string)updatedPrimaryKeyEntry.Key; if (!targetPrimaryKeys.Contains(updatedPrimaryKey)) { Row updatedRow = (Row)updatedPrimaryKeyEntry.Value; updatedRow.Operation = RowOperation.Add; updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; rows.Add(updatedRow); } } } } return(rows); }
/// <summary> /// Creates a transform by diffing two outputs. /// </summary> /// <param name="targetOutput">The target output.</param> /// <param name="updatedOutput">The updated output.</param> /// <param name="validationFlags"></param> /// <returns>The transform.</returns> public Output Diff(Output targetOutput, Output updatedOutput, TransformFlags validationFlags) { Output transform = new Output(null); transform.Type = OutputType.Transform; transform.Codepage = updatedOutput.Codepage; this.transformSummaryInfo = new SummaryInformationStreams(); // compare the codepages if (targetOutput.Codepage != updatedOutput.Codepage && 0 == (TransformFlags.ErrorChangeCodePage & validationFlags)) { this.OnMessage(WixErrors.OutputCodepageMismatch(targetOutput.SourceLineNumbers, targetOutput.Codepage, updatedOutput.Codepage)); if (null != updatedOutput.SourceLineNumbers) { this.OnMessage(WixErrors.OutputCodepageMismatch2(updatedOutput.SourceLineNumbers)); } } // compare the output types if (targetOutput.Type != updatedOutput.Type) { throw new WixException(WixErrors.OutputTypeMismatch(targetOutput.SourceLineNumbers, targetOutput.Type.ToString(), updatedOutput.Type.ToString())); } // compare the contents of the tables foreach (Table targetTable in targetOutput.Tables) { Table updatedTable = updatedOutput.Tables[targetTable.Name]; TableOperation operation = TableOperation.None; RowCollection rows = this.CompareTables(targetOutput, targetTable, updatedTable, out operation); if (TableOperation.Drop == operation) { Table droppedTable = transform.Tables.EnsureTable(null, targetTable.Definition); droppedTable.Operation = TableOperation.Drop; } else if (TableOperation.None == operation) { Table modified = transform.Tables.EnsureTable(null, updatedTable.Definition); modified.Rows.AddRange(rows); } } // added tables foreach (Table updatedTable in updatedOutput.Tables) { if (null == targetOutput.Tables[updatedTable.Name]) { Table addedTable = transform.Tables.EnsureTable(null, updatedTable.Definition); addedTable.Operation = TableOperation.Add; foreach (Row updatedRow in updatedTable.Rows) { updatedRow.Operation = RowOperation.Add; updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; addedTable.Rows.Add(updatedRow); } } } // set summary information properties if (!this.suppressKeepingSpecialRows) { Table summaryInfoTable = transform.Tables["_SummaryInformation"]; this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags); } // inspect the transform InspectorCore inspectorCore = new InspectorCore(this.Message); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectTransform(transform); // reset inspectorExtension.Core = null; } return(transform); }