/// <summary> /// Called after all output changes occur and right before the output is bound into its final format. /// </summary> public override void BundleFinalize(Output output) { Table tagTable = output.Tables["WixBundleTag"]; if (null != tagTable) { Table table = output.Tables["WixBundle"]; WixBundleRow bundleInfo = (WixBundleRow)table.Rows[0]; string bundleId = bundleInfo.BundleId.ToString("D").ToUpperInvariant(); Version bundleVersion = TagBinder.CreateFourPartVersion(bundleInfo.Version); string upgradeCode = NormalizeGuid(bundleInfo.UpgradeCode); string uniqueId = String.Concat("wix:bundle/", bundleId); string persistentId = String.Concat("wix:bundle.upgrade/", upgradeCode); // Try to collect all the software id tags from all the child packages. IList<SoftwareTag> containedTags = TagBinder.CollectPackageTags(output); foreach (Row tagRow in tagTable.Rows) { string regid = (string)tagRow[1]; string name = (string)tagRow[2]; using (MemoryStream ms = new MemoryStream()) { TagBinder.CreateTagFile(ms, uniqueId, bundleInfo.Name, bundleVersion, regid, bundleInfo.Publisher, persistentId, containedTags); tagRow[5] = Encoding.UTF8.GetString(ms.ToArray()); } } } }
/// <summary> /// Called after all output changes occur and right before the output is bound into its final format. /// </summary> public override void BundleFinalize(Output output) { this.overallRegid = null; // always reset overall regid on initialize. Table tagTable = output.Tables["WixBundleTag"]; if (null != tagTable) { Table table = output.Tables["WixBundle"]; WixBundleRow bundleInfo = (WixBundleRow)table.Rows[0]; Version bundleVersion = TagBinder.CreateFourPartVersion(bundleInfo.Version); // Try to collect all the software id tags from all the child packages. IList<SoftwareTag> allTags = TagBinder.CollectPackageTags(output); foreach (Row tagRow in tagTable.Rows) { string regid = (string)tagRow[1]; string name = (string)tagRow[2]; bool licensed = (null != tagRow[3] && 0 != (int)tagRow[3]); string typeString = (string)tagRow[5]; TagType type = String.IsNullOrEmpty(typeString) ? TagType.Unknown : (TagType)Enum.Parse(typeof(TagType), typeString); IList<SoftwareTag> containedTags = TagBinder.CalculateContainedTagsAndType(allTags, ref type); using (MemoryStream ms = new MemoryStream()) { TagBinder.CreateTagFile(ms, regid, bundleInfo.BundleId.ToString("D").ToUpperInvariant(), bundleInfo.Name, bundleVersion, bundleInfo.Publisher, licensed, type, containedTags); tagRow[4] = Encoding.UTF8.GetString(ms.ToArray()); } } } }
/// <summary> /// Called before database binding occurs. /// </summary> public override void DatabaseInitialize(Output output) { this.overallRegid = null; // always reset overall regid on initialize. // Ensure the tag files are generated to be imported by the MSI. this.CreateProductTagFiles(output); }
public static Intermediate ConvertOutput(Wix3.Output output) #pragma warning restore 1591 { var section = new IntermediateSection(String.Empty, OutputType3ToSectionType4(output.Type), output.Codepage); var wixMediaByDiskId = IndexWixMediaTableByDiskId(output); var componentsById = IndexById <Wix3.Row>(output, "Component"); var bindPathsById = IndexById <Wix3.Row>(output, "BindPath"); var fontsById = IndexById <Wix3.Row>(output, "Font"); var selfRegById = IndexById <Wix3.Row>(output, "SelfReg"); var wixDirectoryById = IndexById <Wix3.Row>(output, "WixDirectory"); var wixFileById = IndexById <Wix3.Row>(output, "WixFile"); foreach (Wix3.Table table in output.Tables) { foreach (Wix3.Row row in table.Rows) { var symbol = GenerateSymbolFromRow(row, wixMediaByDiskId, componentsById, fontsById, bindPathsById, selfRegById, wixFileById, wixDirectoryById); if (symbol != null) { section.Symbols.Add(symbol); } } } return(new Intermediate(String.Empty, new[] { section }, localizationsByCulture: null)); }
/// <summary> /// Constructor for auto media assigner. /// </summary> /// <param name="output">Output</param> /// <param name="core">Binder core.</param> /// <param name="filesCompressed">True if files are compressed by default. </param> public AutoMediaAssigner(Output output, BinderCore core, bool filesCompressed) { this.output = output; this.core = core; this.filesCompressed = filesCompressed; this.cabinetNameTemplate = "Cab{0}.cab"; uncompressedFileRows = new FileRowCollection(); mediaRows = new MediaRowCollection(); cabinets = new Hashtable(); }
/// <summary> /// Called after database variable resolution occurs. /// </summary> public override void DatabaseAfterResolvedFields(Output output) { Table wixBindUpdateFilesTable = output.Tables["WixBindUpdatedFiles"]; // We'll end up re-writing the tag files but this time we may have the ProductCode // now to use as the unique id. List<WixFileRow> updatedFileRows = this.CreateProductTagFiles(output); foreach (WixFileRow updateFileRow in updatedFileRows) { Row row = wixBindUpdateFilesTable.CreateRow(updateFileRow.SourceLineNumbers); row[0] = updateFileRow.File; } }
public override void InspectTransform(Output transform) { Table fileTable = transform.Tables["File"]; if (null != fileTable && 0 < fileTable.Rows.Count) { Row fileRow = fileTable.Rows[0]; this.Core.OnMessage(ValidationWarnings.ExampleWarning(fileRow.SourceLineNumbers)); return; } this.Core.OnMessage(ValidationErrors.ExampleError()); }
private static Dictionary <int, Wix3.WixMediaRow> IndexWixMediaTableByDiskId(Wix3.Output output) { var wixMediaByDiskId = new Dictionary <int, Wix3.WixMediaRow>(); var wixMediaTable = output.Tables["WixMedia"]; if (wixMediaTable != null) { foreach (Wix3.WixMediaRow row in wixMediaTable.Rows) { wixMediaByDiskId.Add(FieldAsInt(row, 0), row); } } return(wixMediaByDiskId); }
/// <summary> /// Instantiate a new substorage. /// </summary> /// <param name="name">The substorage name.</param> /// <param name="data">The substorage data.</param> public SubStorage(string name, Output data) { if (null == name) { throw new ArgumentNullException("name"); } if (null == data) { throw new ArgumentNullException("data"); } this.name = name; this.data = data; }
public PayloadInfoRow(SourceLineNumberCollection sourceLineNumbers, Output output, string id, string name, string sourceFile, bool contentFile, bool suppressSignatureValidation, string downloadUrl, string container, PackagingType packaging) : base(sourceLineNumbers, output.Tables["PayloadInfo"]) { this.Id = id; this.Name = name; this.SourceFile = sourceFile; this.ContentFile = contentFile; this.SuppressSignatureValidation = suppressSignatureValidation; this.DownloadUrl = downloadUrl; this.Container = container; this.Packaging = packaging; this.Resolve(); }
private static Dictionary <string, T> IndexById <T>(Wix3.Output output, string tableName) where T : Wix3.Row { var byId = new Dictionary <string, T>(); var table = output.Tables[tableName]; if (table != null) { foreach (T row in table.Rows) { byId.Add(FieldAsString(row, 0), row); } } return(byId); }
public override void InspectPatch(Output patch) { foreach (SubStorage transform in patch.SubStorages) { // Skip patch transforms. if (transform.Name.StartsWith("#")) { continue; } Table fileTable = transform.Data.Tables["File"]; if (null != fileTable && 0 < fileTable.Rows.Count) { Row fileRow = fileTable.Rows[0]; this.Core.OnMessage(ValidationWarnings.AnotherExampleWarning(fileRow.SourceLineNumbers)); return; } } this.Core.OnMessage(ValidationErrors.ExampleError()); }
/// <summary> /// Determine if a particular table should be decompiled with the current settings. /// </summary> /// <param name="output">The output being decompiled.</param> /// <param name="tableName">The name of a table.</param> /// <returns>true if the table should be decompiled; false otherwise.</returns> private bool DecompilableTable(Output output, string tableName) { switch (tableName) { case "ActionText": case "BBControl": case "Billboard": case "CheckBox": case "Control": case "ControlCondition": case "ControlEvent": case "Dialog": case "Error": case "EventMapping": case "RadioButton": case "TextStyle": case "UIText": return !this.suppressUI; case "ModuleAdminExecuteSequence": case "ModuleAdminUISequence": case "ModuleAdvtExecuteSequence": case "ModuleAdvtUISequence": case "ModuleComponents": case "ModuleConfiguration": case "ModuleDependency": case "ModuleIgnoreTable": case "ModuleInstallExecuteSequence": case "ModuleInstallUISequence": case "ModuleExclusion": case "ModuleSignature": case "ModuleSubstitution": if (OutputType.Module != output.Type) { this.core.OnMessage(WixWarnings.SkippingMergeModuleTable(output.SourceLineNumbers, tableName)); return false; } else { return true; } case "ExternalFiles": case "FamilyFileRanges": case "ImageFamilies": case "PatchMetadata": case "PatchSequence": case "Properties": case "TargetFiles_OptionalData": case "TargetImages": case "UpgradedFiles_OptionalData": case "UpgradedFilesToIgnore": case "UpgradedImages": if (OutputType.PatchCreation != output.Type) { this.core.OnMessage(WixWarnings.SkippingPatchCreationTable(output.SourceLineNumbers, tableName)); return false; } else { return true; } case "MsiPatchHeaders": case "MsiPatchMetadata": case "MsiPatchOldAssemblyName": case "MsiPatchOldAssemblyFile": case "MsiPatchSequence": case "Patch": case "PatchPackage": this.core.OnMessage(WixWarnings.PatchTable(output.SourceLineNumbers, tableName)); return false; case "_SummaryInformation": return true; case "_Validation": case "MsiAssemblyName": case "MsiFileHash": return false; default: // all other tables are allowed in any output except for a patch creation package if (OutputType.PatchCreation == output.Type) { this.core.OnMessage(WixWarnings.IllegalPatchCreationTable(output.SourceLineNumbers, tableName)); return false; } else { return true; } } }
/// <summary> /// Finds the entry section and loads the symbols from an array of intermediates. /// </summary> /// <param name="allowIdenticalRows">Flag specifying whether identical rows are allowed or not.</param> /// <param name="messageHandler">Message handler object to route all errors through.</param> /// <param name="expectedOutputType">Expected entry output type, based on output file extension provided to the linker.</param> /// <param name="entrySection">Located entry section.</param> /// <param name="allSymbols">Collection of symbols loaded.</param> internal void FindEntrySectionAndLoadSymbols( bool allowIdenticalRows, IMessageHandler messageHandler, OutputType expectedOutputType, out Section entrySection, out SymbolCollection allSymbols) { entrySection = null; allSymbols = new SymbolCollection(); string outputExtension = Output.GetExtension(expectedOutputType); SectionType expectedEntrySectionType; try { expectedEntrySectionType = (SectionType)Enum.Parse(typeof(SectionType), expectedOutputType.ToString()); } catch (ArgumentException) { expectedEntrySectionType = SectionType.Unknown; } foreach (Section section in this.collection.Keys) { if (SectionType.Product == section.Type || SectionType.Module == section.Type || SectionType.PatchCreation == section.Type || SectionType.Patch == section.Type || SectionType.Bundle == section.Type) { if (SectionType.Unknown != expectedEntrySectionType && section.Type != expectedEntrySectionType) { messageHandler.OnMessage(WixWarnings.UnexpectedEntrySection(section.SourceLineNumbers, section.Type.ToString(), expectedEntrySectionType.ToString(), outputExtension)); } if (null == entrySection) { entrySection = section; } else { messageHandler.OnMessage(WixErrors.MultipleEntrySections(entrySection.SourceLineNumbers, entrySection.Id, section.Id)); messageHandler.OnMessage(WixErrors.MultipleEntrySections2(section.SourceLineNumbers)); } } foreach (Symbol symbol in section.GetSymbols(messageHandler)) { try { Symbol existingSymbol = allSymbols[symbol.Name]; if (null == existingSymbol) { allSymbols.Add(symbol); } else if (allowIdenticalRows && existingSymbol.Row.IsIdentical(symbol.Row)) { messageHandler.OnMessage(WixWarnings.IdenticalRowWarning(symbol.Row.SourceLineNumbers, existingSymbol.Name)); messageHandler.OnMessage(WixWarnings.IdenticalRowWarning2(existingSymbol.Row.SourceLineNumbers)); } else { allSymbols.AddDuplicate(symbol); } } catch (DuplicateSymbolsException) { // if there is already a duplicate symbol, just // another to the list, don't bother trying to // see if there are any identical symbols allSymbols.AddDuplicate(symbol); } } } }
/// <summary> /// Process the complex references. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="sections">Sections that are referenced during the link process.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="componentsToComponentGroupsComplexReferences">Component to ComponentGroup complex references.</param> /// <param name="componentGroupsToFeatures">ComponentGroups to features complex references.</param> /// <param name="componentGroupsToModules">ComponentGroups to modules complex references.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> /// <param name="featuresToFeatures">Feature to feature complex references.</param> private void ProcessComplexReferences( Output output, SectionCollection sections, StringCollection referencedSymbols, ComplexReferenceCollection componentsToComponentGroupsComplexReferences, ConnectToFeatureCollection componentGroupsToFeatures, ConnectToModuleCollection componentGroupsToModules, ConnectToFeatureCollection componentsToFeatures, ConnectToFeatureCollection featuresToFeatures) { Hashtable componentsToModules = new Hashtable(); foreach (Section section in sections) { foreach (ComplexReference cref in section.ComplexReferences) { ConnectToFeature connection; switch (cref.ParentType) { case ComplexReferenceParentType.ComponentGroup: switch (cref.ChildType) { case ComplexReferenceChildType.Component: componentsToComponentGroupsComplexReferences.Add(cref); break; default: throw new ApplicationException("Unexpected complex reference child type."); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; case ComplexReferenceParentType.Feature: switch (cref.ChildType) { case ComplexReferenceChildType.Component: connection = componentsToFeatures[cref.ChildId]; if (null == connection) { componentsToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = cref.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connection.ConnectFeatures.Add(cref.ParentId); } // add a row to the FeatureComponents table Row row = Common.CreateRowInSection(null, section, this.tableDefinitions["FeatureComponents"]); if (this.sectionIdOnTuples) { row.SectionId = section.Id; } row[0] = cref.ParentId; row[1] = cref.ChildId; // index the component for finding orphaned records string symbolName = String.Concat("Component:", cref.ChildId); if (!referencedSymbols.Contains(symbolName)) { referencedSymbols.Add(symbolName); } break; case ComplexReferenceChildType.ComponentGroup: connection = componentGroupsToFeatures[cref.ChildId]; if (null == connection) { componentGroupsToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); connection.PrimaryFeature = cref.ParentId; connection.IsExplicitPrimaryFeature = true; } else { connection.ConnectFeatures.Add(cref.ParentId); } break; case ComplexReferenceChildType.Feature: connection = featuresToFeatures[cref.ChildId]; if (null != connection) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } featuresToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); break; case ComplexReferenceChildType.Module: connection = output.ModulesToFeatures[cref.ChildId]; if (null == connection) { output.ModulesToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = cref.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connection.ConnectFeatures.Add(cref.ParentId); } break; default: throw new ApplicationException("Unexpected complex reference child type"); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; case ComplexReferenceParentType.Module: switch (cref.ChildType) { case ComplexReferenceChildType.Component: if (componentsToModules.ContainsKey(cref.ChildId)) { this.OnMessage(WixErrors.ComponentReferencedTwice(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildId)); continue; } else { componentsToModules.Add(cref.ChildId, cref); // should always be new // add a row to the ModuleComponents table Row row = Common.CreateRowInSection(null, section, this.tableDefinitions["ModuleComponents"]); if (this.sectionIdOnTuples) { row.SectionId = section.Id; } row[0] = cref.ChildId; row[1] = cref.ParentId; row[2] = cref.ParentLanguage; } // index the component for finding orphaned records string componentSymbolName = String.Concat("Component:", cref.ChildId); if (!referencedSymbols.Contains(componentSymbolName)) { referencedSymbols.Add(componentSymbolName); } break; case ComplexReferenceChildType.ComponentGroup: ConnectToModule moduleConnection = componentGroupsToModules[cref.ChildId]; if (null == moduleConnection) { componentGroupsToModules.Add(new ConnectToModule(cref.ChildId, cref.ParentId, cref.ParentLanguage)); } break; default: throw new ApplicationException("Unexpected complex reference child type"); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; } } } }
public void Load(string patchPath) { this.patch = Output.Load(patchPath, false, false); }
/// <summary> /// Ensure transform is uninstallable. /// </summary> /// <param name="productCode">Product code in transform.</param> /// <param name="transform">Transform generated by torch.</param> /// <param name="tables">Tables to be checked</param> /// <returns>True if the transform is uninstallable</returns> private bool CheckUninstallableTransform(string productCode, Output transform, ArrayList tables) { bool ret = true; foreach (string table in tables) { Table wixTable = transform.Tables[table]; if (null != wixTable) { foreach (Row row in wixTable.Rows) { if (row.Operation == RowOperation.Add) { ret = false; string primaryKey = row.GetPrimaryKey('/'); if (null == primaryKey) { primaryKey = string.Empty; } this.OnMessage(WixErrors.NewRowAddedInTable(row.SourceLineNumbers, productCode, wixTable.Name, primaryKey)); } } } } return ret; }
/// <summary> /// Compare two Outputs /// </summary> /// <param name="targetOutput">The expected output</param> /// <param name="updatedOutput">The actual output</param> /// <param name="tables">The list of tables to compare</param> /// <returns>Any differences found.</returns> private static ArrayList CompareOutput(Output targetOutput, Output updatedOutput, params string[] tables) { ArrayList differences = new ArrayList(); Differ differ = new Differ(); differ.SuppressKeepingSpecialRows = true; Output transform = differ.Diff(targetOutput, updatedOutput); foreach (Table table in transform.Tables) { if (null != tables && -1 == Array.IndexOf(tables, table.Name)) { // Skip this table continue; } switch (table.Operation) { case TableOperation.Add: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table has been added.", table.Name)); break; case TableOperation.Drop: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table has been dropped.", table.Name)); continue; } // index the target rows for better error messages Hashtable targetRows = new Hashtable(); Table targetTable = targetOutput.Tables[table.Name]; if (null != targetTable) { foreach (Row row in targetTable.Rows) { string primaryKey = row.GetPrimaryKey('/'); // only index rows with primary keys since these are the ones that can be modified if (null != primaryKey) { targetRows.Add(primaryKey, row); } } } foreach (Row row in table.Rows) { switch (row.Operation) { case RowOperation.Add: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table, row '{1}' has been added.", table.Name, row.ToString())); break; case RowOperation.Delete: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table, row '{1}' has been deleted.", table.Name, row.ToString())); break; case RowOperation.Modify: if (!Verifier.Ignore(row)) { string primaryKey = row.GetPrimaryKey('/'); Row targetRow = (Row)targetRows[primaryKey]; differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table, row '{1}' has changed to '{2}'.", table.Name, targetRow.ToString(), row.ToString())); } break; default: throw new InvalidOperationException("Unknown diff row."); } } } return differences; }
/// <summary> /// Verifies that a given table exists in the output /// </summary> /// <param name="output">Output object to verify.</param> /// <param name="tableName">Name of the table to verify.</param> /// <param name="wixoutFile">File where output object is stored. Only used to display error message.</param> public static void VerifyTableExists(Output output, string tableName, string wixoutFile) { bool tableExists = CheckTableExists(output, tableName); Assert.True(tableExists, String.Format("Table '{0}' does not exist in output '{1}'. It was expected to exist.", tableName, wixoutFile)); }
private RowCollection CompareTables(Output targetOutput, Table targetTable, Table updatedTable, out TableOperation operation) { RowCollection rows = new RowCollection(); operation = TableOperation.None; // dropped tables if (null == updatedTable ^ null == targetTable) { if (null == targetTable) { operation = TableOperation.Add; rows.AddRange(updatedTable.Rows); } else if (null == updatedTable) { operation = TableOperation.Drop; } } else // possibly modified tables { SortedList updatedPrimaryKeys = new SortedList(); SortedList targetPrimaryKeys = new SortedList(); // compare the table definitions if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) { // continue to the next table; may be more mismatches this.OnMessage(WixErrors.DatabaseSchemaMismatch(targetOutput.SourceLineNumbers, targetTable.Name)); } else { this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); // diff the target and updated rows foreach (DictionaryEntry targetPrimaryKeyEntry in targetPrimaryKeys) { string targetPrimaryKey = (string)targetPrimaryKeyEntry.Key; bool keepRow = false; RowOperation rowOperation = RowOperation.None; Row compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value as Row, updatedPrimaryKeys[targetPrimaryKey] as Row, out rowOperation, out keepRow); if (keepRow) { rows.Add(compared); } } // find the inserted rows foreach (DictionaryEntry updatedPrimaryKeyEntry in updatedPrimaryKeys) { string updatedPrimaryKey = (string)updatedPrimaryKeyEntry.Key; if (!targetPrimaryKeys.Contains(updatedPrimaryKey)) { Row updatedRow = (Row)updatedPrimaryKeyEntry.Value; updatedRow.Operation = RowOperation.Add; updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; rows.Add(updatedRow); } } } } return rows; }
/// <summary> /// Creates a transform by diffing two outputs. /// </summary> /// <param name="targetOutput">The target output.</param> /// <param name="updatedOutput">The updated output.</param> /// <param name="validationFlags"></param> /// <returns>The transform.</returns> public Output Diff(Output targetOutput, Output updatedOutput, TransformFlags validationFlags) { Output transform = new Output(null); transform.Type = OutputType.Transform; transform.Codepage = updatedOutput.Codepage; this.transformSummaryInfo = new SummaryInformationStreams(); // compare the codepages if (targetOutput.Codepage != updatedOutput.Codepage && 0 == (TransformFlags.ErrorChangeCodePage & validationFlags)) { this.OnMessage(WixErrors.OutputCodepageMismatch(targetOutput.SourceLineNumbers, targetOutput.Codepage, updatedOutput.Codepage)); if (null != updatedOutput.SourceLineNumbers) { this.OnMessage(WixErrors.OutputCodepageMismatch2(updatedOutput.SourceLineNumbers)); } } // compare the output types if (targetOutput.Type != updatedOutput.Type) { throw new WixException(WixErrors.OutputTypeMismatch(targetOutput.SourceLineNumbers, targetOutput.Type.ToString(), updatedOutput.Type.ToString())); } // compare the contents of the tables foreach (Table targetTable in targetOutput.Tables) { Table updatedTable = updatedOutput.Tables[targetTable.Name]; TableOperation operation = TableOperation.None; RowCollection rows = this.CompareTables(targetOutput, targetTable, updatedTable, out operation); if (TableOperation.Drop == operation) { Table droppedTable = transform.Tables.EnsureTable(null, targetTable.Definition); droppedTable.Operation = TableOperation.Drop; } else if(TableOperation.None == operation) { Table modified = transform.Tables.EnsureTable(null, updatedTable.Definition); modified.Rows.AddRange(rows); } } // added tables foreach (Table updatedTable in updatedOutput.Tables) { if (null == targetOutput.Tables[updatedTable.Name]) { Table addedTable = transform.Tables.EnsureTable(null, updatedTable.Definition); addedTable.Operation = TableOperation.Add; foreach (Row updatedRow in updatedTable.Rows) { updatedRow.Operation = RowOperation.Add; updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; addedTable.Rows.Add(updatedRow); } } } // set summary information properties if (!this.suppressKeepingSpecialRows) { Table summaryInfoTable = transform.Tables["_SummaryInformation"]; this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags); } // inspect the transform InspectorCore inspectorCore = new InspectorCore(this.Message); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectTransform(transform); // reset inspectorExtension.Core = null; } return transform; }
/// <summary> /// Inspect the patch after filtering contained transforms. /// </summary> /// <param name="transform">The <see cref="Output"/> for the patch.</param> /// <remarks> /// To inspect filtered transforms, enumerate <see cref="Output.SubStorages"/>. /// Transforms where the <see cref="SubStorage.Name"/> begins with "#" are /// called patch transforms and instruct Windows Installer how to apply the /// authored transforms - those that do not begin with "#". The authored /// transforms are the primary transforms you'll typically want to inspect /// and contain your changes to target products. /// </remarks> public virtual void InspectPatch(Output patch) { }
private RowCollection CompareTables(Output targetOutput, Table targetTable, Table updatedTable, out TableOperation operation) { RowCollection rows = new RowCollection(); operation = TableOperation.None; // dropped tables if (null == updatedTable ^ null == targetTable) { if (null == targetTable) { operation = TableOperation.Add; rows.AddRange(updatedTable.Rows); } else if (null == updatedTable) { operation = TableOperation.Drop; } } else // possibly modified tables { SortedList updatedPrimaryKeys = new SortedList(); SortedList targetPrimaryKeys = new SortedList(); // compare the table definitions if (0 != targetTable.Definition.CompareTo(updatedTable.Definition)) { // continue to the next table; may be more mismatches this.OnMessage(WixErrors.DatabaseSchemaMismatch(targetOutput.SourceLineNumbers, targetTable.Name)); } else { this.IndexPrimaryKeys(targetTable, targetPrimaryKeys, updatedTable, updatedPrimaryKeys); // diff the target and updated rows foreach (DictionaryEntry targetPrimaryKeyEntry in targetPrimaryKeys) { string targetPrimaryKey = (string)targetPrimaryKeyEntry.Key; bool keepRow = false; RowOperation rowOperation = RowOperation.None; Row compared = this.CompareRows(targetTable, targetPrimaryKeyEntry.Value as Row, updatedPrimaryKeys[targetPrimaryKey] as Row, out rowOperation, out keepRow); if (keepRow) { rows.Add(compared); } } // find the inserted rows foreach (DictionaryEntry updatedPrimaryKeyEntry in updatedPrimaryKeys) { string updatedPrimaryKey = (string)updatedPrimaryKeyEntry.Key; if (!targetPrimaryKeys.Contains(updatedPrimaryKey)) { Row updatedRow = (Row)updatedPrimaryKeyEntry.Value; updatedRow.Operation = RowOperation.Add; updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId; rows.Add(updatedRow); } } } } return(rows); }
/// <summary> /// Verifies that a given table exists in the output /// </summary> /// <param name="output">Output object to verify.</param> /// <param name="tableName">Name of the table to check for.</param> /// <returns>True if the table exists in the output, false otherwise</returns> public static bool CheckTableExists(Output output, string tableName) { bool tableExists = true; try { int i = output.Tables[tableName].Rows.Count; } catch (Exception) { tableExists = false; } return tableExists; }
/// <summary> /// Verifies that a given table does not exists in the output /// </summary> /// <param name="output">Output object to verify.</param> /// <param name="tableName">Name of the table to verify.</param> /// <param name="wixoutFile">File where output object is stored. Only used to display error message.</param> public static void VerifyNotTableExists(Output output, string tableName, string wixoutFile) { bool tableExists = CheckTableExists(output, tableName); Assert.False(tableExists, String.Format("Table '{0}' exists in output '{1}'. It was NOT expected to exist.", tableName, wixoutFile)); }
/// <summary> /// Creates a transform by diffing two outputs. /// </summary> /// <param name="targetOutput">The target output.</param> /// <param name="updatedOutput">The updated output.</param> /// <returns>The transform.</returns> public Output Diff(Output targetOutput, Output updatedOutput) { return Diff(targetOutput, updatedOutput, 0); }
/// <summary> /// Compare two Outputs /// </summary> /// <param name="targetOutput">The expected output</param> /// <param name="updatedOutput">The actual output</param> /// <returns>Any differences found.</returns> private static ArrayList CompareOutput(Output targetOutput, Output updatedOutput) { return Verifier.CompareOutput(targetOutput, updatedOutput, null); }
/// <summary> /// Resolve the feature backlinks to the final feature that a component will live in. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> /// <param name="allSymbols">All symbols loaded from the intermediates.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="unresolvedReferences">Unresolved references.</param> private void ResolveFeatureBacklinks( Output output, ConnectToFeatureCollection componentsToFeatures, SymbolCollection allSymbols, StringCollection referencedSymbols, ArrayList unresolvedReferences) { Hashtable uniqueComponentIds = new Hashtable(); foreach (Section section in output.Sections) { foreach (FeatureBacklink blink in section.FeatureBacklinks) { Reference reference = blink.Reference; Symbol symbol = Common.GetSymbolForReference(section, reference, allSymbols, referencedSymbols, unresolvedReferences, this); if (null == symbol) { continue; } Row row = symbol.Row; string parentFeature; if (OutputType.Module == output.Type) { parentFeature = Guid.Empty.ToString("B"); } else { ConnectToFeature connection = componentsToFeatures[blink.Component]; if (null == connection) { throw new WixMissingFeatureException(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), blink); } parentFeature = connection.PrimaryFeature; // check for unique, implicit, primary feature parents with multiple possible parent features if (PedanticLevel.Legendary == this.pedanticLevel && !connection.IsExplicitPrimaryFeature && 0 < connection.ConnectFeatures.Count && !uniqueComponentIds.Contains(blink.Component)) { this.OnMessage(WixWarnings.ImplicitPrimaryFeature(blink.Component)); // remember this component so only one warning is generated for it uniqueComponentIds[blink.Component] = null; } } switch (blink.Type) { case FeatureBacklinkType.Class: row[11] = parentFeature; break; case FeatureBacklinkType.Extension: row[4] = parentFeature; break; case FeatureBacklinkType.PublishComponent: row[4] = parentFeature; break; case FeatureBacklinkType.Shortcut: row[4] = parentFeature; break; case FeatureBacklinkType.TypeLib: row[6] = parentFeature; break; default: throw new ApplicationException("Internal Error: Unknown FeatureBackLinkType."); } } } }
/// <summary> /// Called after database variable resolution occurs. /// </summary> public virtual void DatabaseAfterResolvedFields(Output output) { }
/// <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); }
/// <summary> /// Reduce the transform according to the patch references. /// </summary> /// <param name="transform">transform generated by torch.</param> /// <param name="patchRefTable">Table contains patch family filter.</param> /// <returns>true if the transform is not empty</returns> public static bool ReduceTransform(Output transform, Table patchRefTable) { // identify sections to keep Hashtable oldSections = new Hashtable(patchRefTable.Rows.Count); Hashtable newSections = new Hashtable(patchRefTable.Rows.Count); Hashtable tableKeyRows = new Hashtable(); ArrayList sequenceList = new ArrayList(); Hashtable componentFeatureAddsIndex = new Hashtable(); Hashtable customActionTable = new Hashtable(); Hashtable directoryTableAdds = new Hashtable(); Hashtable featureTableAdds = new Hashtable(); ArrayList keptComponentTableAdds = new ArrayList(); Hashtable keptDirectories = new Hashtable(); Hashtable keptFeatures = new Hashtable(); foreach (Row patchRefRow in patchRefTable.Rows) { string tableName = (string)patchRefRow[0]; string key = (string)patchRefRow[1]; Table table = transform.Tables[tableName]; if (table == null) { // table not found continue; } // index this table if (!tableKeyRows.Contains(tableName)) { Hashtable newKeyRows = new Hashtable(); foreach (Row newRow in table.Rows) { newKeyRows[newRow.GetPrimaryKey('/')] = newRow; } tableKeyRows[tableName] = newKeyRows; } Hashtable keyRows = (Hashtable)tableKeyRows[tableName]; Row row = (Row)keyRows[key]; if (row == null) { // row not found continue; } // Differ.sectionDelimiter string[] sections = row.SectionId.Split('/'); oldSections[sections[0]] = row; newSections[sections[1]] = row; } // throw away sections not referenced int keptRows = 0; Table directoryTable = null; Table featureTable = null; foreach (Table table in transform.Tables) { if ("_SummaryInformation" == table.Name) { continue; } if (table.Name == "AdminExecuteSequence" || table.Name == "AdminUISequence" || table.Name == "AdvtExecuteSequence" || table.Name == "InstallUISequence" || table.Name == "InstallExecuteSequence") { sequenceList.Add(table); continue; } for (int i = 0; i < table.Rows.Count; i++) { Row row = table.Rows[i]; if (table.Name == "CustomAction") { customActionTable.Add(row[0], row); } if (table.Name == "Directory") { directoryTable = table; if (RowOperation.Add == row.Operation) { directoryTableAdds.Add(row[0], row); } } if (table.Name == "Feature") { featureTable = table; if (RowOperation.Add == row.Operation) { featureTableAdds.Add(row[0], row); } } if (table.Name == "FeatureComponents") { if (RowOperation.Add == row.Operation) { string featureId = (string)row[0]; string componentId = (string)row[1]; if (componentFeatureAddsIndex.ContainsKey(componentId)) { ArrayList featureList = (ArrayList)componentFeatureAddsIndex[componentId]; featureList.Add(featureId); } else { ArrayList featureList = new ArrayList(); componentFeatureAddsIndex.Add(componentId, featureList); featureList.Add(featureId); } } } if (null == row.SectionId) { table.Rows.RemoveAt(i); i--; } else { string[] sections = row.SectionId.Split('/'); // ignore the row without section id. if (0 == sections[0].Length && 0 == sections[1].Length) { table.Rows.RemoveAt(i); i--; } else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections)) { if ("Component" == table.Name) { if (RowOperation.Add == row.Operation) { keptComponentTableAdds.Add(row); } } if ("Directory" == table.Name) { keptDirectories.Add(row[0], row); } if ("Feature" == table.Name) { keptFeatures.Add(row[0], row); } keptRows++; } else { table.Rows.RemoveAt(i); i--; } } } } keptRows += ReduceTransformSequenceTable(sequenceList, oldSections, newSections, customActionTable); if (null != directoryTable) { foreach (Row componentRow in keptComponentTableAdds) { // make sure each added component has its required directory and feature heirarchy. string directoryId = (string)componentRow[2]; while (null != directoryId && directoryTableAdds.ContainsKey(directoryId)) { Row directoryRow = (Row)directoryTableAdds[directoryId]; if (!keptDirectories.ContainsKey(directoryId)) { directoryTable.Rows.Add(directoryRow); keptDirectories.Add(directoryRow[0], null); keptRows++; } directoryId = (string)directoryRow[1]; } string componentId = (string)componentRow[0]; if (componentFeatureAddsIndex.ContainsKey(componentId)) { foreach (string featureId in (ArrayList)componentFeatureAddsIndex[componentId]) { string currentFeatureId = featureId; while (null != currentFeatureId && featureTableAdds.ContainsKey(currentFeatureId)) { Row featureRow = (Row)featureTableAdds[currentFeatureId]; if (!keptFeatures.ContainsKey(currentFeatureId)) { featureTable.Rows.Add(featureRow); keptFeatures.Add(featureRow[0], null); keptRows++; } currentFeatureId = (string)featureRow[1]; } } } } } keptRows += ReduceTransformSequenceTable(sequenceList, oldSections, newSections, customActionTable); // Delete tables that are empty. ArrayList tablesToDelete = new ArrayList(); foreach (Table table in transform.Tables) { if (0 == table.Rows.Count) { tablesToDelete.Add(table.Name); } } // delete separately to avoid messing up enumeration foreach (string tableName in tablesToDelete) { transform.Tables.Remove(tableName); } return keptRows > 0; }
public Wix.Wix Decompile(Output output) { if (null == output) { throw new ArgumentNullException("output"); } this.codepage = output.Codepage; this.outputType = output.Type; // collect the table definitions from the output this.tableDefinitions.Clear(); foreach (Table table in output.Tables) { this.tableDefinitions.Add(table.Definition); } // add any missing standard and wix-specific table definitions foreach (TableDefinition tableDefinition in Installer.GetTableDefinitions()) { if (!this.tableDefinitions.Contains(tableDefinition.Name)) { this.tableDefinitions.Add(tableDefinition); } } // add any missing extension table definitions foreach (WixExtension extension in this.extensions) { if (null != extension.TableDefinitions) { foreach (TableDefinition tableDefinition in extension.TableDefinitions) { if (!this.tableDefinitions.Contains(tableDefinition.Name)) { this.tableDefinitions.Add(tableDefinition); } } } } // if we don't have the temporary files object yet, get one if (null == this.tempFiles) { this.TempFilesLocation = null; } Directory.CreateDirectory(this.tempFiles.BasePath); // ensure the base path is there bool encounteredError = false; Wix.IParentElement rootElement; Wix.Wix wixElement = new Wix.Wix(); switch (this.outputType) { case OutputType.Module: rootElement = new Wix.Module(); break; case OutputType.PatchCreation: rootElement = new Wix.PatchCreation(); break; case OutputType.Product: rootElement = new Wix.Product(); break; default: throw new InvalidOperationException(WixStrings.EXP_UnknownOutputType); } wixElement.AddChild((Wix.ISchemaElement)rootElement); // try to decompile the database file try { this.core = new DecompilerCore(rootElement, this.Message); this.core.ShowPedanticMessages = this.showPedanticMessages; // stop processing if an error previously occurred if (this.core.EncounteredError) { return null; } // initialize the decompiler and its extensions foreach (WixExtension extension in this.extensions) { if (null != extension.DecompilerExtension) { extension.DecompilerExtension.Core = this.core; extension.DecompilerExtension.InitializeDecompile(output.Tables); } } this.InitializeDecompile(output.Tables); // stop processing if an error previously occurred if (this.core.EncounteredError) { return null; } // decompile the tables this.DecompileTables(output); // finalize the decompiler and its extensions this.FinalizeDecompile(output.Tables); foreach (WixExtension extension in this.extensions) { if (null != extension.DecompilerExtension) { extension.DecompilerExtension.FinalizeDecompile(output.Tables); } } } finally { encounteredError = this.core.EncounteredError; this.core = null; foreach (WixExtension extension in this.extensions) { if (null != extension.DecompilerExtension) { extension.DecompilerExtension.Core = null; } } } // return the root element only if decompilation completed successfully return (encounteredError ? null : wixElement); }
public Output BuildPairedTransform(string patchId, string clientPatchId, Output mainTransform, MediaRow mediaRow, int validationFlags, out string productCode) { productCode = null; Output pairedTransform = new Output(null); pairedTransform.Type = OutputType.Transform; pairedTransform.Codepage = mainTransform.Codepage; // lookup productVersion property to correct summaryInformation string newProductVersion = null; Table mainPropertyTable = mainTransform.Tables["Property"]; if (null != mainPropertyTable) { foreach (Row row in mainPropertyTable.Rows) { if ("ProductVersion" == (string)row[0]) { newProductVersion = (string)row[1]; } } } // TODO: build class for manipulating SummaryInformation table Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"]; // add required properties Hashtable mainSummaryRows = new Hashtable(); foreach (Row mainSummaryRow in mainSummaryTable.Rows) { mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow; } if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags)) { Row mainSummaryRow = mainSummaryTable.CreateRow(null); mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags; mainSummaryRow[1] = validationFlags.ToString(CultureInfo.InvariantCulture); } // copy summary information from core transform Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]); foreach (Row mainSummaryRow in mainSummaryTable.Rows) { string value = (string)mainSummaryRow[1]; switch ((SummaryInformation.Transform)mainSummaryRow[0]) { case SummaryInformation.Transform.ProductCodes: string[] propertyData = value.Split(';'); string oldProductVersion = propertyData[0].Substring(38); string upgradeCode = propertyData[2]; productCode = propertyData[0].Substring(0, 38); if (newProductVersion == null) { newProductVersion = oldProductVersion; } // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode); value = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode); break; case SummaryInformation.Transform.ValidationFlags: // use validation flags authored into the patch XML mainSummaryRow[1] = value = validationFlags.ToString(CultureInfo.InvariantCulture); break; } Row pairedSummaryRow = pairedSummaryTable.CreateRow(null); pairedSummaryRow[0] = mainSummaryRow[0]; pairedSummaryRow[1] = value; } if (productCode == null) { throw new InvalidOperationException(WixStrings.EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo); } // copy File table Table mainFileTable = mainTransform.Tables["File"]; if (null != mainFileTable && 0 < mainFileTable.Rows.Count) { // We require file source information. Table mainWixFileTable = mainTransform.Tables["WixFile"]; if (null == mainWixFileTable) { throw new WixException(WixErrors.AdminImageRequired(productCode)); } FileRowCollection mainFileRows = new FileRowCollection(); mainFileRows.AddRange(mainFileTable.Rows); Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition); foreach (WixFileRow mainWixFileRow in mainWixFileTable.Rows) { FileRow mainFileRow = mainFileRows[mainWixFileRow.File]; // set File.Sequence to non null to satisfy transform bind mainFileRow.Sequence = 1; // delete's don't need rows in the paired transform if (mainFileRow.Operation == RowOperation.Delete) { continue; } FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null); pairedFileRow.Operation = RowOperation.Modify; for (int i = 0; i < mainFileRow.Fields.Length; i++) { pairedFileRow[i] = mainFileRow[i]; } // override authored media for patch bind // TODO: consider using File/@DiskId for patch media mainFileRow.DiskId = mediaRow.DiskId; mainWixFileRow.DiskId = mediaRow.DiskId; // suppress any change to File.Sequence to avoid bloat mainFileRow.Fields[7].Modified = false; // force File row to appear in the transform switch (mainFileRow.Operation) { case RowOperation.Modify: case RowOperation.Add: // set msidbFileAttributesPatchAdded pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded; pairedFileRow.Fields[6].Modified = true; pairedFileRow.Operation = mainFileRow.Operation; break; default: pairedFileRow.Fields[6].Modified = false; break; } } } // add Media row to pairedTransform Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]); Row pairedMediaRow = pairedMediaTable.CreateRow(null); pairedMediaRow.Operation = RowOperation.Add; for (int i = 0; i < mediaRow.Fields.Length; i++) { pairedMediaRow[i] = mediaRow[i]; } // add PatchPackage for this Media Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]); pairedPackageTable.Operation = TableOperation.Add; Row pairedPackageRow = pairedPackageTable.CreateRow(null); pairedPackageRow.Operation = RowOperation.Add; pairedPackageRow[0] = patchId; pairedPackageRow[1] = mediaRow.DiskId; // add property to both identify client patches and whether those patches are removable or not int allowRemoval = 0; Table msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"]; if (null != msiPatchMetadataTable) { foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows) { // get the value of the standard AllowRemoval property, if present string company = (string)msiPatchMetadataRow[0]; if ((null == company || 0 == company.Length) && "AllowRemoval" == (string)msiPatchMetadataRow[1]) { allowRemoval = Int32.Parse((string)msiPatchMetadataRow[2], CultureInfo.InvariantCulture); } } } // add the property to the patch transform's Property table Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]); pairedPropertyTable.Operation = TableOperation.Add; Row pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = string.Concat(clientPatchId, ".AllowRemoval"); pairedPropertyRow[1] = allowRemoval.ToString(CultureInfo.InvariantCulture); // add this patch code GUID to the patch transform to identify // which patches are installed, including in multi-patch // installations. pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = string.Concat(clientPatchId, ".PatchCode"); pairedPropertyRow[1] = patchId; // add PATCHNEWPACKAGECODE to apply to admin layouts pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = "PATCHNEWPACKAGECODE"; pairedPropertyRow[1] = patchId; // add PATCHNEWSUMMARYCOMMENTS and PATCHNEWSUMMARYSUBJECT to apply to admin layouts Table _summaryInformationTable = this.patch.Tables["_SummaryInformation"]; if (null != _summaryInformationTable) { foreach (Row row in _summaryInformationTable.Rows) { if (3 == (int)row[0]) // PID_SUBJECT { pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = "PATCHNEWSUMMARYSUBJECT"; pairedPropertyRow[1] = row[1]; } else if (6 == (int)row[0]) // PID_COMMENTS { pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = "PATCHNEWSUMMARYCOMMENTS"; pairedPropertyRow[1] = row[1]; } } } return pairedTransform; }
/// <summary> /// Decompile the tables. /// </summary> /// <param name="output">The output being decompiled.</param> private void DecompileTables(Output output) { StringCollection sortedTableNames = this.GetSortedTableNames(); foreach (string tableName in sortedTableNames) { Table table = output.Tables[tableName]; // table does not exist in this database or should not be decompiled if (null == table || !this.DecompilableTable(output, tableName)) { continue; } this.core.OnMessage(WixVerboses.DecompilingTable(table.Name)); // empty tables may be kept with EnsureTable if the user set the proper option if (0 == table.Rows.Count && this.suppressDroppingEmptyTables) { Wix.EnsureTable ensureTable = new Wix.EnsureTable(); ensureTable.Id = table.Name; this.core.RootElement.AddChild(ensureTable); } switch (table.Name) { case "_SummaryInformation": this.Decompile_SummaryInformationTable(table); break; case "AdminExecuteSequence": case "AdminUISequence": case "AdvtExecuteSequence": case "InstallExecuteSequence": case "InstallUISequence": case "ModuleAdminExecuteSequence": case "ModuleAdminUISequence": case "ModuleAdvtExecuteSequence": case "ModuleInstallExecuteSequence": case "ModuleInstallUISequence": // handled in FinalizeSequenceTables break; case "ActionText": this.DecompileActionTextTable(table); break; case "AdvtUISequence": this.core.OnMessage(WixWarnings.DeprecatedTable(table.Name)); break; case "AppId": this.DecompileAppIdTable(table); break; case "AppSearch": // handled in FinalizeSearchTables break; case "BBControl": this.DecompileBBControlTable(table); break; case "Billboard": this.DecompileBillboardTable(table); break; case "Binary": this.DecompileBinaryTable(table); break; case "BindImage": this.DecompileBindImageTable(table); break; case "CCPSearch": // handled in FinalizeSearchTables break; case "CheckBox": // handled in FinalizeCheckBoxTable break; case "Class": this.DecompileClassTable(table); break; case "ComboBox": this.DecompileComboBoxTable(table); break; case "Control": this.DecompileControlTable(table); break; case "ControlCondition": this.DecompileControlConditionTable(table); break; case "ControlEvent": this.DecompileControlEventTable(table); break; case "CreateFolder": this.DecompileCreateFolderTable(table); break; case "CustomAction": this.DecompileCustomActionTable(table); break; case "CompLocator": this.DecompileCompLocatorTable(table); break; case "Complus": this.DecompileComplusTable(table); break; case "Component": this.DecompileComponentTable(table); break; case "Condition": this.DecompileConditionTable(table); break; case "Dialog": this.DecompileDialogTable(table); break; case "Directory": this.DecompileDirectoryTable(table); break; case "DrLocator": this.DecompileDrLocatorTable(table); break; case "DuplicateFile": this.DecompileDuplicateFileTable(table); break; case "Environment": this.DecompileEnvironmentTable(table); break; case "Error": this.DecompileErrorTable(table); break; case "EventMapping": this.DecompileEventMappingTable(table); break; case "Extension": this.DecompileExtensionTable(table); break; case "ExternalFiles": this.DecompileExternalFilesTable(table); break; case "FamilyFileRanges": // handled in FinalizeFamilyFileRangesTable break; case "Feature": this.DecompileFeatureTable(table); break; case "FeatureComponents": this.DecompileFeatureComponentsTable(table); break; case "File": this.DecompileFileTable(table); break; case "FileSFPCatalog": this.DecompileFileSFPCatalogTable(table); break; case "Font": this.DecompileFontTable(table); break; case "Icon": this.DecompileIconTable(table); break; case "ImageFamilies": this.DecompileImageFamiliesTable(table); break; case "IniFile": this.DecompileIniFileTable(table); break; case "IniLocator": this.DecompileIniLocatorTable(table); break; case "IsolatedComponent": this.DecompileIsolatedComponentTable(table); break; case "LaunchCondition": this.DecompileLaunchConditionTable(table); break; case "ListBox": this.DecompileListBoxTable(table); break; case "ListView": this.DecompileListViewTable(table); break; case "LockPermissions": this.DecompileLockPermissionsTable(table); break; case "Media": this.DecompileMediaTable(table); break; case "MIME": this.DecompileMIMETable(table); break; case "ModuleAdvtUISequence": this.core.OnMessage(WixWarnings.DeprecatedTable(table.Name)); break; case "ModuleComponents": // handled by DecompileComponentTable (since the ModuleComponents table // rows are created by nesting components under the Module element) break; case "ModuleConfiguration": this.DecompileModuleConfigurationTable(table); break; case "ModuleDependency": this.DecompileModuleDependencyTable(table); break; case "ModuleExclusion": this.DecompileModuleExclusionTable(table); break; case "ModuleIgnoreTable": this.DecompileModuleIgnoreTableTable(table); break; case "ModuleSignature": this.DecompileModuleSignatureTable(table); break; case "ModuleSubstitution": this.DecompileModuleSubstitutionTable(table); break; case "MoveFile": this.DecompileMoveFileTable(table); break; case "MsiAssembly": // handled in FinalizeFileTable break; case "MsiDigitalCertificate": this.DecompileMsiDigitalCertificateTable(table); break; case "MsiDigitalSignature": this.DecompileMsiDigitalSignatureTable(table); break; case "MsiEmbeddedChainer": this.DecompileMsiEmbeddedChainerTable(table); break; case "MsiEmbeddedUI": this.DecompileMsiEmbeddedUITable(table); break; case "MsiLockPermissionsEx": this.DecompileMsiLockPermissionsExTable(table); break; case "MsiPackageCertificate": this.DecompileMsiPackageCertificateTable(table); break; case "MsiPatchCertificate": this.DecompileMsiPatchCertificateTable(table); break; case "MsiShortcutProperty": this.DecompileMsiShortcutPropertyTable(table); break; case "ODBCAttribute": this.DecompileODBCAttributeTable(table); break; case "ODBCDataSource": this.DecompileODBCDataSourceTable(table); break; case "ODBCDriver": this.DecompileODBCDriverTable(table); break; case "ODBCSourceAttribute": this.DecompileODBCSourceAttributeTable(table); break; case "ODBCTranslator": this.DecompileODBCTranslatorTable(table); break; case "PatchMetadata": this.DecompilePatchMetadataTable(table); break; case "PatchSequence": this.DecompilePatchSequenceTable(table); break; case "ProgId": this.DecompileProgIdTable(table); break; case "Properties": this.DecompilePropertiesTable(table); break; case "Property": this.DecompilePropertyTable(table); break; case "PublishComponent": this.DecompilePublishComponentTable(table); break; case "RadioButton": this.DecompileRadioButtonTable(table); break; case "Registry": this.DecompileRegistryTable(table); break; case "RegLocator": this.DecompileRegLocatorTable(table); break; case "RemoveFile": this.DecompileRemoveFileTable(table); break; case "RemoveIniFile": this.DecompileRemoveIniFileTable(table); break; case "RemoveRegistry": this.DecompileRemoveRegistryTable(table); break; case "ReserveCost": this.DecompileReserveCostTable(table); break; case "SelfReg": this.DecompileSelfRegTable(table); break; case "ServiceControl": this.DecompileServiceControlTable(table); break; case "ServiceInstall": this.DecompileServiceInstallTable(table); break; case "SFPCatalog": this.DecompileSFPCatalogTable(table); break; case "Shortcut": this.DecompileShortcutTable(table); break; case "Signature": this.DecompileSignatureTable(table); break; case "TargetFiles_OptionalData": this.DecompileTargetFiles_OptionalDataTable(table); break; case "TargetImages": this.DecompileTargetImagesTable(table); break; case "TextStyle": this.DecompileTextStyleTable(table); break; case "TypeLib": this.DecompileTypeLibTable(table); break; case "Upgrade": this.DecompileUpgradeTable(table); break; case "UpgradedFiles_OptionalData": this.DecompileUpgradedFiles_OptionalDataTable(table); break; case "UpgradedFilesToIgnore": this.DecompileUpgradedFilesToIgnoreTable(table); break; case "UpgradedImages": this.DecompileUpgradedImagesTable(table); break; case "UIText": this.DecompileUITextTable(table); break; case "Verb": this.DecompileVerbTable(table); break; default: DecompilerExtension extension = (DecompilerExtension)this.extensionsByTableName[table.Name]; if (null != extension) { extension.DecompileTable(table); } else if (!this.suppressCustomTables) { this.DecompileCustomTable(table); } break; } } }
/// <summary> /// Resolve component groups. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="componentsToComponentGroupsComplexReferences">Component to ComponentGroup complex references.</param> /// <param name="componentGroupsToFeatures">ComponentGroups to features complex references.</param> /// <param name="componentGroupsToModules">ComponentGroups to modules complex references.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> private void ResolveComponentGroups( Output output, StringCollection referencedSymbols, ComplexReferenceCollection componentsToComponentGroupsComplexReferences, ConnectToFeatureCollection componentGroupsToFeatures, ConnectToModuleCollection componentGroupsToModules, ConnectToFeatureCollection componentsToFeatures) { foreach (ComplexReference cref in componentsToComponentGroupsComplexReferences) { // only connect a Component to a Feature if the ComponentGroup is connected to a Feature ConnectToFeature connectComponentGroupToFeature = componentGroupsToFeatures[cref.ParentId]; if (null != connectComponentGroupToFeature) { // create a list of all features (use an ArrayList because StringCollection lacks an AddRange method that takes an ICollection) ArrayList features = new ArrayList(connectComponentGroupToFeature.ConnectFeatures); features.Add(connectComponentGroupToFeature.PrimaryFeature); foreach (string feature in features) { ConnectToFeature connectComponentToFeature = componentsToFeatures[cref.ChildId]; bool isExplicitPrimaryFeature = (connectComponentGroupToFeature.IsExplicitPrimaryFeature && (connectComponentGroupToFeature.PrimaryFeature == feature)); if (null == connectComponentToFeature) { componentsToFeatures.Add(new ConnectToFeature(connectComponentGroupToFeature.Section, cref.ChildId, feature, isExplicitPrimaryFeature)); } else if (isExplicitPrimaryFeature && connectComponentToFeature.IsExplicitPrimaryFeature && feature != connectComponentToFeature.PrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(connectComponentToFeature.Section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, feature)); continue; } else if (isExplicitPrimaryFeature) { connectComponentToFeature.ConnectFeatures.Add(connectComponentToFeature.PrimaryFeature); // move the guessed primary feature to the list of connects connectComponentToFeature.PrimaryFeature = feature; // set the new primary feature connectComponentToFeature.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connectComponentToFeature.ConnectFeatures.Add(feature); } // add a row to the FeatureComponents table Row row = Common.CreateRowInSection(null, output.EntrySection, this.tableDefinitions["FeatureComponents"]); row[0] = feature; row[1] = cref.ChildId; // index the component for finding orphaned records Reference reference = new Reference("Component", cref.ChildId); if (!referencedSymbols.Contains(reference.SymbolicName)) { referencedSymbols.Add(reference.SymbolicName); } } } // only connect a Component to a Module if the ComponentGroup is connected to a Module ConnectToModule connectComponentGroupToModule = componentGroupsToModules[cref.ParentId]; if (null != connectComponentGroupToModule) { // add a row to the ModuleComponents table Row row = Common.CreateRowInSection(null, output.EntrySection, this.tableDefinitions["ModuleComponents"]); row[0] = cref.ChildId; row[1] = connectComponentGroupToModule.Module; row[2] = connectComponentGroupToModule.ModuleLanguage; // index the component for finding orphaned records Reference reference = new Reference("Component", cref.ChildId); if (!referencedSymbols.Contains(reference.SymbolicName)) { referencedSymbols.Add(reference.SymbolicName); } } } }
/// <summary> /// Called during the generation of sectionIds for an admin image. /// </summary> public virtual void GenerateSectionIds(Output output) { }
/// <summary> /// Links an array of intermediates into an output. /// </summary> /// <param name="intermediates">Array of intermediates to link together.</param> /// <returns>Output object from the linking.</returns> public Output Link(Intermediate[] intermediates) { Output output = null; try { SymbolCollection allSymbols; Section entrySection; bool containsModuleSubstitution = false; bool containsModuleConfiguration = false; StringCollection referencedSymbols = new StringCollection(); ArrayList unresolvedReferences = new ArrayList(); ConnectToFeatureCollection componentGroupsToFeatures = new ConnectToFeatureCollection(); ConnectToModuleCollection componentGroupsToModules = new ConnectToModuleCollection(); ComplexReferenceCollection componentsToComponentGroupsComplexReferences = new ComplexReferenceCollection(); ConnectToFeatureCollection componentsToFeatures = new ConnectToFeatureCollection(); ConnectToFeatureCollection featuresToFeatures = new ConnectToFeatureCollection(); this.activeOutput = null; this.foundError = false; SortedList adminProperties = new SortedList(); SortedList secureProperties = new SortedList(); SortedList hiddenProperties = new SortedList(); ActionTable requiredActions = new ActionTable(); RowCollection suppressActionRows = new RowCollection(); TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection(); RowCollection customRows = new RowCollection(); foreach (SchemaExtension extension in this.extensions.Values) { extension.Messages = this.extensionMessages; } // first find the entry section and create the symbols hash for all // the sections in all the intermediates Common.FindEntrySectionAndLoadSymbols(intermediates, this.allowIdenticalRows, this, out entrySection, out allSymbols); // should have found an entry section by now if (null == entrySection) { this.OnMessage(WixErrors.MissingEntrySection()); return null; } // add the standard action symbols to the entry section's symbol table this.LoadStandardActionSymbols(allSymbols, entrySection, this.standardActions); // now that we know where we're starting from, create the output object output = new Output(entrySection); // Note: this entry section will get added to the output section collection later if (null != this.localizer && -1 != this.localizer.Codepage) { output.Codepage = this.localizer.Codepage; } this.activeOutput = output; // resolve the symbol references to find the set of sections we // care about then resolve complex references in those sections Common.ResolveReferences(output.Type, output.Sections, output.EntrySection, allSymbols, referencedSymbols, unresolvedReferences, this); this.ProcessComplexReferences(output, output.Sections, referencedSymbols, componentsToComponentGroupsComplexReferences, componentGroupsToFeatures, componentGroupsToModules, componentsToFeatures, featuresToFeatures); for (int i = 0; i < unresolvedReferences.Count; ++i) { Common.ReferenceSection referenceSection = (Common.ReferenceSection)unresolvedReferences[i]; if (this.allowUnresolvedReferences) { this.OnMessage(WixWarnings.UnresolvedReferenceWarning(SourceLineNumberCollection.FromFileName(referenceSection.section.Intermediate.SourcePath), referenceSection.section.Type.ToString(), referenceSection.section.Id, referenceSection.reference.SymbolicName)); } else { this.OnMessage(WixErrors.UnresolvedReference(SourceLineNumberCollection.FromFileName(referenceSection.section.Intermediate.SourcePath), referenceSection.section.Type.ToString(), referenceSection.section.Id, referenceSection.reference.SymbolicName)); } } if (this.foundError) { return null; } this.ResolveComponentGroups(output, referencedSymbols, componentsToComponentGroupsComplexReferences, componentGroupsToFeatures, componentGroupsToModules, componentsToFeatures); this.FindOrphanedSymbols(referencedSymbols); // resolve the feature backlink for each section then update the feature to feature connects this.ResolveFeatureBacklinks(output, componentsToFeatures, allSymbols, referencedSymbols, unresolvedReferences); this.ResolveFeatureToFeatureConnects(featuresToFeatures, allSymbols, referencedSymbols, unresolvedReferences); // create a Hashtable of all the suppressed sequence types Hashtable suppressedSequenceTypes = new Hashtable(); // create a Hashtable of all the suppressed standard actions Hashtable suppressedStandardActions = new Hashtable(); if (this.suppressAdminSequence) { suppressedSequenceTypes[SequenceType.adminExecute] = null; suppressedSequenceTypes[SequenceType.adminUI] = null; } if (this.suppressAdvertiseSequence) { suppressedSequenceTypes[SequenceType.advertiseExecute] = null; } if (this.suppressUISequence) { suppressedSequenceTypes[SequenceType.adminUI] = null; suppressedSequenceTypes[SequenceType.installUI] = null; } // start generating OutputTables and OutputRows for all the sections in the output RowCollection ensureTableRows = new RowCollection(); foreach (Section section in this.activeOutput.Sections) { // add this sections list of identifiers to ignore modularization this.activeOutput.IgnoreModularizations.Add(section.IgnoreModularizations); foreach (Table table in section.Tables) { bool copyRows = !table.Definition.IsUnreal; // by default, copy rows if the table is not unreal // handle special tables switch (table.Name) { case "Actions": foreach (Row row in table.Rows) { SequenceType sequenceType; string seqType = (string)row[0]; string id = (string)row[1]; int sequence = null == row[3] ? 0 : Convert.ToInt32(row[3]); bool suppress = 1 == Convert.ToInt32(row[6]); switch (seqType) { case "AdminUISequence": sequenceType = SequenceType.adminUI; break; case "AdminExecuteSequence": sequenceType = SequenceType.adminExecute; break; case "AdvertiseExecuteSequence": sequenceType = SequenceType.advertiseExecute; break; case "InstallExecuteSequence": sequenceType = SequenceType.installExecute; break; case "InstallUISequence": sequenceType = SequenceType.installUI; break; default: throw new WixInvalidSequenceTypeException(null, seqType); } if (suppressedSequenceTypes.Contains(sequenceType)) { this.OnMessage(WixWarnings.SuppressAction(id, Action.SequenceTypeToString(sequenceType))); continue; } // create a SuppressAction row to allow suppressing the action from a merge module if (suppress) { Row suppressActionRow = new Row(row.SourceLineNumbers, this.tableDefinitions["SuppressAction"]); if ("AdvertiseExecuteSequence" == (string)row[0]) { suppressActionRow[0] = "AdvtExecuteSequence"; } else { suppressActionRow[0] = row[0]; } suppressActionRow[1] = row[1]; suppressActionRows.Add(suppressActionRow); } Action action = this.standardActions[sequenceType, id]; string beforeAction = (string)row[4]; string afterAction = (string)row[5]; // if this is not a standard action or there is a before or after action specified if (null == action || null != beforeAction || null != afterAction) { action = new Action(sequenceType, id, (string)row[2], sequence, beforeAction, afterAction); requiredActions.Add(action, true); // add the action and overwrite even if it already exists since this is a customization // if the parent action is a standard action add it to the required list string parentActionName = null != beforeAction ? beforeAction : afterAction; Action parentAction = this.standardActions[sequenceType, parentActionName]; if (null != parentAction) { requiredActions.Add(parentAction); } } else if (!suppress) // must have a standard action that is being overriden (when not suppressed) { action.Condition = (string)row[2]; if (0 != sequence) // if the user specified a sequence number, override the default { action.SequenceNumber = sequence; } requiredActions.Add(action, true); // ensure this action is in the required list } // action was suppressed by user if (suppress && null != action) { suppressedStandardActions[String.Concat(action.SequenceType.ToString(), id)] = action; } } break; case "AppSearch": Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Signature"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "AppSearch"]); break; case "Binary": case "Icon": case "MsiDigitalCertificate": foreach (Row row in table.Rows) { ImportStreamType importStreamType = ImportStreamType.Unknown; switch (table.Name) { case "Binary": importStreamType = ImportStreamType.Binary; break; case "Icon": importStreamType = ImportStreamType.Icon; break; case "MsiDigitalCertificate": importStreamType = ImportStreamType.DigitalCertificate; break; } ImportStream importStream = new ImportStream(importStreamType, row[0].ToString(), row[1].ToString()); if (this.activeOutput.ImportStreams.Contains(importStream.Name)) { this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, String.Format("{0} element with Id='{1}' is defined multiple times.", table.Name, row.Symbol.Name))); } this.activeOutput.ImportStreams.Add(importStream); } Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions[table.Name]); copyRows = false; break; case "BindImage": requiredActions.Add(this.standardActions[SequenceType.installExecute, "BindImage"]); break; case "CCPSearch": requiredActions.Add(this.standardActions[SequenceType.installExecute, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "CCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RMCCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "CCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "RMCCPSearch"]); break; case "Class": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterClassInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterClassInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterClassInfo"]); break; case "Complus": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterComPlus"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterComPlus"]); break; case "CreateFolder": requiredActions.Add(this.standardActions[SequenceType.installExecute, "CreateFolders"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFolders"]); break; case "CustomAction": if (OutputType.Module == this.activeOutput.Type) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); } break; case "CustomTables": foreach (Row row in table.Rows) { TableDefinition customTable = new TableDefinition((string)row[0], false); if (null == row[4]) { this.OnMessage(WixErrors.ExpectedAttribute(row.SourceLineNumbers, "CustomTable/Column", "PrimaryKey")); } string[] columnNames = row[2].ToString().Split(tabCharacter); string[] columnTypes = row[3].ToString().Split(tabCharacter); string[] primaryKeys = row[4].ToString().Split(tabCharacter); string[] minValues = row[5] == null ? null : row[5].ToString().Split(tabCharacter); string[] maxValues = row[6] == null ? null : row[6].ToString().Split(tabCharacter); string[] keyTables = row[7] == null ? null : row[7].ToString().Split(tabCharacter); string[] keyColumns = row[8] == null ? null : row[8].ToString().Split(tabCharacter); string[] categories = row[9] == null ? null : row[9].ToString().Split(tabCharacter); string[] sets = row[10] == null ? null : row[10].ToString().Split(tabCharacter); string[] descriptions = row[11] == null ? null : row[11].ToString().Split(tabCharacter); string[] modularizations = row[12] == null ? null : row[12].ToString().Split(tabCharacter); int currentPrimaryKey = 0; for (int i = 0; i < columnNames.Length; ++i) { string name = columnNames[i]; ColumnType type = ColumnType.Unknown; switch (columnTypes[i].Substring(0, 1).ToLower(CultureInfo.InvariantCulture)) { case "s": type = ColumnType.String; break; case "l": type = ColumnType.Localized; break; case "i": type = ColumnType.Number; break; case "g": type = ColumnType.Object; break; default: throw new ApplicationException(String.Format("Unknown custom table column type: {0}", columnTypes[i])); } bool nullable = columnTypes[i].Substring(0, 1) == columnTypes[i].Substring(0, 1).ToUpper(CultureInfo.InvariantCulture); int length = Convert.ToInt32(columnTypes[i].Substring(1)); bool primaryKey = false; if (currentPrimaryKey < primaryKeys.Length && primaryKeys[currentPrimaryKey] == columnNames[i]) { primaryKey = true; currentPrimaryKey++; } bool minValSet = null != minValues && null != minValues[i] && 0 < minValues[i].Length; int minValue = 0; if (minValSet) { minValue = Convert.ToInt32(minValues[i]); } bool maxValSet = null != maxValues && null != maxValues[i] && 0 < maxValues[i].Length; int maxValue = 0; if (maxValSet) { maxValue = Convert.ToInt32(maxValues[i]); } bool keyColumnSet = null != keyColumns && null != keyColumns[i] && 0 < keyColumns[i].Length; int keyColumn = 0; if (keyColumnSet) { keyColumn = Convert.ToInt32(keyColumns[i]); } ColumnCategory category = ColumnCategory.Unknown; if (null != categories && null != categories[i] && 0 < categories[i].Length) { switch (categories[i]) { case "Text": category = ColumnCategory.Text; break; case "UpperCase": category = ColumnCategory.UpperCase; break; case "LowerCase": category = ColumnCategory.LowerCase; break; case "Integer": category = ColumnCategory.Integer; break; case "DoubleInteger": category = ColumnCategory.DoubleInteger; break; case "TimeDate": category = ColumnCategory.TimeDate; break; case "Identifier": category = ColumnCategory.Identifier; break; case "Property": category = ColumnCategory.Property; break; case "Filename": category = ColumnCategory.Filename; break; case "WildCardFilename": category = ColumnCategory.WildCardFilename; break; case "Path": category = ColumnCategory.Path; break; case "Paths": category = ColumnCategory.Paths; break; case "AnyPath": category = ColumnCategory.AnyPath; break; case "DefaultDir": category = ColumnCategory.DefaultDir; break; case "RegPath": category = ColumnCategory.RegPath; break; case "Formatted": category = ColumnCategory.Formatted; break; case "Template": category = ColumnCategory.Template; break; case "Condition": category = ColumnCategory.Condition; break; case "Guid": category = ColumnCategory.Guid; break; case "Version": category = ColumnCategory.Version; break; case "Language": category = ColumnCategory.Language; break; case "Binary": category = ColumnCategory.Binary; break; case "CustomSource": category = ColumnCategory.CustomSource; break; case "Cabinet": category = ColumnCategory.Cabinet; break; case "Shortcut": category = ColumnCategory.Shortcut; break; default: break; } } string keyTable = keyTables != null ? keyTables[i] : null; string setValue = sets != null ? sets[i] : null; string description = descriptions != null ? descriptions[i] : null; string modString = modularizations != null ? modularizations[i] : null; ColumnModularizeType modularization = ColumnModularizeType.None; if (modString != null) { switch (modString) { case "None": modularization = ColumnModularizeType.None; break; case "Column": modularization = ColumnModularizeType.Column; break; case "Property": modularization = ColumnModularizeType.Property; break; case "Condition": modularization = ColumnModularizeType.Condition; break; case "CompanionFile": modularization = ColumnModularizeType.CompanionFile; break; case "SemicolonDelimited": modularization = ColumnModularizeType.SemicolonDelimited; break; } } ColumnDefinition columnDefinition = new ColumnDefinition(name, type, length, primaryKey, false, nullable, modularization, false, ColumnType.Localized == type, minValSet, minValue, maxValSet, maxValue, keyTable, keyColumnSet, keyColumn, category, setValue, description, true, true); customTable.Columns.Add(columnDefinition); } customTableDefinitions.Add(customTable); } copyRows = false; // we've created table definitions from these rows, no need to process them any longer break; case "RowData": foreach (Row row in table.Rows) { customRows.Add(row); } copyRows = false; break; case "Dialog": Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ListBox"]); break; case "Directory": foreach (Row row in table.Rows) { if (OutputType.Module == this.activeOutput.Type && Common.IsStandardDirectory(row[0].ToString())) { // if the directory table contains references to standard windows folders // mergemod.dll will add customactions to set the MSM directory to // the same directory as the standard windows folder and will add references to // custom action to all the standard sequence tables. A problem will occur // if the MSI does not have these tables as mergemod.dll does not add these // tables to the MSI if absent. This code adds the tables in case mergemod.dll // needs them. Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["CustomAction"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); break; // no need to look here any more, we already found all that we needed to } } break; case "DuplicateFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "DuplicateFiles"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveDuplicateFiles"]); break; case "EnsureTables": foreach (Row row in table.Rows) { ensureTableRows.Add(row); } break; case "Environment": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteEnvironmentStrings"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveEnvironmentStrings"]); break; case "Extension": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterExtensionInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterExtensionInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterExtensionInfo"]); break; case "File": foreach (FileRow row in table.Rows) { // DiskId is not valid when creating a module, so set it to // 0 for all files to ensure proper sorting in the binder if (OutputType.Module == this.activeOutput.Type) { row.DiskId = 0; } // if we have an assembly, insert the MsiAssembly row and assembly actions if (FileAssemblyType.NotAnAssembly != row.AssemblyType) { string feature; if (OutputType.Module == output.Type) { feature = Guid.Empty.ToString("B"); } else { ConnectToFeature connect = componentsToFeatures[row.Component]; if (null == connect) { throw new WixMissingFeatureException(row.SourceLineNumbers, new FeatureBacklink(row.Component, FeatureBacklinkType.Assembly, row.File)); } feature = connect.PrimaryFeature; } OutputTable assemblyOutputTable = Common.EnsureOutputTable(output, this.tableDefinitions["MsiAssembly"]); Row assemblyRow = new Row(assemblyOutputTable.TableDefinition); assemblyRow[0] = row.Component; assemblyRow[1] = feature; assemblyRow[2] = row.AssemblyManifest; assemblyRow[3] = row.AssemblyApplication; assemblyRow[4] = Convert.ToInt32(row.AssemblyType); assemblyOutputTable.OutputRows.Add(new OutputRow(assemblyRow, this.sectionIdOnTuples ? section.Id : null)); requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiUnpublishAssemblies"]); } if (null == row.Source) // source to the file must be provided { this.OnMessage(WixErrors.FileSourceRequired(row.SourceLineNumbers, row.File)); } this.activeOutput.FileMediaInformationCollection.Add(new FileMediaInformation(row)); } requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallFiles"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFiles"]); break; case "Font": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterFonts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterFonts"]); break; case "IniFile": case "RemoveIniFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteIniValues"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveIniValues"]); break; case "IsolatedComponent": requiredActions.Add(this.standardActions[SequenceType.installExecute, "IsolateComponents"]); break; case "LaunchCondition": requiredActions.Add(this.standardActions[SequenceType.installExecute, "LaunchConditions"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "LaunchConditions"]); break; case "Media": foreach (MediaRow row in table.Rows) { this.activeOutput.MediaRows.Add(row); } copyRows = false; break; case "Merge": // just copy the rows to the output copyRows = true; break; case "MIME": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterMIMEInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterMIMEInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterMIMEInfo"]); break; case "ModuleSignature": if (OutputType.Module == this.activeOutput.Type) { foreach (Row row in table.Rows) { if (null != this.activeOutput.ModularizationGuid) { throw new ArgumentOutOfRangeException("Unexpected number of rows found in table", "ModuleSignature"); } this.activeOutput.ModularizationGuid = row[3].ToString(); } } break; case "ModuleSubstitution": containsModuleSubstitution = true; break; case "ModuleConfiguration": containsModuleConfiguration = true; break; case "MoveFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "MoveFiles"]); break; case "MsiAssembly": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiUnpublishAssemblies"]); break; case "ODBCDataSource": case "ODBCTranslator": case "ODBCDriver": requiredActions.Add(this.standardActions[SequenceType.installExecute, "SetODBCFolders"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallODBC"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveODBC"]); break; case "ProgId": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterProgIdInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterProgIdInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterProgIdInfo"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Extension"]); // Extension table is required with a ProgId table break; case "Property": foreach (PropertyRow row in table.Rows) { // if there is no value in the property, then it must be virtual if (null == row.Value || 0 == row.Value.Length) { row.IsUnreal = true; } if (row.Admin) { adminProperties[row.Id] = null; } if (row.Secure) { secureProperties[row.Id] = null; } if (row.Hidden) { hiddenProperties[row.Id] = null; } } break; case "PublishComponent": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "PublishComponents"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "PublishComponents"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnpublishComponents"]); break; case "Registry": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteRegistryValues"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveRegistryValues"]); break; case "RemoveFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFiles"]); break; case "SelfReg": requiredActions.Add(this.standardActions[SequenceType.installExecute, "SelfRegModules"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "SelfUnregModules"]); break; case "ServiceControl": requiredActions.Add(this.standardActions[SequenceType.installExecute, "StartServices"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "StopServices"]); break; case "ServiceInstall": requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallServices"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "DeleteServices"]); break; case "Shortcut": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "CreateShortcuts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "CreateShortcuts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveShortcuts"]); break; case "TypeLib": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterTypeLibraries"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterTypeLibraries"]); break; case "Upgrade": { requiredActions.Add(this.standardActions[SequenceType.installExecute, "FindRelatedProducts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MigrateFeatureStates"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "FindRelatedProducts"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "MigrateFeatureStates"]); foreach (UpgradeRow row in table.Rows) { // this should never happen because candle will make sure that all UpgradeVersion(s) have an ActionProperty...but still don't let it slide if (null == row.ActionProperty) { this.OnMessage(WixErrors.ExpectedAttribute(row.SourceLineNumbers, "UpgradeVersion", "ActionProperty")); } secureProperties[row.ActionProperty] = null; } break; } case "_SummaryInformation": // if we are processing a product, reach into the summary // information and pull out the bits that say if the layout // image is supposed to have long file names and is compressed if (OutputType.Product == output.Type) { foreach (Row row in table.Rows) { // we're looking for the "Word Count" property which happens to // be number 15 (and I thought the answer to the universe was 42, heh). if ("15" == row[0].ToString()) { output.LongFileNames = (0 == (Convert.ToInt32(row[1]) & 1)); output.Compressed = (2 == (Convert.ToInt32(row[1]) & 2)); break; // we're done looking for what we came looking for } } } break; } if (copyRows) { OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions[table.Name]); this.CopyTableRowsToOutputTable(table, outputTable, section.Id); } } } if (0 < ensureTableRows.Count) { foreach (Row row in ensureTableRows) { string tableId = (string)row[0]; TableDefinition tableDef = null; try { tableDef = this.tableDefinitions[tableId]; } catch (WixMissingTableDefinitionException) { tableDef = customTableDefinitions[tableId]; } Common.EnsureOutputTable(this.activeOutput, tableDef); } } // copy all the suppress action rows to the output to suppress actions from merge modules if (0 < suppressActionRows.Count) { OutputTable suppressActionOutputTable = new OutputTable(this.tableDefinitions["SuppressAction"]); this.activeOutput.OutputTables.Add(suppressActionOutputTable); foreach (Row suppressActionRow in suppressActionRows) { suppressActionOutputTable.OutputRows.Add(new OutputRow(suppressActionRow)); } } foreach (Action suppressedAction in suppressedStandardActions.Values) { if (requiredActions.Contains(suppressedAction)) { // We thought they really ought to have a standard action // that they wanted to suppress, so warn them and remove it this.OnMessage(WixWarnings.SuppressAction(suppressedAction.Id, Action.SequenceTypeToString(suppressedAction.SequenceType))); requiredActions.Remove(suppressedAction); } } // check for missing table and add them or display an error as appropriate switch (this.activeOutput.Type) { case OutputType.Module: Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Component"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Directory"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["FeatureComponents"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["File"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleComponents"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleSignature"]); break; case OutputType.PatchCreation: OutputTable imageFamiliesTable = this.activeOutput.OutputTables["ImageFamilies"]; OutputTable targetImagesTable = this.activeOutput.OutputTables["TargetImages"]; OutputTable upgradedImagesTable = this.activeOutput.OutputTables["UpgradedImages"]; if (null == imageFamiliesTable || 1 > imageFamiliesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("ImageFamilies")); } if (null == targetImagesTable || 1 > targetImagesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("TargetImages")); } if (null == upgradedImagesTable || 1 > upgradedImagesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("UpgradedImages")); } Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Properties"]); break; case OutputType.Product: // AdminExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallFiles"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallAdminPackage"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallFinalize"]); // AdminUISequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "ExecuteAction"]); // AdvtExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "PublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "PublishProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallFinalize"]); // InstallExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "ValidateProductID"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "ProcessComponents"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "UnpublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "RegisterUser"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "RegisterProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "PublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "PublishProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallFinalize"]); // InstallUISequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "ValidateProductID"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "ExecuteAction"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["File"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Media"]); break; } // check for illegal tables foreach (OutputTable table in this.activeOutput.OutputTables) { switch (this.activeOutput.Type) { case OutputType.Module: if ("BBControl" == table.Name || "Billboard" == table.Name || "CCPSearch" == table.Name || "Feature" == table.Name || "LaunchCondition" == table.Name || "Media" == table.Name || "Merge" == table.Name || "Patch" == table.Name || "Upgrade" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixErrors.UnexpectedTableInMergeModule(outputRow.Row.SourceLineNumbers, table.Name)); } } else if ("Error" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixWarnings.DangerousTableInMergeModule(outputRow.Row.SourceLineNumbers, table.Name)); } } break; case OutputType.PatchCreation: if ("_SummaryInformation" != table.Name && "ExternalFiles" != table.Name && "FamilyFileRanges" != table.Name && "ImageFamilies" != table.Name && "PatchMetadata" != table.Name && "PatchSequence" != table.Name && "Properties" != table.Name && "TargetFiles_OptionalData" != table.Name && "TargetImages" != table.Name && "UpgradedFiles_OptionalData" != table.Name && "UpgradedFilesToIgnore" != table.Name && "UpgradedImages" != table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixErrors.UnexpectedTableInPatchCreationPackage(outputRow.Row.SourceLineNumbers, table.Name)); } } break; case OutputType.Product: if ("ModuleAdminExecuteSequence" == table.Name || "ModuleAdminUISequence" == table.Name || "ModuleAdvtExecuteSequence" == table.Name || "ModuleAdvtUISequence" == table.Name || "ModuleComponents" == table.Name || "ModuleConfiguration" == table.Name || "ModuleDependency" == table.Name || "ModuleExclusion" == table.Name || "ModuleIgnoreTable" == table.Name || "ModuleInstallExecuteSequence" == table.Name || "ModuleInstallUISequence" == table.Name || "ModuleSignature" == table.Name || "ModuleSubstitution" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixWarnings.UnexpectedTableInProduct(outputRow.Row.SourceLineNumbers, table.Name)); } } break; } } // add the custom row data foreach (Row row in customRows) { TableDefinition customTable = (TableDefinition)customTableDefinitions[row[0].ToString()]; string[] data = row[2].ToString().Split(tabCharacter); Row customRow = new Row(customTable); for (int i = 0; i < data.Length; ++i) { string[] item = data[i].Split(colonCharacter, 2); customRow.SetData(item[0], item[1]); } bool dataErrors = false; for (int i = 0; i < customTable.Columns.Count; ++i) { if (!customTable.Columns[i].IsNullable && customRow.IsColumnEmpty(i)) { this.OnMessage(WixErrors.NoDataForColumn(row.SourceLineNumbers, customTable.Columns[i].Name, customTable.Name)); dataErrors = true; } } if (!dataErrors) { OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, customTable); outputTable.OutputRows.Add(new OutputRow(customRow)); } } // update the special properties if (0 < adminProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "AdminProperties"; newRow[1] = GetPropertyListString(adminProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (0 < secureProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "SecureCustomProperties"; newRow[1] = GetPropertyListString(secureProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (0 < hiddenProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "MsiHiddenProperties"; newRow[1] = GetPropertyListString(hiddenProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (containsModuleSubstitution) { Row newRow = new Row(this.tableDefinitions["ModuleIgnoreTable"]); newRow[0] = "ModuleSubstitution"; OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleIgnoreTable"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (containsModuleConfiguration) { Row newRow = new Row(this.tableDefinitions["ModuleIgnoreTable"]); newRow[0] = "ModuleConfiguration"; OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleIgnoreTable"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } // process the actions foreach (Action action in requiredActions) { // skip actions in suppressed sequences if (suppressedSequenceTypes.Contains(action.SequenceType)) { continue; } if (OutputType.Product == this.activeOutput.Type) { this.ResolveActionSequence(action, requiredActions); } TableDefinition sequenceTableDef = null; bool module = OutputType.Module == this.activeOutput.Type; switch (action.SequenceType) { case SequenceType.adminExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdminExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["AdminExecuteSequence"]; } break; case SequenceType.adminUI: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdminUISequence"]; } else { sequenceTableDef = this.tableDefinitions["AdminUISequence"]; } break; case SequenceType.advertiseExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdvtExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["AdvtExecuteSequence"]; } break; case SequenceType.installExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleInstallExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["InstallExecuteSequence"]; } break; case SequenceType.installUI: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); sequenceTableDef = this.tableDefinitions["ModuleInstallUISequence"]; } else { sequenceTableDef = this.tableDefinitions["InstallUISequence"]; } break; } Row row = new Row(sequenceTableDef); if (module) { row[0] = action.Id; if (0 != action.SequenceNumber) { row[1] = action.SequenceNumber; } else { bool after = null == action.Before; row[2] = after ? action.After : action.Before; row[3] = after ? 1 : 0; } row[4] = action.Condition; } else // add the row to the sequence table { row[0] = action.Id; row[1] = action.Condition; row[2] = action.SequenceNumber; } OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, sequenceTableDef); outputTable.OutputRows.Add(new OutputRow(row)); } // set the suppressed action sequences if (this.suppressAdminSequence) { this.activeOutput.SuppressAdminSequence = true; } if (this.suppressAdvertiseSequence) { this.activeOutput.SuppressAdvertiseSequence = true; } if (this.suppressUISequence) { this.activeOutput.SuppressUISequence = true; } } finally { this.activeOutput = null; } return (this.foundError ? null : output); }
/// <summary> /// Creates a transform by diffing two outputs. /// </summary> /// <param name="targetOutput">The target output.</param> /// <param name="updatedOutput">The updated output.</param> /// <returns>The transform.</returns> public Output Diff(Output targetOutput, Output updatedOutput) { return(Diff(targetOutput, updatedOutput, 0)); }