public void AttachTransforms(ArrayList transforms) { InspectorCore inspectorCore = new InspectorCore(this.Message); // Track if at least one transform gets attached. bool attachedTransform = false; if (transforms == null || transforms.Count == 0) { throw new WixException(WixErrors.PatchWithoutTransforms()); } // Get the patch id from the WixPatchId table. string patchId = null; string clientPatchId = null; Table wixPatchIdTable = this.patch.Tables["WixPatchId"]; if (null != wixPatchIdTable && 0 < wixPatchIdTable.Rows.Count) { Row patchIdRow = wixPatchIdTable.Rows[0]; if (null != patchIdRow) { patchId = patchIdRow[0].ToString(); clientPatchId = patchIdRow[1].ToString(); } } if (null == patchId) { throw new WixException(WixErrors.ExpectedPatchIdInWixMsp()); } if (null == clientPatchId) { throw new WixException(WixErrors.ExpectedClientPatchIdInWixMsp()); } // enumerate patch.Media to map diskId to Media row Table patchMediaTable = patch.Tables["Media"]; if (null == patchMediaTable || patchMediaTable.Rows.Count == 0) { throw new WixException(WixErrors.ExpectedMediaRowsInWixMsp()); } Hashtable mediaRows = new Hashtable(patchMediaTable.Rows.Count); foreach (MediaRow row in patchMediaTable.Rows) { int media = row.DiskId; mediaRows[media] = row; } // enumerate patch.WixPatchBaseline to map baseline to diskId Table patchBaselineTable = patch.Tables["WixPatchBaseline"]; int numPatchBaselineRows = (null != patchBaselineTable) ? patchBaselineTable.Rows.Count : 0; Hashtable baselineMedia = new Hashtable(numPatchBaselineRows); if (patchBaselineTable != null) { foreach (Row row in patchBaselineTable.Rows) { string baseline = (string)row[0]; int media = (int)row[1]; int validationFlags = (int)row[2]; if (baselineMedia.Contains(baseline)) { this.OnMessage(WixErrors.SamePatchBaselineId(row.SourceLineNumbers, baseline)); } baselineMedia[baseline] = new int[] { media, validationFlags }; } } // populate MSP summary information Table patchSummaryInfo = patch.EnsureTable(this.tableDefinitions["_SummaryInformation"]); // Remove properties that will be calculated or are reserved. for (int i = patchSummaryInfo.Rows.Count - 1; i >= 0; i--) { Row row = patchSummaryInfo.Rows[i]; switch ((SummaryInformation.Patch)row[0]) { case SummaryInformation.Patch.ProductCodes: case SummaryInformation.Patch.TransformNames: case SummaryInformation.Patch.PatchCode: case SummaryInformation.Patch.InstallerRequirement: case SummaryInformation.Patch.Reserved11: case SummaryInformation.Patch.Reserved14: case SummaryInformation.Patch.Reserved16: patchSummaryInfo.Rows.RemoveAt(i); break; } } // Index remaining summary properties. SummaryInfoRowCollection summaryInfo = new SummaryInfoRowCollection(patchSummaryInfo); // PID_CODEPAGE if (!summaryInfo.Contains((int)SummaryInformation.Patch.CodePage)) { // set the code page by default to the same code page for the // string pool in the database. Row codePage = patchSummaryInfo.CreateRow(null); codePage[0] = (int)SummaryInformation.Patch.CodePage; codePage[1] = this.patch.Codepage.ToString(CultureInfo.InvariantCulture); } // GUID patch code for the patch. Row revisionRow = patchSummaryInfo.CreateRow(null); revisionRow[0] = (int)SummaryInformation.Patch.PatchCode; revisionRow[1] = patchId; // Indicates the minimum Windows Installer version that is required to install the patch. Row wordsRow = patchSummaryInfo.CreateRow(null); wordsRow[0] = (int)SummaryInformation.Patch.InstallerRequirement; wordsRow[1] = ((int)SummaryInformation.InstallerRequirement.Version31).ToString(CultureInfo.InvariantCulture); if (!summaryInfo.Contains((int)SummaryInformation.Patch.Security)) { Row security = patchSummaryInfo.CreateRow(null); security[0] = (int)SummaryInformation.Patch.Security; security[1] = "4"; // Read-only enforced } // use authored comments or default to DisplayName (required) string comments = null; Table msiPatchMetadataTable = patch.Tables["MsiPatchMetadata"]; Hashtable metadataTable = new Hashtable(); if (null != msiPatchMetadataTable) { foreach (Row row in msiPatchMetadataTable.Rows) { metadataTable.Add(row.Fields[1].Data.ToString(), row.Fields[2].Data.ToString()); } if (!summaryInfo.Contains((int)SummaryInformation.Patch.Title) && metadataTable.Contains("DisplayName")) { string displayName = (string)metadataTable["DisplayName"]; Row title = patchSummaryInfo.CreateRow(null); title[0] = (int)SummaryInformation.Patch.Title; title[1] = displayName; // default comments use DisplayName as-is (no loc) comments = displayName; } if (!summaryInfo.Contains((int)SummaryInformation.Patch.CodePage) && metadataTable.Contains("CodePage")) { Row codePage = patchSummaryInfo.CreateRow(null); codePage[0] = (int)SummaryInformation.Patch.CodePage; codePage[1] = metadataTable["CodePage"]; } if (!summaryInfo.Contains((int)SummaryInformation.Patch.PackageName) && metadataTable.Contains("Description")) { Row subject = patchSummaryInfo.CreateRow(null); subject[0] = (int)SummaryInformation.Patch.PackageName; subject[1] = metadataTable["Description"]; } if (!summaryInfo.Contains((int)SummaryInformation.Patch.Manufacturer) && metadataTable.Contains("ManufacturerName")) { Row author = patchSummaryInfo.CreateRow(null); author[0] = (int)SummaryInformation.Patch.Manufacturer; author[1] = metadataTable["ManufacturerName"]; } } // special metadata marshalled through the build Table wixPatchMetadataTable = patch.Tables["WixPatchMetadata"]; Hashtable wixMetadataTable = new Hashtable(); if (null != wixPatchMetadataTable) { foreach (Row row in wixPatchMetadataTable.Rows) { wixMetadataTable.Add(row.Fields[0].Data.ToString(), row.Fields[1].Data.ToString()); } if (wixMetadataTable.Contains("Comments")) { comments = (string)wixMetadataTable["Comments"]; } } // write the package comments to summary info if (!summaryInfo.Contains((int)SummaryInformation.Patch.Comments) && null != comments) { Row commentsRow = patchSummaryInfo.CreateRow(null); commentsRow[0] = (int)SummaryInformation.Patch.Comments; commentsRow[1] = comments; } // enumerate transforms Dictionary<string, object> productCodes = new Dictionary<string, object>(); ArrayList transformNames = new ArrayList(); ArrayList validTransform = new ArrayList(); int transformCount = 0; foreach (PatchTransform mainTransform in transforms) { string baseline = null; int media = -1; int validationFlags = 0; if (baselineMedia.Contains(mainTransform.Baseline)) { int[] baselineData = (int[])baselineMedia[mainTransform.Baseline]; int newMedia = baselineData[0]; if (media != -1 && media != newMedia) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_TransformAuthoredIntoMultipleMedia, media, newMedia)); } baseline = mainTransform.Baseline; media = newMedia; validationFlags = baselineData[1]; } if (media == -1) { // transform's baseline not attached to any Media continue; } Table patchRefTable = patch.Tables["WixPatchRef"]; if (patchRefTable != null && patchRefTable.Rows.Count > 0) { if (!Patch.ReduceTransform(mainTransform.Transform, patchRefTable)) { // transform has none of the content authored into this patch continue; } } // Validate the transform doesn't break any patch specific rules. mainTransform.Validate(); // ensure consistent File.Sequence within each Media MediaRow mediaRow = (MediaRow)mediaRows[media]; // Ensure that files are sequenced after the last file in any transform. Table transformMediaTable = mainTransform.Transform.Tables["Media"]; if (null != transformMediaTable && 0 < transformMediaTable.Rows.Count) { foreach (MediaRow transformMediaRow in transformMediaTable.Rows) { if (mediaRow.LastSequence < transformMediaRow.LastSequence) { // The Binder will pre-increment the sequence. mediaRow.LastSequence = transformMediaRow.LastSequence; } } } // Use the Media/@DiskId if greater for backward compatibility. if (mediaRow.LastSequence < mediaRow.DiskId) { mediaRow.LastSequence = mediaRow.DiskId; } // ignore media table from transform. mainTransform.Transform.Tables.Remove("Media"); mainTransform.Transform.Tables.Remove("WixMedia"); mainTransform.Transform.Tables.Remove("MsiDigitalSignature"); string productCode; Output pairedTransform = this.BuildPairedTransform(patchId, clientPatchId, mainTransform.Transform, mediaRow, validationFlags, out productCode); productCodes[productCode] = null; DictionaryEntry entry = new DictionaryEntry(); entry.Key = productCode; entry.Value = mainTransform.Transform; validTransform.Add(entry); // attach these transforms to the patch object // TODO: is this an acceptable way to auto-generate transform stream names? string transformName = baseline + "." + (++transformCount).ToString(CultureInfo.InvariantCulture); patch.SubStorages.Add(new SubStorage(transformName, mainTransform.Transform)); patch.SubStorages.Add(new SubStorage("#" + transformName, pairedTransform)); transformNames.Add(":" + transformName); transformNames.Add(":#" + transformName); attachedTransform = true; } if (!attachedTransform) { throw new WixException(WixErrors.PatchWithoutValidTransforms()); } // Validate that a patch authored as removable is actually removable if (metadataTable.Contains("AllowRemoval")) { if ("1" == metadataTable["AllowRemoval"].ToString()) { ArrayList tables = Patch.GetPatchUninstallBreakingTables(); bool result = true; foreach (DictionaryEntry entry in validTransform) { result &= this.CheckUninstallableTransform(entry.Key.ToString(), (Output)entry.Value, tables); } if (!result) { throw new WixException(WixErrors.PatchNotRemovable()); } } } // Finish filling tables with transform-dependent data. // Semicolon delimited list of the product codes that can accept the patch. Table wixPatchTargetTable = patch.Tables["WixPatchTarget"]; if (null != wixPatchTargetTable) { Dictionary<string, object> targets = new Dictionary<string, object>(); bool replace = true; foreach (Row wixPatchTargetRow in wixPatchTargetTable.Rows) { string target = wixPatchTargetRow[0].ToString(); if (0 == String.CompareOrdinal("*", target)) { replace = false; } else { targets[target] = null; } } // Replace the target ProductCodes with the authored list. if (replace) { productCodes = targets; } else { // Copy the authored target ProductCodes into the list. foreach (string target in targets.Keys) { productCodes[target] = null; } } } string[] uniqueProductCodes = new string[productCodes.Keys.Count]; productCodes.Keys.CopyTo(uniqueProductCodes, 0); Row templateRow = patchSummaryInfo.CreateRow(null); templateRow[0] = (int)SummaryInformation.Patch.ProductCodes; templateRow[1] = String.Join(";", uniqueProductCodes); // Semicolon delimited list of transform substorage names in the order they are applied. Row savedbyRow = patchSummaryInfo.CreateRow(null); savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames; savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string))); // inspect the patch and filtered transforms foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectPatch(this.patch); // reset inspectorExtension.Core = null; } }
public Intermediate Compile(XmlDocument source) { if (null == source) { throw new ArgumentNullException("source"); } bool encounteredError = false; // create the intermediate Intermediate target = new Intermediate(); // try to compile it try { this.core = new CompilerCore(target, this.tableDefinitions, this.extensions, this.Message, this.schema); this.core.ShowPedanticMessages = this.showPedanticMessages; this.core.CurrentPlatform = this.currentPlatform; this.core.FipsCompliant = this.fipsCompliant; foreach (CompilerExtension extension in this.extensions.Values) { extension.Core = this.core; extension.InitializeCompile(); } // parse the document SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(source.DocumentElement); if ("Wix" == source.DocumentElement.LocalName) { if (this.schema.TargetNamespace == source.DocumentElement.NamespaceURI) { this.ParseWixElement(source.DocumentElement); } else // invalid or missing namespace { if (0 == source.DocumentElement.NamespaceURI.Length) { this.core.OnMessage(WixErrors.InvalidWixXmlNamespace(sourceLineNumbers, "Wix", this.schema.TargetNamespace)); } else { this.core.OnMessage(WixErrors.InvalidWixXmlNamespace(sourceLineNumbers, "Wix", source.DocumentElement.NamespaceURI, this.schema.TargetNamespace)); } } } else { this.core.OnMessage(WixErrors.InvalidDocumentElement(sourceLineNumbers, source.DocumentElement.Name, "source", "Wix")); } // perform schema validation if there were no errors and validation isn't suppressed if (!this.core.EncounteredError && !this.suppressValidation) { this.ValidateDocument(source); } // inspect the document InspectorCore inspectorCore = new InspectorCore(this.Message); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectIntermediate(target); // reset inspectorExtension.Core = null; } if (inspectorCore.EncounteredError) { encounteredError = true; } } finally { if (this.core.EncounteredError) { encounteredError = true; } foreach (CompilerExtension extension in this.extensions.Values) { extension.FinalizeCompile(); extension.Core = null; } this.core = null; } // return the compiled intermediate only if it completed successfully return (encounteredError ? null : target); }
public XmlDocument Process(string sourceFile, Hashtable variables) { Stream processed = new MemoryStream(); XmlDocument sourceDocument = new XmlDocument(); try { this.core = new PreprocessorCore(this.extensionsByPrefix, this.Message, sourceFile, variables); this.core.ResolvedVariableHandler = this.ResolvedVariable; this.core.CurrentPlatform = this.currentPlatform; this.currentLineNumberWritten = false; this.currentLineNumber = new SourceLineNumber(sourceFile); this.currentFileStack.Clear(); this.currentFileStack.Push(this.core.GetVariableValue(this.GetCurrentSourceLineNumbers(), "sys", "SOURCEFILEDIR")); // open the source file for processing using (Stream sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { // inspect the raw source InspectorCore inspectorCore = new InspectorCore(this.Message); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectSource(sourceStream); // reset inspectorExtension.Core = null; sourceStream.Position = 0; } if (inspectorCore.EncounteredError) { return null; } XmlReader reader = new XmlTextReader(sourceStream); XmlTextWriter writer = new XmlTextWriter(processed, Encoding.UTF8); // process the reader into the writer try { foreach (PreprocessorExtension extension in this.extensions) { extension.Core = this.core; extension.InitializePreprocess(); } this.PreprocessReader(false, reader, writer, 0); } catch (XmlException e) { this.UpdateInformation(reader, 0); throw new WixException(WixErrors.InvalidXml(this.GetCurrentSourceLineNumbers(), "source", e.Message)); } writer.Flush(); } // fire event with processed stream ProcessedStreamEventArgs args = new ProcessedStreamEventArgs(sourceFile, processed); this.OnProcessedStream(args); // create an XML Document from the post-processed memory stream XmlTextReader xmlReader = null; try { // create an XmlReader with the path to the original file // to properly set the BaseURI property of the XmlDocument processed.Position = 0; xmlReader = new XmlTextReader(new Uri(Path.GetFullPath(sourceFile)).AbsoluteUri, processed); sourceDocument.Load(xmlReader); } catch (XmlException e) { this.UpdateInformation(xmlReader, 0); throw new WixException(WixErrors.InvalidXml(this.GetCurrentSourceLineNumbers(), "source", e.Message)); } finally { if (null != xmlReader) { xmlReader.Close(); } } // preprocess the generated XML Document foreach (PreprocessorExtension extension in this.extensions) { extension.PreprocessDocument(sourceDocument); } } finally { // finalize the preprocessing foreach (PreprocessorExtension extension in this.extensions) { extension.FinalizePreprocess(); extension.Core = null; } } if (this.core.EncounteredError) { return null; } else { if (null != this.preprocessOut) { sourceDocument.Save(this.preprocessOut); this.preprocessOut.Flush(); } return sourceDocument; } }
/// <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; }
public Output Link(SectionCollection sections, ArrayList transforms, OutputType expectedOutputType) { Output output = null; try { SymbolCollection allSymbols; Section entrySection; bool containsModuleSubstitution = false; bool containsModuleConfiguration = false; StringCollection referencedSymbols = new StringCollection(); ArrayList unresolvedReferences = new ArrayList(); ConnectToFeatureCollection componentsToFeatures = new ConnectToFeatureCollection(); ConnectToFeatureCollection featuresToFeatures = new ConnectToFeatureCollection(); ConnectToFeatureCollection modulesToFeatures = new ConnectToFeatureCollection(); this.activeOutput = null; this.encounteredError = false; SortedList adminProperties = new SortedList(); SortedList secureProperties = new SortedList(); SortedList hiddenProperties = new SortedList(); RowCollection actionRows = new RowCollection(); RowCollection suppressActionRows = new RowCollection(); TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection(); RowCollection customRows = new RowCollection(); StringCollection generatedShortFileNameIdentifiers = new StringCollection(); Hashtable generatedShortFileNames = new Hashtable(); Hashtable multipleFeatureComponents = new Hashtable(); Hashtable wixVariables = new Hashtable(); // verify that modularization types match for foreign key relationships foreach (TableDefinition tableDefinition in this.tableDefinitions) { foreach (ColumnDefinition columnDefinition in tableDefinition.Columns) { if (null != columnDefinition.KeyTable && 0 > columnDefinition.KeyTable.IndexOf(';') && columnDefinition.IsKeyColumnSet) { try { TableDefinition keyTableDefinition = this.tableDefinitions[columnDefinition.KeyTable]; if (0 >= columnDefinition.KeyColumn || keyTableDefinition.Columns.Count < columnDefinition.KeyColumn) { this.OnMessage(WixErrors.InvalidKeyColumn(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn)); } else if (keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType != columnDefinition.ModularizeType && ColumnModularizeType.CompanionFile != columnDefinition.ModularizeType) { this.OnMessage(WixErrors.CollidingModularizationTypes(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn, columnDefinition.ModularizeType.ToString(), keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType.ToString())); } } catch (WixMissingTableDefinitionException) { // ignore missing table definitions - this error is caught in other places } } } } // add in the extension sections foreach (WixExtension extension in this.extensions) { Library library = extension.GetLibrary(this.tableDefinitions); if (null != library) { sections.AddRange(library.Sections); } } // first find the entry section and create the symbols hash for all the sections sections.FindEntrySectionAndLoadSymbols(this.allowIdenticalRows, this, expectedOutputType, out entrySection, out allSymbols); // should have found an entry section by now if (null == entrySection) { throw new WixException(WixErrors.MissingEntrySection(expectedOutputType.ToString())); } // add the missing standard action symbols this.LoadStandardActionSymbols(allSymbols); // now that we know where we're starting from, create the output object output = new Output(null); output.EntrySection = entrySection; // Note: this entry section will get added to the Output.Sections collection later if (null != this.localizer && -1 != this.localizer.Codepage) { output.Codepage = this.localizer.Codepage; } this.activeOutput = output; // Resolve the symbol references to find the set of sections we // care about for linking. Of course, we start with the entry // section (that's how it got its name after all). output.Sections.AddRange(output.EntrySection.ResolveReferences(output.Type, allSymbols, referencedSymbols, unresolvedReferences, this)); // Flattening the complex references that participate in groups. this.FlattenSectionsComplexReferences(output.Sections); if (this.encounteredError) { return null; } // The hard part in linking is processing the complex references. this.ProcessComplexReferences(output, output.Sections, referencedSymbols, componentsToFeatures, featuresToFeatures, modulesToFeatures); for (int i = 0; i < unresolvedReferences.Count; ++i) { Section.SimpleReferenceSection referenceSection = (Section.SimpleReferenceSection)unresolvedReferences[i]; if (this.allowUnresolvedReferences) { this.OnMessage(WixWarnings.UnresolvedReferenceWarning(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName)); } else { this.OnMessage(WixErrors.UnresolvedReference(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName)); } } if (this.encounteredError) { return null; } SymbolCollection unreferencedSymbols = output.Sections.GetOrphanedSymbols(referencedSymbols, this); // Display a warning message for Components that were never referenced by a Feature. foreach (Symbol symbol in unreferencedSymbols) { if ("Component" == symbol.Row.Table.Name) { this.OnMessage(WixErrors.OrphanedComponent(symbol.Row.SourceLineNumbers, (string)symbol.Row[0])); } } Dictionary<string, List<Symbol>> duplicatedSymbols = output.Sections.GetDuplicateSymbols(this); // Display a warning message for Components that were never referenced by a Feature. foreach (List<Symbol> duplicatedSymbolList in duplicatedSymbols.Values) { Symbol symbol = duplicatedSymbolList[0]; // Certain tables allow duplicates because they allow overrides. if (symbol.Row.Table.Name != "WixAction" && symbol.Row.Table.Name != "WixVariable") { this.OnMessage(WixErrors.DuplicateSymbol(symbol.Row.SourceLineNumbers, symbol.Name)); for (int i = 1; i < duplicatedSymbolList.Count; i++) { Symbol duplicateSymbol = duplicatedSymbolList[i]; this.OnMessage(WixErrors.DuplicateSymbol2(duplicateSymbol.Row.SourceLineNumbers)); } } } if (this.encounteredError) { return null; } if (null != this.unreferencedSymbolsFile) { sections.GetOrphanedSymbols(referencedSymbols, this).OutputSymbols(this.unreferencedSymbolsFile); } // resolve the feature to feature connects this.ResolveFeatureToFeatureConnects(featuresToFeatures, allSymbols); // start generating OutputTables and OutputRows for all the sections in the output RowCollection ensureTableRows = new RowCollection(); int sectionCount = 0; foreach (Section section in output.Sections) { sectionCount++; string sectionId = section.Id; if (null == sectionId && this.sectionIdOnRows) { sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture); } foreach (Table table in section.Tables) { // By default, copy rows unless we've been asked to drop unreal tables from // the output and it's an unreal table and *not* a UX Manifest table. bool copyRows = true; if (this.dropUnrealTables && table.Definition.IsUnreal && !table.Definition.IsBootstrapperApplicationData) { copyRows = false; } // handle special tables switch (table.Name) { case "AppSearch": this.activeOutput.EnsureTable(this.tableDefinitions["Signature"]); break; case "Class": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 2, 11, componentsToFeatures, multipleFeatureComponents); } break; case "ChainPackage": case "ChainPackageGroup": case "MsiProperty": copyRows = true; break; case "CustomAction": if (OutputType.Module == this.activeOutput.Type) { this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]); } foreach (Row row in table.Rows) { // For script CAs that specify HideTarget we should also hide the CA data property for the action. int bits = Convert.ToInt32(row[1]); if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) && MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript)) { hiddenProperties[Convert.ToString(row[0])] = null; } } break; case "Dialog": this.activeOutput.EnsureTable(this.tableDefinitions["ListBox"]); break; case "Directory": foreach (Row row in table.Rows) { if (OutputType.Module == this.activeOutput.Type) { string directory = row[0].ToString(); if (Util.IsStandardDirectory(directory)) { // if the directory table contains references to standard windows folders // mergemod.dll will add customactions to set the MSM directory to // the same directory as the standard windows folder and will add references to // custom action to all the standard sequence tables. A problem will occur // if the MSI does not have these tables as mergemod.dll does not add these // tables to the MSI if absent. This code adds the tables in case mergemod.dll // needs them. this.activeOutput.EnsureTable(this.tableDefinitions["CustomAction"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]); this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]); } else { foreach (string standardDirectory in Util.StandardDirectories.Keys) { if (directory.StartsWith(standardDirectory, StringComparison.Ordinal)) { this.OnMessage(WixWarnings.StandardDirectoryConflictInMergeModule(row.SourceLineNumbers, directory, standardDirectory)); } } } } } break; case "Extension": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 1, 4, componentsToFeatures, multipleFeatureComponents); } break; case "ModuleSubstitution": containsModuleSubstitution = true; break; case "ModuleConfiguration": containsModuleConfiguration = true; break; case "MsiAssembly": if (this.suppressMsiAssemblyTable) { copyRows = false; } else if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 0, 1, componentsToFeatures, multipleFeatureComponents); } break; case "ProgId": // the Extension table is required with a ProgId table this.activeOutput.EnsureTable(this.tableDefinitions["Extension"]); break; case "Property": for (int i = 0; i < table.Rows.Count; i++) { if (null == table.Rows[i][1]) { table.Rows.RemoveAt(i); i--; } } break; case "PublishComponent": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 2, 4, componentsToFeatures, multipleFeatureComponents); } break; case "Shortcut": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 3, 4, componentsToFeatures, multipleFeatureComponents); } break; case "TypeLib": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 2, 6, componentsToFeatures, multipleFeatureComponents); } break; case "Upgrade": foreach (UpgradeRow row in table.Rows) { secureProperties[row.ActionProperty] = null; } break; case "Variable": copyRows = true; break; case "WixAction": if (this.sectionIdOnRows) { foreach (Row row in table.Rows) { row.SectionId = sectionId; } } actionRows.AddRange(table.Rows); break; case "WixBBControl": case "WixControl": copyRows = true; break; case "WixCustomTable": this.LinkCustomTable(table, customTableDefinitions); copyRows = false; // we've created table definitions from these rows, no need to process them any longer break; case "WixCustomRow": foreach (Row row in table.Rows) { row.SectionId = (this.sectionIdOnRows ? sectionId : null); customRows.Add(row); } copyRows = false; break; case "WixEnsureTable": ensureTableRows.AddRange(table.Rows); break; case "WixFile": foreach (Row row in table.Rows) { // DiskId is not valid when creating a module, so set it to // 0 for all files to ensure proper sorting in the binder if (OutputType.Module == this.activeOutput.Type) { row[5] = 0; } // if the short file name was generated, check for collisions if (0x1 == (int)row[9]) { generatedShortFileNameIdentifiers.Add((string)row[0]); } } copyRows = true; break; case "WixFragment": copyRows = true; break; case "WixGroup": copyRows = true; break; case "WixInstanceTransforms": copyRows = true; break; case "WixMedia": copyRows = true; break; case "WixMerge": if (OutputType.Product == output.Type) { this.ResolveFeatures(table.Rows, 0, 7, modulesToFeatures, null); } copyRows = true; break; case "WixOrdering": copyRows = true; break; case "WixProperty": foreach (WixPropertyRow wixPropertyRow in table.Rows) { if (wixPropertyRow.Admin) { adminProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Hidden) { hiddenProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Secure) { secureProperties[wixPropertyRow.Id] = null; } } break; case "WixSuppressAction": suppressActionRows.AddRange(table.Rows); break; case "WixSuppressModularization": // just copy the rows to the output copyRows = true; break; case "WixVariable": // check for colliding values and collect the wix variable rows foreach (WixVariableRow row in table.Rows) { WixVariableRow collidingRow = (WixVariableRow)wixVariables[row.Id]; if (null == collidingRow || (collidingRow.Overridable && !row.Overridable)) { wixVariables[row.Id] = row; } else if (!row.Overridable || (collidingRow.Overridable && row.Overridable)) { this.OnMessage(WixErrors.WixVariableCollision(row.SourceLineNumbers, row.Id)); } } copyRows = false; break; case "WixPatchRef": case "WixPatchBaseline": case "WixPatchId": copyRows = true; break; } if (copyRows) { Table outputTable = this.activeOutput.EnsureTable(this.tableDefinitions[table.Name]); this.CopyTableRowsToOutputTable(table, outputTable, sectionId); } } } // Verify that there were no duplicate fragment Id's. Table wixFragmentTable = this.activeOutput.Tables["WixFragment"]; Hashtable fragmentIdIndex = new Hashtable(); if (null != wixFragmentTable) { foreach (Row row in wixFragmentTable.Rows) { string fragmentId = row.Fields[0].Data.ToString(); if (!fragmentIdIndex.ContainsKey(fragmentId)) { fragmentIdIndex.Add(fragmentId, row.SourceLineNumbers); } else { this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, fragmentId)); if (null != fragmentIdIndex[fragmentId]) { this.OnMessage(WixErrors.DuplicateSymbol2((SourceLineNumberCollection)fragmentIdIndex[fragmentId])); } } } } // copy the module to feature connections into the output if (0 < modulesToFeatures.Count) { Table wixFeatureModulesTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixFeatureModules"]); foreach (ConnectToFeature connectToFeature in modulesToFeatures) { foreach (string feature in connectToFeature.ConnectFeatures) { Row row = wixFeatureModulesTable.CreateRow(null); row[0] = feature; row[1] = connectToFeature.ChildId; } } } // ensure the creation of tables that need to exist if (0 < ensureTableRows.Count) { foreach (Row row in ensureTableRows) { string tableId = (string)row[0]; TableDefinition tableDef = null; try { tableDef = this.tableDefinitions[tableId]; } catch (WixMissingTableDefinitionException) { tableDef = customTableDefinitions[tableId]; } this.activeOutput.EnsureTable(tableDef); } } // copy all the suppress action rows to the output to suppress actions from merge modules if (0 < suppressActionRows.Count) { Table suppressActionTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixSuppressAction"]); suppressActionTable.Rows.AddRange(suppressActionRows); } // sequence all the actions this.SequenceActions(actionRows, suppressActionRows); // check for missing table and add them or display an error as appropriate switch (this.activeOutput.Type) { case OutputType.Module: this.activeOutput.EnsureTable(this.tableDefinitions["Component"]); this.activeOutput.EnsureTable(this.tableDefinitions["Directory"]); this.activeOutput.EnsureTable(this.tableDefinitions["FeatureComponents"]); this.activeOutput.EnsureTable(this.tableDefinitions["File"]); this.activeOutput.EnsureTable(this.tableDefinitions["ModuleComponents"]); this.activeOutput.EnsureTable(this.tableDefinitions["ModuleSignature"]); break; case OutputType.PatchCreation: Table imageFamiliesTable = this.activeOutput.Tables["ImageFamilies"]; Table targetImagesTable = this.activeOutput.Tables["TargetImages"]; Table upgradedImagesTable = this.activeOutput.Tables["UpgradedImages"]; if (null == imageFamiliesTable || 1 > imageFamiliesTable.Rows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("ImageFamilies")); } if (null == targetImagesTable || 1 > targetImagesTable.Rows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("TargetImages")); } if (null == upgradedImagesTable || 1 > upgradedImagesTable.Rows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("UpgradedImages")); } this.activeOutput.EnsureTable(this.tableDefinitions["Properties"]); break; case OutputType.Product: this.activeOutput.EnsureTable(this.tableDefinitions["File"]); this.activeOutput.EnsureTable(this.tableDefinitions["Media"]); break; } this.CheckForIllegalTables(this.activeOutput); // add the custom row data foreach (Row row in customRows) { TableDefinition customTableDefinition = (TableDefinition)customTableDefinitions[row[0].ToString()]; Table customTable = this.activeOutput.EnsureTable(customTableDefinition); Row customRow = customTable.CreateRow(row.SourceLineNumbers); customRow.SectionId = row.SectionId; string[] data = row[1].ToString().Split(Common.CustomRowFieldSeparator); for (int i = 0; i < data.Length; ++i) { bool foundColumn = false; string[] item = data[i].Split(colonCharacter, 2); for (int j = 0; j < customRow.Fields.Length; ++j) { if (customRow.Fields[j].Column.Name == item[0]) { if (0 < item[1].Length) { if (ColumnType.Number == customRow.Fields[j].Column.Type) { try { customRow.Fields[j].Data = Convert.ToInt32(item[1], CultureInfo.InvariantCulture); } catch (FormatException) { this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1])); } catch (OverflowException) { this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1])); } } else if (ColumnCategory.Identifier == customRow.Fields[j].Column.Category) { if (CompilerCore.IsIdentifier(item[1]) || Common.IsValidBinderVariable(item[1]) || ColumnCategory.Formatted == customRow.Fields[j].Column.Category) { customRow.Fields[j].Data = item[1]; } else { this.OnMessage(WixErrors.IllegalIdentifier(row.SourceLineNumbers, "Data", item[1])); } } else { customRow.Fields[j].Data = item[1]; } } foundColumn = true; break; } } if (!foundColumn) { this.OnMessage(WixErrors.UnexpectedCustomTableColumn(row.SourceLineNumbers, item[0])); } } for (int i = 0; i < customTableDefinition.Columns.Count; ++i) { if (!customTableDefinition.Columns[i].IsNullable && (null == customRow.Fields[i].Data || 0 == customRow.Fields[i].Data.ToString().Length)) { this.OnMessage(WixErrors.NoDataForColumn(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name)); } } } //correct the section Id in FeatureComponents table if (this.sectionIdOnRows) { Hashtable componentSectionIds = new Hashtable(); Table componentTable = output.Tables["Component"]; if (null != componentTable) { foreach (Row componentRow in componentTable.Rows) { componentSectionIds.Add(componentRow.Fields[0].Data.ToString(), componentRow.SectionId); } } Table featureComponentsTable = output.Tables["FeatureComponents"]; if (null != featureComponentsTable) { foreach (Row featureComponentsRow in featureComponentsTable.Rows) { if (componentSectionIds.Contains(featureComponentsRow.Fields[1].Data.ToString())) { featureComponentsRow.SectionId = (string)componentSectionIds[featureComponentsRow.Fields[1].Data.ToString()]; } } } } // update the special properties if (0 < adminProperties.Count) { Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]); Row row = propertyTable.CreateRow(null); row[0] = "AdminProperties"; row[1] = GetPropertyListString(adminProperties); } if (0 < secureProperties.Count) { Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]); Row row = propertyTable.CreateRow(null); row[0] = "SecureCustomProperties"; row[1] = GetPropertyListString(secureProperties); } if (0 < hiddenProperties.Count) { Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]); Row row = propertyTable.CreateRow(null); row[0] = "MsiHiddenProperties"; row[1] = GetPropertyListString(hiddenProperties); } // add the ModuleSubstitution table to the ModuleIgnoreTable if (containsModuleSubstitution) { Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]); Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null); moduleIgnoreTableRow[0] = "ModuleSubstitution"; } // add the ModuleConfiguration table to the ModuleIgnoreTable if (containsModuleConfiguration) { Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]); Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null); moduleIgnoreTableRow[0] = "ModuleConfiguration"; } // index all the file rows FileRowCollection indexedFileRows = new FileRowCollection(); Table fileTable = this.activeOutput.Tables["File"]; if (null != fileTable) { indexedFileRows.AddRange(fileTable.Rows); } // flag all the generated short file name collisions foreach (string fileId in generatedShortFileNameIdentifiers) { FileRow fileRow = indexedFileRows[fileId]; string[] names = fileRow.FileName.Split('|'); string shortFileName = names[0]; // create lists of conflicting generated short file names if (!generatedShortFileNames.Contains(shortFileName)) { generatedShortFileNames.Add(shortFileName, new ArrayList()); } ((ArrayList)generatedShortFileNames[shortFileName]).Add(fileRow); } // check for generated short file name collisions foreach (DictionaryEntry entry in generatedShortFileNames) { string shortFileName = (string)entry.Key; ArrayList fileRows = (ArrayList)entry.Value; if (1 < fileRows.Count) { // sort the rows by DiskId fileRows.Sort(); this.OnMessage(WixWarnings.GeneratedShortFileNameConflict(((FileRow)fileRows[0]).SourceLineNumbers, shortFileName)); for (int i = 1; i < fileRows.Count; i++) { FileRow fileRow = (FileRow)fileRows[i]; if (null != fileRow.SourceLineNumbers) { this.OnMessage(WixWarnings.GeneratedShortFileNameConflict2(fileRow.SourceLineNumbers)); } } } } // copy the wix variable rows to the output after all overriding has been accounted for. if (0 < wixVariables.Count) { Table wixVariableTable = output.EnsureTable(this.tableDefinitions["WixVariable"]); foreach (WixVariableRow row in wixVariables.Values) { wixVariableTable.Rows.Add(row); } } // Bundles have groups of data that must be flattened in a way different from other types. this.FlattenBundleTables(output); if (this.encounteredError) { return null; } this.CheckOutputConsistency(output); // inspect the output InspectorCore inspectorCore = new InspectorCore(this.Message); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectOutput(output); // reset inspectorExtension.Core = null; } if (inspectorCore.EncounteredError) { this.encounteredError = true; } } finally { this.activeOutput = null; } return (this.encounteredError ? null : output); }
private bool BindDatabase(Output output, string databaseFile) { foreach (BinderExtension extension in this.extensions) { extension.DatabaseInitialize(output); } bool compressed = false; FileRowCollection fileRows = new FileRowCollection(OutputType.Patch == output.Type); bool longNames = false; MediaRowCollection mediaRows = new MediaRowCollection(); Hashtable suppressModularizationIdentifiers = null; StringCollection suppressedTableNames = new StringCollection(); Table propertyTable = output.Tables["Property"]; this.WriteBuildInfoTable(output, databaseFile); // gather all the wix variables Table wixVariableTable = output.Tables["WixVariable"]; if (null != wixVariableTable) { foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows) { this.WixVariableResolver.AddVariable(wixVariableRow); } } // gather all the suppress modularization identifiers Table wixSuppressModularizationTable = output.Tables["WixSuppressModularization"]; if (null != wixSuppressModularizationTable) { suppressModularizationIdentifiers = new Hashtable(wixSuppressModularizationTable.Rows.Count); foreach (Row row in wixSuppressModularizationTable.Rows) { suppressModularizationIdentifiers[row[0]] = null; } } // localize fields, resolve wix variables, and resolve file paths Hashtable cabinets = new Hashtable(); ArrayList delayedFields = new ArrayList(); this.ResolveFields(output.Tables, cabinets, delayedFields); // if there are any fields to resolve later, create the cache to populate during bind IDictionary<string, string> variableCache = null; if (0 < delayedFields.Count) { variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); } this.LocalizeUI(output.Tables); // process the summary information table before the other tables string modularizationGuid = this.BindDatabaseSummaryInfo(output, out longNames, out compressed); // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // modularize identifiers and add tables with real streams to the import tables if (OutputType.Module == output.Type) { foreach (Table table in output.Tables) { table.Modularize(modularizationGuid, suppressModularizationIdentifiers); } // Reset the special property lists after modularization. The linker creates these properties before modularization // so we have to reconstruct them for merge modules after modularization in the binder. Table wixPropertyTable = output.Tables["WixProperty"]; if (null != wixPropertyTable) { // Create lists of the properties that contribute to the special lists of properties. SortedList adminProperties = new SortedList(); SortedList secureProperties = new SortedList(); SortedList hiddenProperties = new SortedList(); foreach (WixPropertyRow wixPropertyRow in wixPropertyTable.Rows) { if (wixPropertyRow.Admin) { adminProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Hidden) { hiddenProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Secure) { secureProperties[wixPropertyRow.Id] = null; } } if (0 < adminProperties.Count || 0 < hiddenProperties.Count || 0 < secureProperties.Count) { Table table = output.Tables["Property"]; foreach (Row propertyRow in table.Rows) { if ("AdminProperties" == (string)propertyRow[0]) { propertyRow[1] = GetPropertyListString(adminProperties); } if ("MsiHiddenProperties" == (string)propertyRow[0]) { propertyRow[1] = GetPropertyListString(hiddenProperties); } if ("SecureCustomProperties" == (string)propertyRow[0]) { propertyRow[1] = GetPropertyListString(secureProperties); } } } } } // merge unreal table data into the real tables // this must occur after all variables and source paths have been resolved this.MergeUnrealTables(output.Tables); if (this.core.EncounteredError) { return false; } if (OutputType.Patch == output.Type) { foreach (SubStorage substorage in output.SubStorages) { Output transform = (Output)substorage.Data; this.ResolveFields(transform.Tables, cabinets, null); this.MergeUnrealTables(transform.Tables); } } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // index the File table for quicker access later // this must occur after the unreal data has been merged in Table fileTable = output.Tables["File"]; if (null != fileTable) { fileRows.AddRange(fileTable.Rows); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // add binder variables for all properties propertyTable = output.Tables["Property"]; if (null != propertyTable) { foreach (Row propertyRow in propertyTable.Rows) { string property = propertyRow[0].ToString(); // set the ProductCode if its generated if (OutputType.Product == output.Type && "ProductCode" == property && "*" == propertyRow[1].ToString()) { propertyRow[1] = Common.GenerateGuid(); // Update the target ProductCode in any instance transforms foreach (SubStorage subStorage in output.SubStorages) { Output subStorageOutput = (Output)subStorage.Data; if (OutputType.Transform != subStorageOutput.Type) { continue; } Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; foreach (Row row in instanceSummaryInformationTable.Rows) { if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0]) { row[1] = ((string)row[1]).Replace("*", (string)propertyRow[1]); break; } } } } // add the property name and value to the variableCache if (0 != delayedFields.Count) { string key = String.Concat("property.", Demodularize(output, modularizationGuid, property)); variableCache[key] = (string)propertyRow[1]; } } } // extract files that come from cabinet files (this does not extract files from merge modules) this.ExtractCabinets(cabinets); // retrieve files and their information from merge modules if (OutputType.Product == output.Type) { this.ProcessMergeModules(output, fileRows); } else if (OutputType.Patch == output.Type) { // merge transform data into the output object this.CopyTransformData(output, fileRows); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // assign files to media AutoMediaAssigner autoMediaAssigner = new AutoMediaAssigner(output, this.core, compressed); autoMediaAssigner.AssignFiles(fileRows); // update file version, hash, assembly, etc.. information this.core.OnMessage(WixVerboses.UpdatingFileInformation()); Hashtable indexedFileRows = this.UpdateFileInformation(output, fileRows, autoMediaAssigner.MediaRows, variableCache, modularizationGuid); // set generated component guids this.SetComponentGuids(output); // With the Component Guids set now we can create instance transforms. this.CreateInstanceTransforms(output); this.ValidateComponentGuids(output); this.UpdateControlText(output); if (0 < delayedFields.Count) { this.ResolveDelayedFields(output, delayedFields, variableCache, modularizationGuid); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // Extended binder extensions can be called now that fields are resolved. foreach (BinderExtension extension in this.extensions) { BinderExtensionEx extensionEx = extension as BinderExtensionEx; if (null != extensionEx) { output.EnsureTable(this.core.TableDefinitions["WixBindUpdatedFiles"]); extensionEx.DatabaseAfterResolvedFields(output); } } Table updatedFiles = output.Tables["WixBindUpdatedFiles"]; if (null != updatedFiles) { foreach (Row updatedFile in updatedFiles.Rows) { FileRow updatedFileRow = (FileRow)indexedFileRows[updatedFile[0]]; this.UpdateFileRow(output, null, modularizationGuid, indexedFileRows, updatedFileRow, true); } } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // create cabinet files and process uncompressed files string layoutDirectory = Path.GetDirectoryName(databaseFile); FileRowCollection uncompressedFileRows = null; if (!this.suppressLayout || OutputType.Module == output.Type) { this.core.OnMessage(WixVerboses.CreatingCabinetFiles()); uncompressedFileRows = this.CreateCabinetFiles(output, fileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, autoMediaAssigner); } if (OutputType.Patch == output.Type) { // copy output data back into the transforms this.CopyTransformData(output, null); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // add back suppressed tables which must be present prior to merging in modules if (OutputType.Product == output.Type) { Table wixMergeTable = output.Tables["WixMerge"]; if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count) { foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) { string sequenceTableName = sequence.ToString(); Table sequenceTable = output.Tables[sequenceTableName]; if (null == sequenceTable) { sequenceTable = output.EnsureTable(this.core.TableDefinitions[sequenceTableName]); } if (0 == sequenceTable.Rows.Count) { suppressedTableNames.Add(sequenceTableName); } } } } foreach (BinderExtension extension in this.extensions) { extension.DatabaseFinalize(output); } // generate database file this.core.OnMessage(WixVerboses.GeneratingDatabase()); string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(databaseFile)); this.GenerateDatabase(output, tempDatabaseFile, false, false); FileTransfer transfer; if (FileTransfer.TryCreate(tempDatabaseFile, databaseFile, true, output.Type.ToString(), null, out transfer)) // note where this database needs to move in the future { transfer.Built = true; this.fileTransfers.Add(transfer); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // Output the output to a file if (null != this.pdbFile) { Pdb pdb = new Pdb(null); pdb.Output = output; pdb.Save(this.pdbFile, null, this.WixVariableResolver, this.TempFilesLocation); } // merge modules if (OutputType.Product == output.Type) { this.core.OnMessage(WixVerboses.MergingModules()); this.MergeModules(tempDatabaseFile, output, fileRows, suppressedTableNames); // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } } // inspect the MSI prior to running ICEs InspectorCore inspectorCore = new InspectorCore(this.MessageHandler); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectDatabase(tempDatabaseFile, output); // reset inspectorExtension.Core = null; } if (inspectorCore.EncounteredError) { return false; } // validate the output if there is an MSI validator if (null != this.validator) { Stopwatch stopwatch = Stopwatch.StartNew(); // set the output file for source line information this.validator.Output = output; this.core.OnMessage(WixVerboses.ValidatingDatabase()); this.core.EncounteredError = !this.validator.Validate(tempDatabaseFile); stopwatch.Stop(); this.core.OnMessage(WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } } // process uncompressed files if (!this.suppressLayout) { this.ProcessUncompressedFiles(tempDatabaseFile, uncompressedFileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, longNames); } // layout media try { this.core.OnMessage(WixVerboses.LayingOutMedia()); this.LayoutMedia(this.fileTransfers, this.suppressAclReset); } finally { if (!String.IsNullOrEmpty(this.contentsFile)) { this.CreateContentsFile(this.contentsFile, fileRows); } if (!String.IsNullOrEmpty(this.outputsFile)) { this.CreateOutputsFile(this.outputsFile, this.fileTransfers, this.pdbFile); } if (!String.IsNullOrEmpty(this.builtOutputsFile)) { this.CreateBuiltOutputsFile(this.builtOutputsFile, this.fileTransfers, this.pdbFile); } } return !this.core.EncounteredError; }
/// <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); }