Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
 /// <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();
 }
Beispiel #3
0
        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;
        }
Beispiel #4
0
        /// <summary>
        /// Clone the RowCollection.
        /// </summary>
        /// <returns>The cloned RowCollection.</returns>
        public RowCollection Clone()
        {
            RowCollection rowCollection = new RowCollection();

            rowCollection.collection.AddRange(this.collection);

            return rowCollection;
        }
Beispiel #5
0
 /// <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);
 }
Beispiel #6
0
        /// <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;
                }
            }
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        /// <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);
            }
        }
Beispiel #9
0
        /// <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;
                    }
                }
            }
        }
Beispiel #10
0
 /// <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);
             }
         }
     }
 }
Beispiel #11
0
        /// <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);
            }
        }
Beispiel #12
0
 /// <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);
 }
Beispiel #13
0
 /// <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();
 }
Beispiel #14
0
        /// <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;
        }
Beispiel #15
0
        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);
        }
Beispiel #16
0
        /// <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);
        }