From dbde9e7104b907bbbaea17e21247d8cafc8b3a4c Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sat, 14 Oct 2017 16:12:07 -0700 Subject: Massive refactoring to introduce the concept of IBackend --- .../Bind/Databases/AssignMediaCommand.cs | 314 ----------- .../Bind/Databases/BindSummaryInfoCommand.cs | 135 ----- .../Bind/Databases/CabinetBuilder.cs | 176 ------ .../Bind/Databases/CabinetWorkItem.cs | 78 --- .../Bind/Databases/ConfigurationCallback.cs | 91 ---- .../Bind/Databases/CopyTransformDataCommand.cs | 606 --------------------- .../Bind/Databases/CreateCabinetsCommand.cs | 489 ----------------- .../Bind/Databases/CreateDeltaPatchesCommand.cs | 86 --- .../Databases/CreateSpecialPropertiesCommand.cs | 68 --- .../Databases/ExtractMergeModuleFilesCommand.cs | 225 -------- src/WixToolset.Core/Bind/Databases/FileFacade.cs | 44 -- .../Bind/Databases/GetFileFacadesCommand.cs | 148 ----- .../Bind/Databases/MergeModulesCommand.cs | 350 ------------ .../Databases/ProcessUncompressedFilesCommand.cs | 115 ---- .../Bind/Databases/UpdateControlTextCommand.cs | 80 --- .../Bind/Databases/UpdateFileFacadesCommand.cs | 532 ------------------ 16 files changed, 3537 deletions(-) delete mode 100644 src/WixToolset.Core/Bind/Databases/AssignMediaCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/BindSummaryInfoCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/CabinetBuilder.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/CabinetWorkItem.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/ConfigurationCallback.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/CopyTransformDataCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/CreateCabinetsCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/CreateDeltaPatchesCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/CreateSpecialPropertiesCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/FileFacade.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/GetFileFacadesCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/ProcessUncompressedFilesCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/UpdateControlTextCommand.cs delete mode 100644 src/WixToolset.Core/Bind/Databases/UpdateFileFacadesCommand.cs (limited to 'src/WixToolset.Core/Bind/Databases') diff --git a/src/WixToolset.Core/Bind/Databases/AssignMediaCommand.cs b/src/WixToolset.Core/Bind/Databases/AssignMediaCommand.cs deleted file mode 100644 index 5e2650e9..00000000 --- a/src/WixToolset.Core/Bind/Databases/AssignMediaCommand.cs +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using WixToolset.Data; - using WixToolset.Data.Rows; - - /// - /// AssignMediaCommand assigns files to cabs based on Media or MediaTemplate rows. - /// - public class AssignMediaCommand : ICommand - { - public AssignMediaCommand() - { - this.CabinetNameTemplate = "Cab{0}.cab"; - } - - public Output Output { private get; set; } - - public bool FilesCompressed { private get; set; } - - public string CabinetNameTemplate { private get; set; } - - public IEnumerable FileFacades { private get; set; } - - public TableDefinitionCollection TableDefinitions { private get; set; } - - /// - /// Gets cabinets with their file rows. - /// - public Dictionary> FileFacadesByCabinetMedia { get; private set; } - - /// - /// Get media rows. - /// - public RowDictionary MediaRows { get; private set; } - - /// - /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. - /// This contains all the files when Package element is marked with compression=no - /// - public IEnumerable UncompressedFileFacades { get; private set; } - - public void Execute() - { - Dictionary> filesByCabinetMedia = new Dictionary>(); - - RowDictionary mediaRows = new RowDictionary(); - - List uncompressedFiles = new List(); - - MediaRow mergeModuleMediaRow = null; - Table mediaTable = this.Output.Tables["Media"]; - Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"]; - - // If both tables are authored, it is an error. - if ((mediaTemplateTable != null && mediaTemplateTable.Rows.Count > 0) && (mediaTable != null && mediaTable.Rows.Count > 1)) - { - throw new WixException(WixErrors.MediaTableCollision(null)); - } - - // When building merge module, all the files go to "#MergeModule.CABinet". - if (OutputType.Module == this.Output.Type) - { - Table mergeModuleMediaTable = new Table(null, this.TableDefinitions["Media"]); - mergeModuleMediaRow = (MediaRow)mergeModuleMediaTable.CreateRow(null); - mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet"; - - filesByCabinetMedia.Add(mergeModuleMediaRow, new List()); - } - - if (OutputType.Module == this.Output.Type || null == mediaTemplateTable) - { - this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); - } - else - { - this.AutoAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); - } - - this.FileFacadesByCabinetMedia = new Dictionary>(); - - foreach (var mediaRowWithFiles in filesByCabinetMedia) - { - this.FileFacadesByCabinetMedia.Add(mediaRowWithFiles.Key, mediaRowWithFiles.Value); - } - - this.MediaRows = mediaRows; - - this.UncompressedFileFacades = uncompressedFiles; - } - - /// - /// Assign files to cabinets based on MediaTemplate authoring. - /// - /// FileRowCollection - private void AutoAssignFiles(Table mediaTable, IEnumerable fileFacades, Dictionary> filesByCabinetMedia, RowDictionary mediaRows, List uncompressedFiles) - { - const int MaxCabIndex = 999; - - ulong currentPreCabSize = 0; - ulong maxPreCabSizeInBytes; - int maxPreCabSizeInMB = 0; - int currentCabIndex = 0; - - MediaRow currentMediaRow = null; - - Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"]; - - // Auto assign files to cabinets based on maximum uncompressed media size - mediaTable.Rows.Clear(); - WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0]; - - if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate)) - { - this.CabinetNameTemplate = mediaTemplateRow.CabinetTemplate; - } - - string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS"); - - try - { - // Override authored mums value if environment variable is authored. - if (!String.IsNullOrEmpty(mumsString)) - { - maxPreCabSizeInMB = Int32.Parse(mumsString); - } - else - { - maxPreCabSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize; - } - - maxPreCabSizeInBytes = (ulong)maxPreCabSizeInMB * 1024 * 1024; - } - catch (FormatException) - { - throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString)); - } - catch (OverflowException) - { - throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB)); - } - - foreach (FileFacade facade in this.FileFacades) - { - // When building a product, if the current file is not to be compressed or if - // the package set not to be compressed, don't cab it. - if (OutputType.Product == this.Output.Type && - (YesNoType.No == facade.File.Compressed || - (YesNoType.NotSet == facade.File.Compressed && !this.FilesCompressed))) - { - uncompressedFiles.Add(facade); - continue; - } - - if (currentCabIndex == MaxCabIndex) - { - // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore. - List cabinetFiles = filesByCabinetMedia[currentMediaRow]; - facade.WixFile.DiskId = currentCabIndex; - cabinetFiles.Add(facade); - continue; - } - - // Update current cab size. - currentPreCabSize += (ulong)facade.File.FileSize; - - if (currentPreCabSize > maxPreCabSizeInBytes) - { - // Overflow due to current file - currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex); - mediaRows.Add(currentMediaRow); - filesByCabinetMedia.Add(currentMediaRow, new List()); - - List cabinetFileRows = filesByCabinetMedia[currentMediaRow]; - facade.WixFile.DiskId = currentCabIndex; - cabinetFileRows.Add(facade); - // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize - currentPreCabSize = (ulong)facade.File.FileSize; - } - else - { - // File fits in the current cab. - if (currentMediaRow == null) - { - // Create new cab and MediaRow - currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex); - mediaRows.Add(currentMediaRow); - filesByCabinetMedia.Add(currentMediaRow, new List()); - } - - // Associate current file with current cab. - List cabinetFiles = filesByCabinetMedia[currentMediaRow]; - facade.WixFile.DiskId = currentCabIndex; - cabinetFiles.Add(facade); - } - } - - // If there are uncompressed files and no MediaRow, create a default one. - if (uncompressedFiles.Count > 0 && mediaTable.Rows.Count == 0) - { - MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null); - defaultMediaRow.DiskId = 1; - mediaRows.Add(defaultMediaRow); - } - } - - /// - /// Assign files to cabinets based on Media authoring. - /// - /// - /// - /// - private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, IEnumerable fileFacades, Dictionary> filesByCabinetMedia, RowDictionary mediaRows, List uncompressedFiles) - { - if (OutputType.Module != this.Output.Type) - { - if (null != mediaTable) - { - Dictionary cabinetMediaRows = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (MediaRow mediaRow in mediaTable.Rows) - { - // If the Media row has a cabinet, make sure it is unique across all Media rows. - if (!String.IsNullOrEmpty(mediaRow.Cabinet)) - { - MediaRow existingRow; - if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow)) - { - Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); - Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); - } - else - { - cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow); - } - } - - mediaRows.Add(mediaRow); - } - } - - foreach (MediaRow mediaRow in mediaRows.Values) - { - if (null != mediaRow.Cabinet) - { - filesByCabinetMedia.Add(mediaRow, new List()); - } - } - } - - foreach (FileFacade facade in fileFacades) - { - if (OutputType.Module == this.Output.Type) - { - filesByCabinetMedia[mergeModuleMediaRow].Add(facade); - } - else - { - MediaRow mediaRow; - if (!mediaRows.TryGetValue(facade.WixFile.DiskId.ToString(CultureInfo.InvariantCulture), out mediaRow)) - { - Messaging.Instance.OnMessage(WixErrors.MissingMedia(facade.File.SourceLineNumbers, facade.WixFile.DiskId)); - continue; - } - - // When building a product, if the current file is not to be compressed or if - // the package set not to be compressed, don't cab it. - if (OutputType.Product == this.Output.Type && - (YesNoType.No == facade.File.Compressed || - (YesNoType.NotSet == facade.File.Compressed && !this.FilesCompressed))) - { - uncompressedFiles.Add(facade); - } - else // file is marked compressed. - { - List cabinetFiles; - if (filesByCabinetMedia.TryGetValue(mediaRow, out cabinetFiles)) - { - cabinetFiles.Add(facade); - } - else - { - Messaging.Instance.OnMessage(WixErrors.ExpectedMediaCabinet(facade.File.SourceLineNumbers, facade.File.File, facade.WixFile.DiskId)); - } - } - } - } - } - - /// - /// Adds a row to the media table with cab name template filled in. - /// - /// - /// - /// - private MediaRow AddMediaRow(WixMediaTemplateRow mediaTemplateRow, Table mediaTable, int cabIndex) - { - MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers); - currentMediaRow.DiskId = cabIndex; - currentMediaRow.Cabinet = String.Format(CultureInfo.InvariantCulture, this.CabinetNameTemplate, cabIndex); - - Table wixMediaTable = this.Output.EnsureTable(this.TableDefinitions["WixMedia"]); - WixMediaRow row = (WixMediaRow)wixMediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers); - row.DiskId = cabIndex; - row.CompressionLevel = mediaTemplateRow.CompressionLevel; - - return currentMediaRow; - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/BindSummaryInfoCommand.cs b/src/WixToolset.Core/Bind/Databases/BindSummaryInfoCommand.cs deleted file mode 100644 index 95bd4cf0..00000000 --- a/src/WixToolset.Core/Bind/Databases/BindSummaryInfoCommand.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Globalization; - using WixToolset.Data; - - /// - /// Binds the summary information table of a database. - /// - internal class BindSummaryInfoCommand : ICommand - { - /// - /// The output to bind. - /// - public Output Output { private get; set; } - - /// - /// Returns a flag indicating if files are compressed by default. - /// - public bool Compressed { get; private set; } - - /// - /// Returns a flag indicating if uncompressed files use long filenames. - /// - public bool LongNames { get; private set; } - - public int InstallerVersion { get; private set; } - - /// - /// Modularization guid, or null if the output is not a module. - /// - public string ModularizationGuid { get; private set; } - - public void Execute() - { - this.Compressed = false; - this.LongNames = false; - this.InstallerVersion = 0; - this.ModularizationGuid = null; - - Table summaryInformationTable = this.Output.Tables["_SummaryInformation"]; - - if (null != summaryInformationTable) - { - bool foundCreateDataTime = false; - bool foundLastSaveDataTime = false; - bool foundCreatingApplication = false; - string now = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture); - - foreach (Row summaryInformationRow in summaryInformationTable.Rows) - { - switch (summaryInformationRow.FieldAsInteger(0)) - { - case 1: // PID_CODEPAGE - // make sure the code page is an int and not a web name or null - string codepage = summaryInformationRow.FieldAsString(1); - - if (null == codepage) - { - codepage = "0"; - } - else - { - summaryInformationRow[1] = Common.GetValidCodePage(codepage, false, false, summaryInformationRow.SourceLineNumbers).ToString(CultureInfo.InvariantCulture); - } - break; - case 9: // PID_REVNUMBER - string packageCode = (string)summaryInformationRow[1]; - - if (OutputType.Module == this.Output.Type) - { - this.ModularizationGuid = packageCode.Substring(1, 36).Replace('-', '_'); - } - else if ("*" == packageCode) - { - // set the revision number (package/patch code) if it should be automatically generated - summaryInformationRow[1] = Common.GenerateGuid(); - } - break; - case 12: // PID_CREATE_DTM - foundCreateDataTime = true; - break; - case 13: // PID_LASTSAVE_DTM - foundLastSaveDataTime = true; - break; - case 14: - this.InstallerVersion = summaryInformationRow.FieldAsInteger(1); - break; - case 15: // PID_WORDCOUNT - if (OutputType.Patch == this.Output.Type) - { - this.LongNames = true; - this.Compressed = true; - } - else - { - this.LongNames = (0 == (summaryInformationRow.FieldAsInteger(1) & 1)); - this.Compressed = (2 == (summaryInformationRow.FieldAsInteger(1) & 2)); - } - break; - case 18: // PID_APPNAME - foundCreatingApplication = true; - break; - } - } - - // add a summary information row for the create time/date property if its not already set - if (!foundCreateDataTime) - { - Row createTimeDateRow = summaryInformationTable.CreateRow(null); - createTimeDateRow[0] = 12; - createTimeDateRow[1] = now; - } - - // add a summary information row for the last save time/date property if its not already set - if (!foundLastSaveDataTime) - { - Row lastSaveTimeDateRow = summaryInformationTable.CreateRow(null); - lastSaveTimeDateRow[0] = 13; - lastSaveTimeDateRow[1] = now; - } - - // add a summary information row for the creating application property if its not already set - if (!foundCreatingApplication) - { - Row creatingApplicationRow = summaryInformationTable.CreateRow(null); - creatingApplicationRow[0] = 18; - creatingApplicationRow[1] = String.Format(CultureInfo.InvariantCulture, AppCommon.GetCreatingApplicationString()); - } - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/CabinetBuilder.cs b/src/WixToolset.Core/Bind/Databases/CabinetBuilder.cs deleted file mode 100644 index 2de6ec25..00000000 --- a/src/WixToolset.Core/Bind/Databases/CabinetBuilder.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections; - using System.IO; - using System.Linq; - using System.Threading; - using WixToolset.Cab; - using WixToolset.Data; - using WixToolset.Data.Rows; - - /// - /// Builds cabinets using multiple threads. This implements a thread pool that generates cabinets with multiple - /// threads. Unlike System.Threading.ThreadPool, it waits until all threads are finished. - /// - internal sealed class CabinetBuilder - { - private Queue cabinetWorkItems; - private object lockObject; - private int threadCount; - - // Address of Binder's callback function for Cabinet Splitting - private IntPtr newCabNamesCallBackAddress; - - public int MaximumCabinetSizeForLargeFileSplitting { get; set; } - public int MaximumUncompressedMediaSize { get; set; } - - /// - /// Instantiate a new CabinetBuilder. - /// - /// number of threads to use - /// Address of Binder's callback function for Cabinet Splitting - public CabinetBuilder(int threadCount, IntPtr newCabNamesCallBackAddress) - { - if (0 >= threadCount) - { - throw new ArgumentOutOfRangeException("threadCount"); - } - - this.cabinetWorkItems = new Queue(); - this.lockObject = new object(); - - this.threadCount = threadCount; - - // Set Address of Binder's callback function for Cabinet Splitting - this.newCabNamesCallBackAddress = newCabNamesCallBackAddress; - } - - /// - /// Enqueues a CabinetWorkItem to the queue. - /// - /// cabinet work item - public void Enqueue(CabinetWorkItem cabinetWorkItem) - { - this.cabinetWorkItems.Enqueue(cabinetWorkItem); - } - - /// - /// Create the queued cabinets. - /// - /// error message number (zero if no error) - public void CreateQueuedCabinets() - { - // don't create more threads than the number of cabinets to build - if (this.cabinetWorkItems.Count < this.threadCount) - { - this.threadCount = this.cabinetWorkItems.Count; - } - - if (0 < this.threadCount) - { - Thread[] threads = new Thread[this.threadCount]; - - for (int i = 0; i < threads.Length; i++) - { - threads[i] = new Thread(new ThreadStart(this.ProcessWorkItems)); - threads[i].Start(); - } - - // wait for all threads to finish - foreach (Thread thread in threads) - { - thread.Join(); - } - } - } - - /// - /// This function gets called by multiple threads to do actual work. - /// It takes one work item at a time and calls this.CreateCabinet(). - /// It does not return until cabinetWorkItems queue is empty - /// - private void ProcessWorkItems() - { - try - { - while (true) - { - CabinetWorkItem cabinetWorkItem; - - lock (this.cabinetWorkItems) - { - // check if there are any more cabinets to create - if (0 == this.cabinetWorkItems.Count) - { - break; - } - - cabinetWorkItem = (CabinetWorkItem)this.cabinetWorkItems.Dequeue(); - } - - // create a cabinet - this.CreateCabinet(cabinetWorkItem); - } - } - catch (WixException we) - { - Messaging.Instance.OnMessage(we.Error); - } - catch (Exception e) - { - Messaging.Instance.OnMessage(WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); - } - } - - /// - /// Creates a cabinet using the wixcab.dll interop layer. - /// - /// CabinetWorkItem containing information about the cabinet to create. - private void CreateCabinet(CabinetWorkItem cabinetWorkItem) - { - Messaging.Instance.OnMessage(WixVerboses.CreateCabinet(cabinetWorkItem.CabinetFile)); - - int maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting - ulong maxPreCompressedSizeInBytes = 0; - - if (MaximumCabinetSizeForLargeFileSplitting != 0) - { - // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize - // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file - if (1 == cabinetWorkItem.FileFacades.Count()) - { - // Cabinet has Single File, Check if this is Large File than needs Splitting into Multiple cabs - // Get the Value for Max Uncompressed Media Size - maxPreCompressedSizeInBytes = (ulong)MaximumUncompressedMediaSize * 1024 * 1024; - - foreach (FileFacade facade in cabinetWorkItem.FileFacades) // No other easy way than looping to get the only row - { - if ((ulong)facade.File.FileSize >= maxPreCompressedSizeInBytes) - { - // If file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting - maxCabinetSize = MaximumCabinetSizeForLargeFileSplitting; - } - } - } - } - - // create the cabinet file - string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); - string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); - - using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, cabinetWorkItem.FileFacades.Count(), maxCabinetSize, cabinetWorkItem.MaxThreshold, cabinetWorkItem.CompressionLevel)) - { - foreach (FileFacade facade in cabinetWorkItem.FileFacades) - { - cab.AddFile(facade); - } - - cab.Complete(newCabNamesCallBackAddress); - } - } - } -} - diff --git a/src/WixToolset.Core/Bind/Databases/CabinetWorkItem.cs b/src/WixToolset.Core/Bind/Databases/CabinetWorkItem.cs deleted file mode 100644 index 20241bc9..00000000 --- a/src/WixToolset.Core/Bind/Databases/CabinetWorkItem.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System.Collections.Generic; - using WixToolset.Data; - using WixToolset.Data.Rows; - - /// - /// A cabinet builder work item. - /// - internal sealed class CabinetWorkItem - { - private string cabinetFile; - private CompressionLevel compressionLevel; - //private BinderFileManager binderFileManager; - private int maxThreshold; - - /// - /// Instantiate a new CabinetWorkItem. - /// - /// The collection of files in this cabinet. - /// The cabinet file. - /// Maximum threshold for each cabinet. - /// The compression level of the cabinet. - /// The binder file manager. - public CabinetWorkItem(IEnumerable fileFacades, string cabinetFile, int maxThreshold, CompressionLevel compressionLevel /*, BinderFileManager binderFileManager*/) - { - this.cabinetFile = cabinetFile; - this.compressionLevel = compressionLevel; - this.FileFacades = fileFacades; - //this.binderFileManager = binderFileManager; - this.maxThreshold = maxThreshold; - } - - /// - /// Gets the cabinet file. - /// - /// The cabinet file. - public string CabinetFile - { - get { return this.cabinetFile; } - } - - /// - /// Gets the compression level of the cabinet. - /// - /// The compression level of the cabinet. - public CompressionLevel CompressionLevel - { - get { return this.compressionLevel; } - } - - /// - /// Gets the collection of files in this cabinet. - /// - /// The collection of files in this cabinet. - public IEnumerable FileFacades { get; private set; } - - /// - /// Gets the binder file manager. - /// - /// The binder file manager. - //public BinderFileManager BinderFileManager - //{ - // get { return this.binderFileManager; } - //} - - /// - /// Gets the max threshold. - /// - /// The maximum threshold for a folder in a cabinet. - public int MaxThreshold - { - get { return this.maxThreshold; } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/ConfigurationCallback.cs b/src/WixToolset.Core/Bind/Databases/ConfigurationCallback.cs deleted file mode 100644 index 7cb18e0f..00000000 --- a/src/WixToolset.Core/Bind/Databases/ConfigurationCallback.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections; - using System.Globalization; - using WixToolset.MergeMod; - - /// - /// Callback object for configurable merge modules. - /// - internal sealed class ConfigurationCallback : IMsmConfigureModule - { - private const int SOk = 0x0; - private const int SFalse = 0x1; - private Hashtable configurationData; - - /// - /// Creates a ConfigurationCallback object. - /// - /// String to break up into name/value pairs. - public ConfigurationCallback(string configData) - { - if (String.IsNullOrEmpty(configData)) - { - throw new ArgumentNullException("configData"); - } - - string[] pairs = configData.Split(','); - this.configurationData = new Hashtable(pairs.Length); - for (int i = 0; i < pairs.Length; ++i) - { - string[] nameVal = pairs[i].Split('='); - string name = nameVal[0]; - string value = nameVal[1]; - - name = name.Replace("%2C", ","); - name = name.Replace("%3D", "="); - name = name.Replace("%25", "%"); - - value = value.Replace("%2C", ","); - value = value.Replace("%3D", "="); - value = value.Replace("%25", "%"); - - this.configurationData[name] = value; - } - } - - /// - /// Returns text data based on name. - /// - /// Name of value to return. - /// Out param to put configuration data into. - /// S_OK if value provided, S_FALSE if not. - public int ProvideTextData(string name, out string configData) - { - if (this.configurationData.Contains(name)) - { - configData = (string)this.configurationData[name]; - return SOk; - } - else - { - configData = null; - return SFalse; - } - } - - /// - /// Returns integer data based on name. - /// - /// Name of value to return. - /// Out param to put configuration data into. - /// S_OK if value provided, S_FALSE if not. - public int ProvideIntegerData(string name, out int configData) - { - if (this.configurationData.Contains(name)) - { - string val = (string)this.configurationData[name]; - configData = Convert.ToInt32(val, CultureInfo.InvariantCulture); - return SOk; - } - else - { - configData = 0; - return SFalse; - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/CopyTransformDataCommand.cs b/src/WixToolset.Core/Bind/Databases/CopyTransformDataCommand.cs deleted file mode 100644 index af1ab3b0..00000000 --- a/src/WixToolset.Core/Bind/Databases/CopyTransformDataCommand.cs +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using WixToolset.Data; - using WixToolset.Data.Rows; - using WixToolset.Extensibility; - using WixToolset.Core.Native; - - internal class CopyTransformDataCommand : ICommand - { - public bool CopyOutFileRows { private get; set; } - - public BinderFileManagerCore FileManagerCore { private get; set; } - - public IEnumerable FileManagers { private get; set; } - - public Output Output { private get; set; } - - public TableDefinitionCollection TableDefinitions { private get; set; } - - public IEnumerable FileFacades { get; private set; } - - public void Execute() - { - Debug.Assert(OutputType.Patch != this.Output.Type); - - List allFileRows = this.CopyOutFileRows ? new List() : null; - -#if false // TODO: Fix this patching related code to work correctly with FileFacades. - bool copyToPatch = (allFileRows != null); - bool copyFromPatch = !copyToPatch; - - RowDictionary patchMediaRows = new RowDictionary(); - - Dictionary> patchMediaFileRows = new Dictionary>(); - - Table patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]); - Table patchFileTable = this.Output.EnsureTable(this.TableDefinitions["WixFile"]); - - if (copyFromPatch) - { - // index patch files by diskId+fileId - foreach (WixFileRow patchFileRow in patchFileTable.Rows) - { - int diskId = patchFileRow.DiskId; - RowDictionary mediaFileRows; - if (!patchMediaFileRows.TryGetValue(diskId, out mediaFileRows)) - { - mediaFileRows = new RowDictionary(); - patchMediaFileRows.Add(diskId, mediaFileRows); - } - - mediaFileRows.Add(patchFileRow); - } - - Table patchMediaTable = this.Output.EnsureTable(this.TableDefinitions["Media"]); - patchMediaRows = new RowDictionary(patchMediaTable); - } - - // index paired transforms - Dictionary pairedTransforms = new Dictionary(); - foreach (SubStorage substorage in this.Output.SubStorages) - { - if (substorage.Name.StartsWith("#")) - { - pairedTransforms.Add(substorage.Name.Substring(1), substorage.Data); - } - } - - try - { - // copy File bind data into substorages - foreach (SubStorage substorage in this.Output.SubStorages) - { - if (substorage.Name.StartsWith("#")) - { - // no changes necessary for paired transforms - continue; - } - - Output mainTransform = substorage.Data; - Table mainWixFileTable = mainTransform.Tables["WixFile"]; - Table mainMsiFileHashTable = mainTransform.Tables["MsiFileHash"]; - - this.FileManagerCore.ActiveSubStorage = substorage; - - RowDictionary mainWixFiles = new RowDictionary(mainWixFileTable); - RowDictionary mainMsiFileHashIndex = new RowDictionary(); - - Table mainFileTable = mainTransform.Tables["File"]; - Output pairedTransform = (Output)pairedTransforms[substorage.Name]; - - // copy Media.LastSequence and index the MsiFileHash table if it exists. - if (copyFromPatch) - { - Table pairedMediaTable = pairedTransform.Tables["Media"]; - foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows) - { - MediaRow patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId); - pairedMediaRow.Fields[1] = patchMediaRow.Fields[1]; - } - - if (null != mainMsiFileHashTable) - { - mainMsiFileHashIndex = new RowDictionary(mainMsiFileHashTable); - } - - // Validate file row changes for keypath-related issues - this.ValidateFileRowChanges(mainTransform); - } - - // Index File table of pairedTransform - Table pairedFileTable = pairedTransform.Tables["File"]; - RowDictionary pairedFileRows = new RowDictionary(pairedFileTable); - - if (null != mainFileTable) - { - if (copyFromPatch) - { - // Remove the MsiFileHash table because it will be updated later with the final file hash for each file - mainTransform.Tables.Remove("MsiFileHash"); - } - - foreach (FileRow mainFileRow in mainFileTable.Rows) - { - if (RowOperation.Delete == mainFileRow.Operation) - { - continue; - } - else if (RowOperation.None == mainFileRow.Operation && !copyToPatch) - { - continue; - } - - WixFileRow mainWixFileRow = mainWixFiles.Get(mainFileRow.File); - - if (copyToPatch) // when copying to the patch, we need compare the underlying files and include all file changes. - { - ObjectField objectField = (ObjectField)mainWixFileRow.Fields[6]; - FileRow pairedFileRow = pairedFileRows.Get(mainFileRow.File); - - // If the file is new, we always need to add it to the patch. - if (mainFileRow.Operation != RowOperation.Add) - { - // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare. - if (null == objectField.PreviousData) - { - if (mainFileRow.Operation == RowOperation.None) - { - continue; - } - } - else - { - // TODO: should this entire condition be placed in the binder file manager? - if ((0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) && - !this.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString())) - { - // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified. - mainFileRow.Operation = RowOperation.Modify; - if (null != pairedFileRow) - { - // Always patch-added, but never non-compressed. - pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded; - pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; - pairedFileRow.Fields[6].Modified = true; - pairedFileRow.Operation = RowOperation.Modify; - } - } - else - { - // The File is same. We need mark all the attributes as unchanged. - mainFileRow.Operation = RowOperation.None; - foreach (Field field in mainFileRow.Fields) - { - field.Modified = false; - } - - if (null != pairedFileRow) - { - pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesPatchAdded; - pairedFileRow.Fields[6].Modified = false; - pairedFileRow.Operation = RowOperation.None; - } - continue; - } - } - } - else if (null != pairedFileRow) // RowOperation.Add - { - // Always patch-added, but never non-compressed. - pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded; - pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; - pairedFileRow.Fields[6].Modified = true; - pairedFileRow.Operation = RowOperation.Add; - } - } - - // index patch files by diskId+fileId - int diskId = mainWixFileRow.DiskId; - - RowDictionary mediaFileRows; - if (!patchMediaFileRows.TryGetValue(diskId, out mediaFileRows)) - { - mediaFileRows = new RowDictionary(); - patchMediaFileRows.Add(diskId, mediaFileRows); - } - - string fileId = mainFileRow.File; - WixFileRow patchFileRow = mediaFileRows.Get(fileId); - if (copyToPatch) - { - if (null == patchFileRow) - { - FileRow patchActualFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers); - patchActualFileRow.CopyFrom(mainFileRow); - - patchFileRow = (WixFileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers); - patchFileRow.CopyFrom(mainWixFileRow); - - mediaFileRows.Add(patchFileRow); - - allFileRows.Add(new FileFacade(patchActualFileRow, patchFileRow, null)); // TODO: should we be passing along delta information? Probably, right? - } - else - { - // TODO: confirm the rest of data is identical? - - // make sure Source is same. Otherwise we are silently ignoring a file. - if (0 != String.Compare(patchFileRow.Source, mainWixFileRow.Source, StringComparison.OrdinalIgnoreCase)) - { - Messaging.Instance.OnMessage(WixErrors.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, fileId, patchFileRow.Source, mainWixFileRow.Source)); - } - - // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow. - patchFileRow.AppendPreviousDataFrom(mainWixFileRow); - } - } - else - { - // copy data from the patch back to the transform - if (null != patchFileRow) - { - FileRow pairedFileRow = (FileRow)pairedFileRows.Get(fileId); - for (int i = 0; i < patchFileRow.Fields.Length; i++) - { - string patchValue = patchFileRow[i] == null ? "" : patchFileRow[i].ToString(); - string mainValue = mainFileRow[i] == null ? "" : mainFileRow[i].ToString(); - - if (1 == i) - { - // File.Component_ changes should not come from the shared file rows - // that contain the file information as each individual transform might - // have different changes (or no changes at all). - } - // File.Attributes should not changed for binary deltas - else if (6 == i) - { - if (null != patchFileRow.Patch) - { - // File.Attribute should not change for binary deltas - pairedFileRow.Attributes = mainFileRow.Attributes; - mainFileRow.Fields[i].Modified = false; - } - } - // File.Sequence is updated in pairedTransform, not mainTransform - else if (7 == i) - { - // file sequence is updated in Patch table instead of File table for delta patches - if (null != patchFileRow.Patch) - { - pairedFileRow.Fields[i].Modified = false; - } - else - { - pairedFileRow[i] = patchFileRow[i]; - pairedFileRow.Fields[i].Modified = true; - } - mainFileRow.Fields[i].Modified = false; - } - else if (patchValue != mainValue) - { - mainFileRow[i] = patchFileRow[i]; - mainFileRow.Fields[i].Modified = true; - if (mainFileRow.Operation == RowOperation.None) - { - mainFileRow.Operation = RowOperation.Modify; - } - } - } - - // copy MsiFileHash row for this File - Row patchHashRow; - if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out patchHashRow)) - { - patchHashRow = patchFileRow.Hash; - } - - if (null != patchHashRow) - { - Table mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]); - Row mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers); - for (int i = 0; i < patchHashRow.Fields.Length; i++) - { - mainHashRow[i] = patchHashRow[i]; - if (i > 1) - { - // assume all hash fields have been modified - mainHashRow.Fields[i].Modified = true; - } - } - - // assume the MsiFileHash operation follows the File one - mainHashRow.Operation = mainFileRow.Operation; - } - - // copy MsiAssemblyName rows for this File - List patchAssemblyNameRows = patchFileRow.AssemblyNames; - if (null != patchAssemblyNameRows) - { - Table mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); - foreach (Row patchAssemblyNameRow in patchAssemblyNameRows) - { - // Copy if there isn't an identical modified/added row already in the transform. - bool foundMatchingModifiedRow = false; - foreach (Row mainAssemblyNameRow in mainAssemblyNameTable.Rows) - { - if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/'))) - { - foundMatchingModifiedRow = true; - break; - } - } - - if (!foundMatchingModifiedRow) - { - Row mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers); - for (int i = 0; i < patchAssemblyNameRow.Fields.Length; i++) - { - mainAssemblyNameRow[i] = patchAssemblyNameRow[i]; - } - - // assume value field has been modified - mainAssemblyNameRow.Fields[2].Modified = true; - mainAssemblyNameRow.Operation = mainFileRow.Operation; - } - } - } - - // Add patch header for this file - if (null != patchFileRow.Patch) - { - // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables. - AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow); - AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow); - - // Add to Patch table - Table patchTable = pairedTransform.EnsureTable(this.TableDefinitions["Patch"]); - if (0 == patchTable.Rows.Count) - { - patchTable.Operation = TableOperation.Add; - } - - Row patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers); - patchRow[0] = patchFileRow.File; - patchRow[1] = patchFileRow.Sequence; - - FileInfo patchFile = new FileInfo(patchFileRow.Source); - patchRow[2] = (int)patchFile.Length; - patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1; - - string streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1]; - if (MsiInterop.MsiMaxStreamNameLength < streamName.Length) - { - streamName = "_" + Guid.NewGuid().ToString("D").ToUpperInvariant().Replace('-', '_'); - Table patchHeadersTable = pairedTransform.EnsureTable(this.TableDefinitions["MsiPatchHeaders"]); - if (0 == patchHeadersTable.Rows.Count) - { - patchHeadersTable.Operation = TableOperation.Add; - } - Row patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers); - patchHeadersRow[0] = streamName; - patchHeadersRow[1] = patchFileRow.Patch; - patchRow[5] = streamName; - patchHeadersRow.Operation = RowOperation.Add; - } - else - { - patchRow[4] = patchFileRow.Patch; - } - patchRow.Operation = RowOperation.Add; - } - } - else - { - // TODO: throw because all transform rows should have made it into the patch - } - } - } - } - - if (copyFromPatch) - { - this.Output.Tables.Remove("Media"); - this.Output.Tables.Remove("File"); - this.Output.Tables.Remove("MsiFileHash"); - this.Output.Tables.Remove("MsiAssemblyName"); - } - } - } - finally - { - this.FileManagerCore.ActiveSubStorage = null; - } -#endif - this.FileFacades = allFileRows; - } - - /// - /// Adds the PatchFiles action to the sequence table if it does not already exist. - /// - /// The sequence table to check or modify. - /// The primary authoring transform. - /// The secondary patch transform. - /// The file row that contains information about the patched file. - private void AddPatchFilesActionToSequenceTable(SequenceTable table, Output mainTransform, Output pairedTransform, Row mainFileRow) - { - // Find/add PatchFiles action (also determine sequence for it). - // Search mainTransform first, then pairedTransform (pairedTransform overrides). - bool hasPatchFilesAction = false; - int seqInstallFiles = 0; - int seqDuplicateFiles = 0; - string tableName = table.ToString(); - - TestSequenceTableForPatchFilesAction( - mainTransform.Tables[tableName], - ref hasPatchFilesAction, - ref seqInstallFiles, - ref seqDuplicateFiles); - TestSequenceTableForPatchFilesAction( - pairedTransform.Tables[tableName], - ref hasPatchFilesAction, - ref seqInstallFiles, - ref seqDuplicateFiles); - if (!hasPatchFilesAction) - { - Table iesTable = pairedTransform.EnsureTable(this.TableDefinitions[tableName]); - if (0 == iesTable.Rows.Count) - { - iesTable.Operation = TableOperation.Add; - } - - Row patchAction = iesTable.CreateRow(null); - WixActionRow wixPatchAction = WindowsInstallerStandard.GetStandardActions()[table, "PatchFiles"]; - int sequence = wixPatchAction.Sequence; - // Test for default sequence value's appropriateness - if (seqInstallFiles >= sequence || (0 != seqDuplicateFiles && seqDuplicateFiles <= sequence)) - { - if (0 != seqDuplicateFiles) - { - if (seqDuplicateFiles < seqInstallFiles) - { - throw new WixException(WixErrors.InsertInvalidSequenceActionOrder(mainFileRow.SourceLineNumbers, iesTable.Name, "InstallFiles", "DuplicateFiles", wixPatchAction.Action)); - } - else - { - sequence = (seqDuplicateFiles + seqInstallFiles) / 2; - if (seqInstallFiles == sequence || seqDuplicateFiles == sequence) - { - throw new WixException(WixErrors.InsertSequenceNoSpace(mainFileRow.SourceLineNumbers, iesTable.Name, "InstallFiles", "DuplicateFiles", wixPatchAction.Action)); - } - } - } - else - { - sequence = seqInstallFiles + 1; - } - } - patchAction[0] = wixPatchAction.Action; - patchAction[1] = wixPatchAction.Condition; - patchAction[2] = sequence; - patchAction.Operation = RowOperation.Add; - } - } - - /// - /// Tests sequence table for PatchFiles and associated actions - /// - /// The table to test. - /// Set to true if PatchFiles action is found. Left unchanged otherwise. - /// Set to sequence value of InstallFiles action if found. Left unchanged otherwise. - /// Set to sequence value of DuplicateFiles action if found. Left unchanged otherwise. - private static void TestSequenceTableForPatchFilesAction(Table iesTable, ref bool hasPatchFilesAction, ref int seqInstallFiles, ref int seqDuplicateFiles) - { - if (null != iesTable) - { - foreach (Row iesRow in iesTable.Rows) - { - if (String.Equals("PatchFiles", (string)iesRow[0], StringComparison.Ordinal)) - { - hasPatchFilesAction = true; - } - if (String.Equals("InstallFiles", (string)iesRow[0], StringComparison.Ordinal)) - { - seqInstallFiles = (int)iesRow.Fields[2].Data; - } - if (String.Equals("DuplicateFiles", (string)iesRow[0], StringComparison.Ordinal)) - { - seqDuplicateFiles = (int)iesRow.Fields[2].Data; - } - } - } - } - - /// - /// Signal a warning if a non-keypath file was changed in a patch without also changing the keypath file of the component. - /// - /// The output to validate. - private void ValidateFileRowChanges(Output transform) - { - Table componentTable = transform.Tables["Component"]; - Table fileTable = transform.Tables["File"]; - - // There's no sense validating keypaths if the transform has no component or file table - if (componentTable == null || fileTable == null) - { - return; - } - - Dictionary componentKeyPath = new Dictionary(componentTable.Rows.Count); - - // Index the Component table for non-directory & non-registry key paths. - foreach (Row row in componentTable.Rows) - { - if (null != row.Fields[5].Data && - 0 != ((int)row.Fields[3].Data & MsiInterop.MsidbComponentAttributesRegistryKeyPath)) - { - componentKeyPath.Add(row.Fields[0].Data.ToString(), row.Fields[5].Data.ToString()); - } - } - - Dictionary componentWithChangedKeyPath = new Dictionary(); - Dictionary componentWithNonKeyPathChanged = new Dictionary(); - // Verify changes in the file table, now that file diffing has occurred - foreach (FileRow row in fileTable.Rows) - { - string fileId = row.Fields[0].Data.ToString(); - string componentId = row.Fields[1].Data.ToString(); - - if (RowOperation.Modify != row.Operation) - { - continue; - } - - // If this file is the keypath of a component - if (componentKeyPath.ContainsValue(fileId)) - { - if (!componentWithChangedKeyPath.ContainsKey(componentId)) - { - componentWithChangedKeyPath.Add(componentId, fileId); - } - } - else - { - if (!componentWithNonKeyPathChanged.ContainsKey(componentId)) - { - componentWithNonKeyPathChanged.Add(componentId, fileId); - } - } - } - - foreach (KeyValuePair componentFile in componentWithNonKeyPathChanged) - { - // Make sure all changes to non keypath files also had a change in the keypath. - if (!componentWithChangedKeyPath.ContainsKey(componentFile.Key) && componentKeyPath.ContainsKey(componentFile.Key)) - { - Messaging.Instance.OnMessage(WixWarnings.UpdateOfNonKeyPathFile((string)componentFile.Value, (string)componentFile.Key, (string)componentKeyPath[componentFile.Key])); - } - } - } - - private bool CompareFiles(string targetFile, string updatedFile) - { - bool? compared = null; - foreach (IBinderFileManager fileManager in this.FileManagers) - { - compared = fileManager.CompareFiles(targetFile, updatedFile); - if (compared.HasValue) - { - break; - } - } - - if (!compared.HasValue) - { - throw new InvalidOperationException(); // TODO: something needs to be said here that none of the binder file managers returned a result. - } - - return compared.Value; - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/CreateCabinetsCommand.cs b/src/WixToolset.Core/Bind/Databases/CreateCabinetsCommand.cs deleted file mode 100644 index 35c8abb4..00000000 --- a/src/WixToolset.Core/Bind/Databases/CreateCabinetsCommand.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Runtime.InteropServices; - using System.Threading; - using WixToolset.Data; - using WixToolset.Data.Rows; - using WixToolset.Extensibility; - - /// - /// Creates cabinet files. - /// - internal class CreateCabinetsCommand : ICommand - { - private List fileTransfers; - - private FileSplitCabNamesCallback newCabNamesCallBack; - - private Dictionary lastCabinetAddedToMediaTable; // Key is First Cabinet Name, Value is Last Cabinet Added in the Split Sequence - - public CreateCabinetsCommand() - { - this.fileTransfers = new List(); - - this.newCabNamesCallBack = NewCabNamesCallBack; - } - - /// - /// Sets the number of threads to use for cabinet creation. - /// - public int CabbingThreadCount { private get; set; } - - public string TempFilesLocation { private get; set; } - - /// - /// Sets the default compression level to use for cabinets - /// that don't have their compression level explicitly set. - /// - public CompressionLevel DefaultCompressionLevel { private get; set; } - - public Output Output { private get; set; } - - public IEnumerable FileManagers { private get; set; } - - public string LayoutDirectory { private get; set; } - - public bool Compressed { private get; set; } - - public Dictionary> FileRowsByCabinet { private get; set; } - - public Func ResolveMedia { private get; set; } - - public TableDefinitionCollection TableDefinitions { private get; set; } - - public Table WixMediaTable { private get; set; } - - public IEnumerable FileTransfers { get { return this.fileTransfers; } } - - /// Output to generate image for. - /// Array of files to be transfered. - /// The directory in which the image should be layed out. - /// Flag if source image should be compressed. - /// The uncompressed file rows. - public void Execute() - { - RowDictionary wixMediaRows = new RowDictionary(this.WixMediaTable); - - this.lastCabinetAddedToMediaTable = new Dictionary(); - - this.SetCabbingThreadCount(); - - // Send Binder object to Facilitate NewCabNamesCallBack Callback - CabinetBuilder cabinetBuilder = new CabinetBuilder(this.CabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack)); - - // Supply Compile MediaTemplate Attributes to Cabinet Builder - int MaximumCabinetSizeForLargeFileSplitting; - int MaximumUncompressedMediaSize; - this.GetMediaTemplateAttributes(out MaximumCabinetSizeForLargeFileSplitting, out MaximumUncompressedMediaSize); - cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = MaximumCabinetSizeForLargeFileSplitting; - cabinetBuilder.MaximumUncompressedMediaSize = MaximumUncompressedMediaSize; - - foreach (var entry in this.FileRowsByCabinet) - { - MediaRow mediaRow = entry.Key; - IEnumerable files = entry.Value; - CompressionLevel compressionLevel = this.DefaultCompressionLevel; - - WixMediaRow wixMediaRow = null; - string mediaLayoutFolder = null; - - if (wixMediaRows.TryGetValue(mediaRow.GetKey(), out wixMediaRow)) - { - mediaLayoutFolder = wixMediaRow.Layout; - - if (wixMediaRow.CompressionLevel.HasValue) - { - compressionLevel = wixMediaRow.CompressionLevel.Value; - } - } - - string cabinetDir = this.ResolveMedia(mediaRow, mediaLayoutFolder, this.LayoutDirectory); - - CabinetWorkItem cabinetWorkItem = this.CreateCabinetWorkItem(this.Output, cabinetDir, mediaRow, compressionLevel, files, this.fileTransfers); - if (null != cabinetWorkItem) - { - cabinetBuilder.Enqueue(cabinetWorkItem); - } - } - - // stop processing if an error previously occurred - if (Messaging.Instance.EncounteredError) - { - return; - } - - // create queued cabinets with multiple threads - cabinetBuilder.CreateQueuedCabinets(); - if (Messaging.Instance.EncounteredError) - { - return; - } - } - - /// - /// Sets the thead count to the number of processors if the current thread count is set to 0. - /// - /// The thread count value must be greater than 0 otherwise and exception will be thrown. - private void SetCabbingThreadCount() - { - // default the number of cabbing threads to the number of processors if it wasn't specified - if (0 == this.CabbingThreadCount) - { - string numberOfProcessors = System.Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"); - - try - { - if (null != numberOfProcessors) - { - this.CabbingThreadCount = Convert.ToInt32(numberOfProcessors, CultureInfo.InvariantCulture.NumberFormat); - - if (0 >= this.CabbingThreadCount) - { - throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); - } - } - else // default to 1 if the environment variable is not set - { - this.CabbingThreadCount = 1; - } - - Messaging.Instance.OnMessage(WixVerboses.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); - } - catch (ArgumentException) - { - throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); - } - catch (FormatException) - { - throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); - } - } - } - - - /// - /// Creates a work item to create a cabinet. - /// - /// Output for the current database. - /// Directory to create cabinet in. - /// MediaRow containing information about the cabinet. - /// Collection of files in this cabinet. - /// Array of files to be transfered. - /// created CabinetWorkItem object - private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaRow mediaRow, CompressionLevel compressionLevel, IEnumerable fileFacades, List fileTransfers) - { - CabinetWorkItem cabinetWorkItem = null; - string tempCabinetFileX = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet); - - // check for an empty cabinet - if (!fileFacades.Any()) - { - string cabinetName = mediaRow.Cabinet; - - // remove the leading '#' from the embedded cabinet name to make the warning easier to understand - if (cabinetName.StartsWith("#", StringComparison.Ordinal)) - { - cabinetName = cabinetName.Substring(1); - } - - // If building a patch, remind them to run -p for torch. - if (OutputType.Patch == output.Type) - { - Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true)); - } - else - { - Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName)); - } - } - - ResolvedCabinet resolvedCabinet = this.ResolveCabinet(tempCabinetFileX, fileFacades); - - // create a cabinet work item if it's not being skipped - if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) - { - int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet). - - cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold, compressionLevel/*, this.FileManager*/); - } - else // reuse the cabinet from the cabinet cache. - { - Messaging.Instance.OnMessage(WixVerboses.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, resolvedCabinet.Path)); - - try - { - // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The - // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that - // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from - // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output) - // causing the project to look like it perpetually needs a rebuild until all of the reused - // cabinets get newer timestamps. - File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now); - } - catch (Exception e) - { - Messaging.Instance.OnMessage(WixWarnings.CannotUpdateCabCache(mediaRow.SourceLineNumbers, resolvedCabinet.Path, e.Message)); - } - } - - if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) - { - Table streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]); - - Row streamRow = streamsTable.CreateRow(mediaRow.SourceLineNumbers); - streamRow[0] = mediaRow.Cabinet.Substring(1); - streamRow[1] = resolvedCabinet.Path; - } - else - { - string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet); - FileTransfer transfer; - if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out transfer)) - { - transfer.Built = true; - fileTransfers.Add(transfer); - } - } - - return cabinetWorkItem; - } - - private ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable fileFacades) - { - ResolvedCabinet resolved = null; - - List filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source }).ToList(); - - foreach (IBinderFileManager fileManager in this.FileManagers) - { - resolved = fileManager.ResolveCabinet(cabinetPath, filesWithPath); - if (null != resolved) - { - break; - } - } - - return resolved; - } - - /// - /// Delegate for Cabinet Split Callback - /// - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate void FileSplitCabNamesCallback([MarshalAs(UnmanagedType.LPWStr)]string firstCabName, [MarshalAs(UnmanagedType.LPWStr)]string newCabName, [MarshalAs(UnmanagedType.LPWStr)]string fileToken); - - /// - /// Call back to Add File Transfer for new Cab and add new Cab to Media table - /// This callback can come from Multiple Cabinet Builder Threads and so should be thread safe - /// This callback will not be called in case there is no File splitting. i.e. MaximumCabinetSizeForLargeFileSplitting was not authored - /// - /// The name of splitting cabinet without extention e.g. "cab1". - /// The name of the new cabinet that would be formed by splitting e.g. "cab1b.cab" - /// The file token of the first file present in the splitting cabinet - internal void NewCabNamesCallBack([MarshalAs(UnmanagedType.LPWStr)]string firstCabName, [MarshalAs(UnmanagedType.LPWStr)]string newCabName, [MarshalAs(UnmanagedType.LPWStr)]string fileToken) - { - // Locking Mutex here as this callback can come from Multiple Cabinet Builder Threads - Mutex mutex = new Mutex(false, "WixCabinetSplitBinderCallback"); - try - { - if (!mutex.WaitOne(0, false)) // Check if you can get the lock - { - // Cound not get the Lock - Messaging.Instance.OnMessage(WixVerboses.CabinetsSplitInParallel()); - mutex.WaitOne(); // Wait on other thread - } - - string firstCabinetName = firstCabName + ".cab"; - string newCabinetName = newCabName; - bool transferAdded = false; // Used for Error Handling - - // Create File Transfer for new Cabinet using transfer of Base Cabinet - foreach (FileTransfer transfer in this.FileTransfers) - { - if (firstCabinetName.Equals(Path.GetFileName(transfer.Source), StringComparison.InvariantCultureIgnoreCase)) - { - string newCabSourcePath = Path.Combine(Path.GetDirectoryName(transfer.Source), newCabinetName); - string newCabTargetPath = Path.Combine(Path.GetDirectoryName(transfer.Destination), newCabinetName); - - FileTransfer newTransfer; - if (FileTransfer.TryCreate(newCabSourcePath, newCabTargetPath, transfer.Move, "Cabinet", transfer.SourceLineNumbers, out newTransfer)) - { - newTransfer.Built = true; - this.fileTransfers.Add(newTransfer); - transferAdded = true; - break; - } - } - } - - // Check if File Transfer was added - if (!transferAdded) - { - throw new WixException(WixErrors.SplitCabinetCopyRegistrationFailed(newCabinetName, firstCabinetName)); - } - - // Add the new Cabinets to media table using LastSequence of Base Cabinet - Table mediaTable = this.Output.Tables["Media"]; - Table wixFileTable = this.Output.Tables["WixFile"]; - int diskIDForLastSplitCabAdded = 0; // The DiskID value for the first cab in this cabinet split chain - int lastSequenceForLastSplitCabAdded = 0; // The LastSequence value for the first cab in this cabinet split chain - bool lastSplitCabinetFound = false; // Used for Error Handling - - string lastCabinetOfThisSequence = String.Empty; - // Get the Value of Last Cabinet Added in this split Sequence from Dictionary - if (!this.lastCabinetAddedToMediaTable.TryGetValue(firstCabinetName, out lastCabinetOfThisSequence)) - { - // If there is no value for this sequence, then use first Cabinet is the last one of this split sequence - lastCabinetOfThisSequence = firstCabinetName; - } - - foreach (MediaRow mediaRow in mediaTable.Rows) - { - // Get details for the Last Cabinet Added in this Split Sequence - if ((lastSequenceForLastSplitCabAdded == 0) && lastCabinetOfThisSequence.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) - { - lastSequenceForLastSplitCabAdded = mediaRow.LastSequence; - diskIDForLastSplitCabAdded = mediaRow.DiskId; - lastSplitCabinetFound = true; - } - - // Check for Name Collision for the new Cabinet added - if (newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) - { - // Name Collision of generated Split Cabinet Name and user Specified Cab name for current row - throw new WixException(WixErrors.SplitCabinetNameCollision(newCabinetName, firstCabinetName)); - } - } - - // Check if the last Split Cabinet was found in the Media Table - if (!lastSplitCabinetFound) - { - throw new WixException(WixErrors.SplitCabinetInsertionFailed(newCabinetName, firstCabinetName, lastCabinetOfThisSequence)); - } - - // The new Row has to be inserted just after the last cab in this cabinet split chain according to DiskID Sort - // This is because the FDI Extract requires DiskID of Split Cabinets to be continuous. It Fails otherwise with - // Error 2350 (FDI Server Error) as next DiskID did not have the right split cabinet during extraction - MediaRow newMediaRow = (MediaRow)mediaTable.CreateRow(null); - newMediaRow.Cabinet = newCabinetName; - newMediaRow.DiskId = diskIDForLastSplitCabAdded + 1; // When Sorted with DiskID, this new Cabinet Row is an Insertion - newMediaRow.LastSequence = lastSequenceForLastSplitCabAdded; - - // Now increment the DiskID for all rows that come after the newly inserted row to Ensure that DiskId is unique - foreach (MediaRow mediaRow in mediaTable.Rows) - { - // Check if this row comes after inserted row and it is not the new cabinet inserted row - if (mediaRow.DiskId >= newMediaRow.DiskId && !newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) - { - mediaRow.DiskId++; // Increment DiskID - } - } - - // Now Increment DiskID for All files Rows so that they refer to the right Media Row - foreach (WixFileRow wixFileRow in wixFileTable.Rows) - { - // Check if this row comes after inserted row and if this row is not the file that has to go into the current cabinet - // This check will work as we have only one large file in every splitting cabinet - // If we want to support splitting cabinet with more large files we need to update this code - if (wixFileRow.DiskId >= newMediaRow.DiskId && !wixFileRow.File.Equals(fileToken, StringComparison.InvariantCultureIgnoreCase)) - { - wixFileRow.DiskId++; // Increment DiskID - } - } - - // Update the Last Cabinet Added in the Split Sequence in Dictionary for future callback - this.lastCabinetAddedToMediaTable[firstCabinetName] = newCabinetName; - - mediaTable.ValidateRows(); // Valdiates DiskDIs, throws Exception as Wix Error if validation fails - } - finally - { - // Releasing the Mutex here - mutex.ReleaseMutex(); - } - } - - - /// - /// Gets Compiler Values of MediaTemplate Attributes governing Maximum Cabinet Size after applying Environment Variable Overrides - /// - /// Output to generate image for. - /// The indexed file rows. - private void GetMediaTemplateAttributes(out int maxCabSizeForLargeFileSplitting, out int maxUncompressedMediaSize) - { - // Get Environment Variable Overrides for MediaTemplate Attributes governing Maximum Cabinet Size - string mcslfsString = Environment.GetEnvironmentVariable("WIX_MCSLFS"); - string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS"); - int maxCabSizeForLargeFileInMB = 0; - int maxPreCompressedSizeInMB = 0; - ulong testOverFlow = 0; - - // Supply Compile MediaTemplate Attributes to Cabinet Builder - Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"]; - if (mediaTemplateTable != null) - { - WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0]; - - // Get the Value for Max Cab Size for File Splitting - try - { - // Override authored mcslfs value if environment variable is authored. - if (!String.IsNullOrEmpty(mcslfsString)) - { - maxCabSizeForLargeFileInMB = Int32.Parse(mcslfsString); - } - else - { - maxCabSizeForLargeFileInMB = mediaTemplateRow.MaximumCabinetSizeForLargeFileSplitting; - } - testOverFlow = (ulong)maxCabSizeForLargeFileInMB * 1024 * 1024; - } - catch (FormatException) - { - throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MCSLFS", mcslfsString)); - } - catch (OverflowException) - { - throw new WixException(WixErrors.MaximumCabinetSizeForLargeFileSplittingTooLarge(null, maxCabSizeForLargeFileInMB, CompilerCore.MaxValueOfMaxCabSizeForLargeFileSplitting)); - } - - try - { - // Override authored mums value if environment variable is authored. - if (!String.IsNullOrEmpty(mumsString)) - { - maxPreCompressedSizeInMB = Int32.Parse(mumsString); - } - else - { - maxPreCompressedSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize; - } - testOverFlow = (ulong)maxPreCompressedSizeInMB * 1024 * 1024; - } - catch (FormatException) - { - throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString)); - } - catch (OverflowException) - { - throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCompressedSizeInMB)); - } - - maxCabSizeForLargeFileSplitting = maxCabSizeForLargeFileInMB; - maxUncompressedMediaSize = maxPreCompressedSizeInMB; - } - else - { - maxCabSizeForLargeFileSplitting = 0; - maxUncompressedMediaSize = CompilerCore.DefaultMaximumUncompressedMediaSize; - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/CreateDeltaPatchesCommand.cs b/src/WixToolset.Core/Bind/Databases/CreateDeltaPatchesCommand.cs deleted file mode 100644 index 933a1ea8..00000000 --- a/src/WixToolset.Core/Bind/Databases/CreateDeltaPatchesCommand.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using WixToolset.Data; - using WixToolset.Data.Rows; - - /// - /// Creates delta patches and updates the appropriate rows to point to the newly generated patches. - /// - internal class CreateDeltaPatchesCommand : ICommand - { - public IEnumerable FileFacades { private get; set; } - - public Table WixPatchIdTable { private get; set; } - - public string TempFilesLocation { private get; set; } - - public void Execute() - { - bool optimizePatchSizeForLargeFiles = false; - PatchAPI.PatchInterop.PatchSymbolFlagsType apiPatchingSymbolFlags = 0; - - if (null != this.WixPatchIdTable) - { - Row row = this.WixPatchIdTable.Rows[0]; - if (null != row) - { - if (null != row[2]) - { - optimizePatchSizeForLargeFiles = (1 == Convert.ToUInt32(row[2], CultureInfo.InvariantCulture)); - } - - if (null != row[3]) - { - apiPatchingSymbolFlags = (PatchAPI.PatchInterop.PatchSymbolFlagsType)Convert.ToUInt32(row[3], CultureInfo.InvariantCulture); - } - } - } - - foreach (FileFacade facade in this.FileFacades) - { - if (RowOperation.Modify == facade.File.Operation && - 0 != (facade.WixFile.PatchAttributes & PatchAttributeType.IncludeWholeFile)) - { - string deltaBase = String.Concat("delta_", facade.File.File); - string deltaFile = Path.Combine(this.TempFilesLocation, String.Concat(deltaBase, ".dpf")); - string headerFile = Path.Combine(this.TempFilesLocation, String.Concat(deltaBase, ".phd")); - - bool retainRangeWarning = false; - - if (PatchAPI.PatchInterop.CreateDelta( - deltaFile, - facade.WixFile.Source, - facade.DeltaPatchFile.Symbols, - facade.DeltaPatchFile.RetainOffsets, - new[] { facade.WixFile.PreviousSource }, - facade.DeltaPatchFile.PreviousSymbols.Split(new[] { ';' }), - facade.DeltaPatchFile.PreviousIgnoreLengths.Split(new[] { ';' }), - facade.DeltaPatchFile.PreviousIgnoreOffsets.Split(new[] { ';' }), - facade.DeltaPatchFile.PreviousRetainLengths.Split(new[] { ';' }), - facade.DeltaPatchFile.PreviousRetainOffsets.Split(new[] { ';' }), - apiPatchingSymbolFlags, - optimizePatchSizeForLargeFiles, - out retainRangeWarning)) - { - PatchAPI.PatchInterop.ExtractDeltaHeader(deltaFile, headerFile); - - facade.WixFile.Source = deltaFile; - facade.WixFile.DeltaPatchHeaderSource = headerFile; - } - - if (retainRangeWarning) - { - // TODO: get patch family to add to warning message for PatchWiz parity. - Messaging.Instance.OnMessage(WixWarnings.RetainRangeMismatch(facade.File.SourceLineNumbers, facade.File.File)); - } - } - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/CreateSpecialPropertiesCommand.cs b/src/WixToolset.Core/Bind/Databases/CreateSpecialPropertiesCommand.cs deleted file mode 100644 index 5db2768b..00000000 --- a/src/WixToolset.Core/Bind/Databases/CreateSpecialPropertiesCommand.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using WixToolset.Data; - using WixToolset.Data.Rows; - - internal class CreateSpecialPropertiesCommand : ICommand - { - public Table PropertyTable { private get; set; } - - public Table WixPropertyTable { private get; set; } - - public void Execute() - { - // Create the special properties. - if (null != this.WixPropertyTable) - { - // Create lists of the properties that contribute to the special lists of properties. - SortedSet adminProperties = new SortedSet(); - SortedSet secureProperties = new SortedSet(); - SortedSet hiddenProperties = new SortedSet(); - - foreach (WixPropertyRow wixPropertyRow in this.WixPropertyTable.Rows) - { - if (wixPropertyRow.Admin) - { - adminProperties.Add(wixPropertyRow.Id); - } - - if (wixPropertyRow.Hidden) - { - hiddenProperties.Add(wixPropertyRow.Id); - } - - if (wixPropertyRow.Secure) - { - secureProperties.Add(wixPropertyRow.Id); - } - } - - Table propertyTable = this.PropertyTable; - if (0 < adminProperties.Count) - { - PropertyRow row = (PropertyRow)propertyTable.CreateRow(null); - row.Property = "AdminProperties"; - row.Value = String.Join(";", adminProperties); - } - - if (0 < secureProperties.Count) - { - PropertyRow row = (PropertyRow)propertyTable.CreateRow(null); - row.Property = "SecureCustomProperties"; - row.Value = String.Join(";", secureProperties); - } - - if (0 < hiddenProperties.Count) - { - PropertyRow row = (PropertyRow)propertyTable.CreateRow(null); - row.Property = "MsiHiddenProperties"; - row.Value = String.Join(";", hiddenProperties); - } - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs deleted file mode 100644 index bee1488b..00000000 --- a/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Runtime.InteropServices; - using WixToolset.Cab; - using WixToolset.Data; - using WixToolset.Data.Rows; - using WixToolset.MergeMod; - using WixToolset.Msi; - using WixToolset.Core.Native; - - /// - /// Retrieve files information and extract them from merge modules. - /// - internal class ExtractMergeModuleFilesCommand : ICommand - { - public IEnumerable FileFacades { private get; set; } - - public Table FileTable { private get; set; } - - public Table WixFileTable { private get; set; } - - public Table WixMergeTable { private get; set; } - - public int OutputInstallerVersion { private get; set; } - - public bool SuppressLayout { private get; set; } - - public string TempFilesLocation { private get; set; } - - public IEnumerable MergeModulesFileFacades { get; private set; } - - public void Execute() - { - List mergeModulesFileFacades = new List(); - - IMsmMerge2 merge = MsmInterop.GetMsmMerge(); - - // Index all of the file rows to be able to detect collisions with files in the Merge Modules. - // It may seem a bit expensive to build up this index solely for the purpose of checking collisions - // and you may be thinking, "Surely, we must need the file rows indexed elsewhere." It turns out - // there are other cases where we need all the file rows indexed, however they are not common cases. - // Now since Merge Modules are already slow and generally less desirable than .wixlibs we'll let - // this case be slightly more expensive because the cost of maintaining an indexed file row collection - // is a lot more costly for the common cases. - Dictionary indexedFileFacades = this.FileFacades.ToDictionary(f => f.File.File, StringComparer.Ordinal); - - foreach (WixMergeRow wixMergeRow in this.WixMergeTable.Rows) - { - bool containsFiles = this.CreateFacadesForMergeModuleFiles(wixMergeRow, mergeModulesFileFacades, indexedFileFacades); - - // If the module has files and creating layout - if (containsFiles && !this.SuppressLayout) - { - this.ExtractFilesFromMergeModule(merge, wixMergeRow); - } - } - - this.MergeModulesFileFacades = mergeModulesFileFacades; - } - - private bool CreateFacadesForMergeModuleFiles(WixMergeRow wixMergeRow, List mergeModulesFileFacades, Dictionary indexedFileFacades) - { - bool containsFiles = false; - - try - { - // read the module's File table to get its FileMediaInformation entries and gather any other information needed from the module. - using (Database db = new Database(wixMergeRow.SourceFile, OpenDatabase.ReadOnly)) - { - if (db.TableExists("File") && db.TableExists("Component")) - { - Dictionary uniqueModuleFileIdentifiers = new Dictionary(StringComparer.OrdinalIgnoreCase); - - using (View view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`")) - { - // add each file row from the merge module into the file row collection (check for errors along the way) - while (true) - { - using (Record record = view.Fetch()) - { - if (null == record) - { - break; - } - - // NOTE: this is very tricky - the merge module file rows are not added to the - // file table because they should not be created via idt import. Instead, these - // rows are created by merging in the actual modules. - FileRow fileRow = (FileRow)this.FileTable.CreateRow(wixMergeRow.SourceLineNumbers, false); - fileRow.File = record[1]; - fileRow.Compressed = wixMergeRow.FileCompression; - - WixFileRow wixFileRow = (WixFileRow)this.WixFileTable.CreateRow(wixMergeRow.SourceLineNumbers, false); - wixFileRow.Directory = record[2]; - wixFileRow.DiskId = wixMergeRow.DiskId; - wixFileRow.PatchGroup = -1; - wixFileRow.Source = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", wixMergeRow.Number.ToString(CultureInfo.InvariantCulture), Path.DirectorySeparatorChar, record[1]); - - FileFacade mergeModuleFileFacade = new FileFacade(true, fileRow, wixFileRow); - - FileFacade collidingFacade; - - // If case-sensitive collision with another merge module or a user-authored file identifier. - if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.File.File, out collidingFacade)) - { - Messaging.Instance.OnMessage(WixErrors.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, collidingFacade.File.File)); - } - else if (uniqueModuleFileIdentifiers.TryGetValue(mergeModuleFileFacade.File.File, out collidingFacade)) // case-insensitive collision with another file identifier in the same merge module - { - Messaging.Instance.OnMessage(WixErrors.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, mergeModuleFileFacade.File.File, collidingFacade.File.File)); - } - else // no collision - { - mergeModulesFileFacades.Add(mergeModuleFileFacade); - - // Keep updating the indexes as new rows are added. - indexedFileFacades.Add(mergeModuleFileFacade.File.File, mergeModuleFileFacade); - uniqueModuleFileIdentifiers.Add(mergeModuleFileFacade.File.File, mergeModuleFileFacade); - } - - containsFiles = true; - } - } - } - } - - // Get the summary information to detect the Schema - using (SummaryInformation summaryInformation = new SummaryInformation(db)) - { - string moduleInstallerVersionString = summaryInformation.GetProperty(14); - - try - { - int moduleInstallerVersion = Convert.ToInt32(moduleInstallerVersionString, CultureInfo.InvariantCulture); - if (moduleInstallerVersion > this.OutputInstallerVersion) - { - Messaging.Instance.OnMessage(WixWarnings.InvalidHigherInstallerVersionInModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleInstallerVersion, this.OutputInstallerVersion)); - } - } - catch (FormatException) - { - throw new WixException(WixErrors.MissingOrInvalidModuleInstallerVersion(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile, moduleInstallerVersionString)); - } - } - } - } - catch (FileNotFoundException) - { - throw new WixException(WixErrors.FileNotFound(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile)); - } - catch (Win32Exception) - { - throw new WixException(WixErrors.CannotOpenMergeModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile)); - } - - return containsFiles; - } - - private void ExtractFilesFromMergeModule(IMsmMerge2 merge, WixMergeRow wixMergeRow) - { - bool moduleOpen = false; - short mergeLanguage; - - try - { - mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); - } - catch (System.FormatException) - { - Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); - return; - } - - try - { - merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); - moduleOpen = true; - - string safeMergeId = wixMergeRow.Number.ToString(CultureInfo.InvariantCulture.NumberFormat); - - // extract the module cabinet, then explode all of the files to a temp directory - string moduleCabPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, safeMergeId, ".module.cab"); - merge.ExtractCAB(moduleCabPath); - - string mergeIdPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", safeMergeId); - Directory.CreateDirectory(mergeIdPath); - - using (WixExtractCab extractCab = new WixExtractCab()) - { - try - { - extractCab.Extract(moduleCabPath, mergeIdPath); - } - catch (FileNotFoundException) - { - throw new WixException(WixErrors.CabFileDoesNotExist(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath)); - } - catch - { - throw new WixException(WixErrors.CabExtractionFailed(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath)); - } - } - } - catch (COMException ce) - { - throw new WixException(WixErrors.UnableToOpenModule(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile, ce.Message)); - } - finally - { - if (moduleOpen) - { - merge.CloseModule(); - } - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/FileFacade.cs b/src/WixToolset.Core/Bind/Databases/FileFacade.cs deleted file mode 100644 index 37115c97..00000000 --- a/src/WixToolset.Core/Bind/Databases/FileFacade.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System.Collections.Generic; - using WixToolset.Data; - using WixToolset.Data.Rows; - - public class FileFacade - { - public FileFacade(FileRow file, WixFileRow wixFile, WixDeltaPatchFileRow deltaPatchFile) - { - this.File = file; - this.WixFile = wixFile; - this.DeltaPatchFile = deltaPatchFile; - } - - public FileFacade(bool fromModule, FileRow file, WixFileRow wixFile) - { - this.FromModule = fromModule; - this.File = file; - this.WixFile = wixFile; - } - - public bool FromModule { get; private set; } - - public FileRow File { get; private set; } - - public WixFileRow WixFile { get; private set; } - - public WixDeltaPatchFileRow DeltaPatchFile { get; private set; } - - /// - /// Gets the set of MsiAssemblyName rows created for this file. - /// - /// RowCollection of MsiAssemblyName table. - public List AssemblyNames { get; set; } - - /// - /// Gets or sets the MsiFileHash row for this file. - /// - public Row Hash { get; set; } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/GetFileFacadesCommand.cs b/src/WixToolset.Core/Bind/Databases/GetFileFacadesCommand.cs deleted file mode 100644 index b6bcd3af..00000000 --- a/src/WixToolset.Core/Bind/Databases/GetFileFacadesCommand.cs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using WixToolset.Data; - using WixToolset.Data.Rows; - - internal class GetFileFacadesCommand : ICommand - { - public Table FileTable { private get; set; } - - public Table WixFileTable { private get; set; } - - public Table WixDeltaPatchFileTable { private get; set; } - - public Table WixDeltaPatchSymbolPathsTable { private get; set; } - - public List FileFacades { get; private set; } - - public void Execute() - { - List facades = new List(this.FileTable.Rows.Count); - - RowDictionary wixFiles = new RowDictionary(this.WixFileTable); - RowDictionary deltaPatchFiles = new RowDictionary(this.WixDeltaPatchFileTable); - - foreach (FileRow file in this.FileTable.Rows) - { - WixDeltaPatchFileRow deltaPatchFile = null; - - deltaPatchFiles.TryGetValue(file.File, out deltaPatchFile); - - facades.Add(new FileFacade(file, wixFiles[file.File], deltaPatchFile)); - } - - if (null != this.WixDeltaPatchSymbolPathsTable) - { - this.ResolveDeltaPatchSymbolPaths(deltaPatchFiles, facades); - } - - this.FileFacades = facades; - } - - /// - /// Merge data from the WixPatchSymbolPaths rows into the WixDeltaPatchFile rows. - /// - public RowDictionary ResolveDeltaPatchSymbolPaths(RowDictionary deltaPatchFiles, IEnumerable facades) - { - ILookup filesByComponent = null; - ILookup filesByDirectory = null; - ILookup filesByDiskId = null; - - foreach (WixDeltaPatchSymbolPathsRow row in this.WixDeltaPatchSymbolPathsTable.RowsAs().OrderBy(r => r.Type)) - { - switch (row.Type) - { - case SymbolPathType.File: - this.MergeSymbolPaths(row, deltaPatchFiles[row.Id]); - break; - - case SymbolPathType.Component: - if (null == filesByComponent) - { - filesByComponent = facades.ToLookup(f => f.File.Component); - } - - foreach (FileFacade facade in filesByComponent[row.Id]) - { - this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); - } - break; - - case SymbolPathType.Directory: - if (null == filesByDirectory) - { - filesByDirectory = facades.ToLookup(f => f.WixFile.Directory); - } - - foreach (FileFacade facade in filesByDirectory[row.Id]) - { - this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); - } - break; - - case SymbolPathType.Media: - if (null == filesByDiskId) - { - filesByDiskId = facades.ToLookup(f => f.WixFile.DiskId.ToString(CultureInfo.InvariantCulture)); - } - - foreach (FileFacade facade in filesByDiskId[row.Id]) - { - this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); - } - break; - - case SymbolPathType.Product: - foreach (WixDeltaPatchFileRow fileRow in deltaPatchFiles.Values) - { - this.MergeSymbolPaths(row, fileRow); - } - break; - - default: - // error - break; - } - } - - return deltaPatchFiles; - } - - /// - /// Merge data from a row in the WixPatchSymbolsPaths table into an associated WixDeltaPatchFile row. - /// - /// Row from the WixPatchSymbolsPaths table. - /// FileRow into which to set symbol information. - /// This includes PreviousData as well. - private void MergeSymbolPaths(WixDeltaPatchSymbolPathsRow row, WixDeltaPatchFileRow file) - { - if (null == file.Symbols) - { - file.Symbols = row.SymbolPaths; - } - else - { - file.Symbols = String.Concat(file.Symbols, ";", row.SymbolPaths); - } - - Field field = row.Fields[2]; - if (null != field.PreviousData) - { - if (null == file.PreviousSymbols) - { - file.PreviousSymbols = field.PreviousData; - } - else - { - file.PreviousSymbols = String.Concat(file.PreviousSymbols, ";", field.PreviousData); - } - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs b/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs deleted file mode 100644 index 035ef059..00000000 --- a/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.Collections.Specialized; - using System.ComponentModel; - using System.Diagnostics; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Runtime.InteropServices; - using System.Text; - using System.Xml; - using System.Xml.XPath; - using WixToolset.Clr.Interop; - using WixToolset.Data; - using WixToolset.Data.Rows; - using WixToolset.MergeMod; - using WixToolset.Msi; - using WixToolset.Core.Native; - - /// - /// Update file information. - /// - internal class MergeModulesCommand : ICommand - { - public IEnumerable FileFacades { private get; set; } - - public Output Output { private get; set; } - - public string OutputPath { private get; set; } - - public IEnumerable SuppressedTableNames { private get; set; } - - public string TempFilesLocation { private get; set; } - - public void Execute() - { - Debug.Assert(OutputType.Product == this.Output.Type); - - Table wixMergeTable = this.Output.Tables["WixMerge"]; - Table wixFeatureModulesTable = this.Output.Tables["WixFeatureModules"]; - - // check for merge rows to see if there is any work to do - if (null == wixMergeTable || 0 == wixMergeTable.Rows.Count) - { - return; - } - - IMsmMerge2 merge = null; - bool commit = true; - bool logOpen = false; - bool databaseOpen = false; - string logPath = null; - try - { - merge = MsmInterop.GetMsmMerge(); - - logPath = Path.Combine(this.TempFilesLocation, "merge.log"); - merge.OpenLog(logPath); - logOpen = true; - - merge.OpenDatabase(this.OutputPath); - databaseOpen = true; - - // process all the merge rows - foreach (WixMergeRow wixMergeRow in wixMergeTable.Rows) - { - bool moduleOpen = false; - - try - { - short mergeLanguage; - - try - { - mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); - } - catch (System.FormatException) - { - Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); - continue; - } - - Messaging.Instance.OnMessage(WixVerboses.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage)); - merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); - moduleOpen = true; - - // If there is merge configuration data, create a callback object to contain it all. - ConfigurationCallback callback = null; - if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData)) - { - callback = new ConfigurationCallback(wixMergeRow.ConfigurationData); - } - - // merge the module into the database that's being built - Messaging.Instance.OnMessage(WixVerboses.MergingMergeModule(wixMergeRow.SourceFile)); - merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback); - - // connect any non-primary features - if (null != wixFeatureModulesTable) - { - foreach (Row row in wixFeatureModulesTable.Rows) - { - if (wixMergeRow.Id == (string)row[1]) - { - Messaging.Instance.OnMessage(WixVerboses.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0])); - merge.Connect((string)row[0]); - } - } - } - } - catch (COMException) - { - commit = false; - } - finally - { - IMsmErrors mergeErrors = merge.Errors; - - // display all the errors encountered during the merge operations for this module - for (int i = 1; i <= mergeErrors.Count; i++) - { - IMsmError mergeError = mergeErrors[i]; - StringBuilder databaseKeys = new StringBuilder(); - StringBuilder moduleKeys = new StringBuilder(); - - // build a string of the database keys - for (int j = 1; j <= mergeError.DatabaseKeys.Count; j++) - { - if (1 != j) - { - databaseKeys.Append(';'); - } - databaseKeys.Append(mergeError.DatabaseKeys[j]); - } - - // build a string of the module keys - for (int j = 1; j <= mergeError.ModuleKeys.Count; j++) - { - if (1 != j) - { - moduleKeys.Append(';'); - } - moduleKeys.Append(mergeError.ModuleKeys[j]); - } - - // display the merge error based on the msm error type - switch (mergeError.Type) - { - case MsmErrorType.msmErrorExclusion: - Messaging.Instance.OnMessage(WixErrors.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleKeys.ToString())); - break; - case MsmErrorType.msmErrorFeatureRequired: - Messaging.Instance.OnMessage(WixErrors.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id)); - break; - case MsmErrorType.msmErrorLanguageFailed: - Messaging.Instance.OnMessage(WixErrors.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); - break; - case MsmErrorType.msmErrorLanguageUnsupported: - Messaging.Instance.OnMessage(WixErrors.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); - break; - case MsmErrorType.msmErrorResequenceMerge: - Messaging.Instance.OnMessage(WixWarnings.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); - break; - case MsmErrorType.msmErrorTableMerge: - if ("_Validation" != mergeError.DatabaseTable) // ignore merge errors in the _Validation table - { - Messaging.Instance.OnMessage(WixWarnings.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); - } - break; - case MsmErrorType.msmErrorPlatformMismatch: - Messaging.Instance.OnMessage(WixErrors.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile)); - break; - default: - Messaging.Instance.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorWithType, Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace)); - break; - } - } - - if (0 >= mergeErrors.Count && !commit) - { - Messaging.Instance.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorInSourceFile, wixMergeRow.SourceFile, logPath), "InvalidOperationException", Environment.StackTrace)); - } - - if (moduleOpen) - { - merge.CloseModule(); - } - } - } - } - finally - { - if (databaseOpen) - { - merge.CloseDatabase(commit); - } - - if (logOpen) - { - merge.CloseLog(); - } - } - - // stop processing if an error previously occurred - if (Messaging.Instance.EncounteredError) - { - return; - } - - using (Database db = new Database(this.OutputPath, OpenDatabase.Direct)) - { - Table suppressActionTable = this.Output.Tables["WixSuppressAction"]; - - // suppress individual actions - if (null != suppressActionTable) - { - foreach (Row row in suppressActionTable.Rows) - { - if (db.TableExists((string)row[0])) - { - string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]); - - using (View view = db.OpenExecuteView(query)) - { - using (Record record = view.Fetch()) - { - if (null != record) - { - Messaging.Instance.OnMessage(WixWarnings.SuppressMergedAction((string)row[1], row[0].ToString())); - view.Modify(ModifyView.Delete, record); - } - } - } - } - } - } - - // query for merge module actions in suppressed sequences and drop them - foreach (string tableName in this.SuppressedTableNames) - { - if (!db.TableExists(tableName)) - { - continue; - } - - using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) - { - while (true) - { - using (Record resultRecord = view.Fetch()) - { - if (null == resultRecord) - { - break; - } - - Messaging.Instance.OnMessage(WixWarnings.SuppressMergedAction(resultRecord.GetString(1), tableName)); - } - } - } - - // drop suppressed sequences - using (View view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName))) - { - } - - // delete the validation rows - using (View view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?"))) - { - using (Record record = new Record(1)) - { - record.SetString(1, tableName); - view.Execute(record); - } - } - } - - // now update the Attributes column for the files from the Merge Modules - Messaging.Instance.OnMessage(WixVerboses.ResequencingMergeModuleFiles()); - using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) - { - foreach (FileFacade file in this.FileFacades) - { - if (!file.FromModule) - { - continue; - } - - using (Record record = new Record(1)) - { - record.SetString(1, file.File.File); - view.Execute(record); - } - - using (Record recordUpdate = view.Fetch()) - { - if (null == recordUpdate) - { - throw new InvalidOperationException("Failed to fetch a File row from the database that was merged in from a module."); - } - - recordUpdate.SetInteger(1, file.File.Sequence); - - // update the file attributes to match the compression specified - // on the Merge element or on the Package element - int attributes = 0; - - // get the current value if its not null - if (!recordUpdate.IsNull(2)) - { - attributes = recordUpdate.GetInteger(2); - } - - if (YesNoType.Yes == file.File.Compressed) - { - // these are mutually exclusive - attributes |= MsiInterop.MsidbFileAttributesCompressed; - attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; - } - else if (YesNoType.No == file.File.Compressed) - { - // these are mutually exclusive - attributes |= MsiInterop.MsidbFileAttributesNoncompressed; - attributes &= ~MsiInterop.MsidbFileAttributesCompressed; - } - else // not specified - { - Debug.Assert(YesNoType.NotSet == file.File.Compressed); - - // clear any compression bits - attributes &= ~MsiInterop.MsidbFileAttributesCompressed; - attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; - } - - recordUpdate.SetInteger(2, attributes); - - view.Modify(ModifyView.Update, recordUpdate); - } - } - } - - db.Commit(); - } - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/ProcessUncompressedFilesCommand.cs b/src/WixToolset.Core/Bind/Databases/ProcessUncompressedFilesCommand.cs deleted file mode 100644 index dd7b85b7..00000000 --- a/src/WixToolset.Core/Bind/Databases/ProcessUncompressedFilesCommand.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.IO; - using WixToolset.Data; - using WixToolset.Data.Rows; - using WixToolset.Msi; - using WixToolset.Core.Native; - - /// - /// Defines the file transfers necessary to layout the uncompressed files. - /// - internal class ProcessUncompressedFilesCommand : ICommand - { - public string DatabasePath { private get; set; } - - public IEnumerable FileFacades { private get; set; } - - public RowDictionary MediaRows { private get; set; } - - public string LayoutDirectory { private get; set; } - - public bool Compressed { private get; set; } - - public bool LongNamesInImage { private get; set; } - - public Func ResolveMedia { private get; set; } - - public Table WixMediaTable { private get; set; } - - public IEnumerable FileTransfers { get; private set; } - - public void Execute() - { - List fileTransfers = new List(); - - Hashtable directories = new Hashtable(); - - RowDictionary wixMediaRows = new RowDictionary(this.WixMediaTable); - - using (Database db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) - { - using (View directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) - { - while (true) - { - using (Record directoryRecord = directoryView.Fetch()) - { - if (null == directoryRecord) - { - break; - } - - string sourceName = Installer.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage); - - directories.Add(directoryRecord.GetString(1), new ResolvedDirectory(directoryRecord.GetString(2), sourceName)); - } - } - } - - using (View fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?")) - { - using (Record fileQueryRecord = new Record(1)) - { - // for each file in the array of uncompressed files - foreach (FileFacade facade in this.FileFacades) - { - MediaRow mediaRow = this.MediaRows.Get(facade.WixFile.DiskId); - string relativeFileLayoutPath = null; - - WixMediaRow wixMediaRow = null; - string mediaLayoutFolder = null; - - if (wixMediaRows.TryGetValue(mediaRow.GetKey(), out wixMediaRow)) - { - mediaLayoutFolder = wixMediaRow.Layout; - } - - string mediaLayoutDirectory = this.ResolveMedia(mediaRow, mediaLayoutFolder, this.LayoutDirectory); - - // setup up the query record and find the appropriate file in the - // previously executed file view - fileQueryRecord[1] = facade.File.File; - fileView.Execute(fileQueryRecord); - - using (Record fileRecord = fileView.Fetch()) - { - if (null == fileRecord) - { - throw new WixException(WixErrors.FileIdentifierNotFound(facade.File.SourceLineNumbers, facade.File.File)); - } - - relativeFileLayoutPath = Binder.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage); - } - - // finally put together the base media layout path and the relative file layout path - string fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath); - FileTransfer transfer; - if (FileTransfer.TryCreate(facade.WixFile.Source, fileLayoutPath, false, "File", facade.File.SourceLineNumbers, out transfer)) - { - fileTransfers.Add(transfer); - } - } - } - } - } - - this.FileTransfers = fileTransfers; - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/UpdateControlTextCommand.cs b/src/WixToolset.Core/Bind/Databases/UpdateControlTextCommand.cs deleted file mode 100644 index 9e17ee02..00000000 --- a/src/WixToolset.Core/Bind/Databases/UpdateControlTextCommand.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.IO; - using WixToolset.Data; - using WixToolset.Data.Rows; - - internal class UpdateControlTextCommand : ICommand - { - public Table BBControlTable { private get; set; } - - public Table WixBBControlTable { private get; set; } - - public Table ControlTable { private get; set; } - - public Table WixControlTable { private get; set; } - - public void Execute() - { - if (null != this.WixBBControlTable) - { - RowDictionary bbControlRows = new RowDictionary(this.BBControlTable); - foreach (Row wixRow in this.WixBBControlTable.Rows) - { - BBControlRow bbControlRow = bbControlRows.Get(wixRow.GetPrimaryKey()); - bbControlRow.Text = this.ReadTextFile(bbControlRow.SourceLineNumbers, wixRow.FieldAsString(2)); - } - } - - if (null != this.WixControlTable) - { - RowDictionary controlRows = new RowDictionary(this.ControlTable); - foreach (Row wixRow in this.WixControlTable.Rows) - { - ControlRow controlRow = controlRows.Get(wixRow.GetPrimaryKey()); - controlRow.Text = this.ReadTextFile(controlRow.SourceLineNumbers, wixRow.FieldAsString(2)); - } - } - } - - /// - /// Reads a text file and returns the contents. - /// - /// Source line numbers for row from source. - /// Source path to file to read. - /// Text string read from file. - private string ReadTextFile(SourceLineNumber sourceLineNumbers, string source) - { - string text = null; - - try - { - using (StreamReader reader = new StreamReader(source)) - { - text = reader.ReadToEnd(); - } - } - catch (DirectoryNotFoundException e) - { - Messaging.Instance.OnMessage(WixErrors.BinderFileManagerMissingFile(sourceLineNumbers, e.Message)); - } - catch (FileNotFoundException e) - { - Messaging.Instance.OnMessage(WixErrors.BinderFileManagerMissingFile(sourceLineNumbers, e.Message)); - } - catch (IOException e) - { - Messaging.Instance.OnMessage(WixErrors.BinderFileManagerMissingFile(sourceLineNumbers, e.Message)); - } - catch (NotSupportedException) - { - Messaging.Instance.OnMessage(WixErrors.FileNotFound(sourceLineNumbers, source)); - } - - return text; - } - } -} diff --git a/src/WixToolset.Core/Bind/Databases/UpdateFileFacadesCommand.cs b/src/WixToolset.Core/Bind/Databases/UpdateFileFacadesCommand.cs deleted file mode 100644 index 36818afa..00000000 --- a/src/WixToolset.Core/Bind/Databases/UpdateFileFacadesCommand.cs +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Bind.Databases -{ - using System; - using System.Collections.Generic; - using System.Collections.Specialized; - using System.ComponentModel; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Xml; - using System.Xml.XPath; - using WixToolset.Clr.Interop; - using WixToolset.Data; - using WixToolset.Data.Rows; - using WixToolset.Msi; - - /// - /// Update file information. - /// - internal class UpdateFileFacadesCommand : ICommand - { - public IEnumerable FileFacades { private get; set; } - - public IEnumerable UpdateFileFacades { private get; set; } - - public string ModularizationGuid { private get; set; } - - public Output Output { private get; set; } - - public bool OverwriteHash { private get; set; } - - public TableDefinitionCollection TableDefinitions { private get; set; } - - public IDictionary VariableCache { private get; set; } - - public void Execute() - { - foreach (FileFacade file in this.UpdateFileFacades) - { - this.UpdateFileFacade(file); - } - } - - private void UpdateFileFacade(FileFacade file) - { - FileInfo fileInfo = null; - try - { - fileInfo = new FileInfo(file.WixFile.Source); - } - catch (ArgumentException) - { - Messaging.Instance.OnMessage(WixErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); - return; - } - catch (PathTooLongException) - { - Messaging.Instance.OnMessage(WixErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); - return; - } - catch (NotSupportedException) - { - Messaging.Instance.OnMessage(WixErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); - return; - } - - if (!fileInfo.Exists) - { - Messaging.Instance.OnMessage(WixErrors.CannotFindFile(file.File.SourceLineNumbers, file.File.File, file.File.FileName, file.WixFile.Source)); - return; - } - - using (FileStream fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - if (Int32.MaxValue < fileStream.Length) - { - throw new WixException(WixErrors.FileTooLarge(file.File.SourceLineNumbers, file.WixFile.Source)); - } - - file.File.FileSize = Convert.ToInt32(fileStream.Length, CultureInfo.InvariantCulture); - } - - string version = null; - string language = null; - try - { - Installer.GetFileVersion(fileInfo.FullName, out version, out language); - } - catch (Win32Exception e) - { - if (0x2 == e.NativeErrorCode) // ERROR_FILE_NOT_FOUND - { - throw new WixException(WixErrors.FileNotFound(file.File.SourceLineNumbers, fileInfo.FullName)); - } - else - { - throw new WixException(WixErrors.Win32Exception(e.NativeErrorCode, e.Message)); - } - } - - // If there is no version, it is assumed there is no language because it won't matter in the versioning of the install. - if (String.IsNullOrEmpty(version)) // unversioned files have their hashes added to the MsiFileHash table - { - if (!this.OverwriteHash) - { - // not overwriting hash, so don't do the rest of these options. - } - else if (null != file.File.Version) - { - // Search all of the file rows available to see if the specified version is actually a companion file. Yes, this looks - // very expensive and you're probably thinking it would be better to create an index of some sort to do an O(1) look up. - // That's a reasonable thought but companion file usage is usually pretty rare so we'd be doing something expensive (indexing - // all the file rows) for a relatively uncommon situation. Let's not do that. - // - // Also, if we do not find a matching file identifier then the user provided a default version and is providing a version - // for unversioned file. That's allowed but generally a dangerous thing to do so let's point that out to the user. - if (!this.FileFacades.Any(r => file.File.Version.Equals(r.File.File, StringComparison.Ordinal))) - { - Messaging.Instance.OnMessage(WixWarnings.DefaultVersionUsedForUnversionedFile(file.File.SourceLineNumbers, file.File.Version, file.File.File)); - } - } - else - { - if (null != file.File.Language) - { - Messaging.Instance.OnMessage(WixWarnings.DefaultLanguageUsedForUnversionedFile(file.File.SourceLineNumbers, file.File.Language, file.File.File)); - } - - int[] hash; - try - { - Installer.GetFileHash(fileInfo.FullName, 0, out hash); - } - catch (Win32Exception e) - { - if (0x2 == e.NativeErrorCode) // ERROR_FILE_NOT_FOUND - { - throw new WixException(WixErrors.FileNotFound(file.File.SourceLineNumbers, fileInfo.FullName)); - } - else - { - throw new WixException(WixErrors.Win32Exception(e.NativeErrorCode, fileInfo.FullName, e.Message)); - } - } - - if (null == file.Hash) - { - Table msiFileHashTable = this.Output.EnsureTable(this.TableDefinitions["MsiFileHash"]); - file.Hash = msiFileHashTable.CreateRow(file.File.SourceLineNumbers); - } - - file.Hash[0] = file.File.File; - file.Hash[1] = 0; - file.Hash[2] = hash[0]; - file.Hash[3] = hash[1]; - file.Hash[4] = hash[2]; - file.Hash[5] = hash[3]; - } - } - else // update the file row with the version and language information. - { - // If no version was provided by the user, use the version from the file itself. - // This is the most common case. - if (String.IsNullOrEmpty(file.File.Version)) - { - file.File.Version = version; - } - else if (!this.FileFacades.Any(r => file.File.Version.Equals(r.File.File, StringComparison.Ordinal))) // this looks expensive, but see explanation below. - { - // The user provided a default version for the file row so we looked for a companion file (a file row with Id matching - // the version value). We didn't find it so, we will override the default version they provided with the actual - // version from the file itself. Now, I know it looks expensive to search through all the file rows trying to match - // on the Id. However, the alternative is to build a big index of all file rows to do look ups. Since this case - // where the file version is already present is rare (companion files are pretty uncommon), we'll do the more - // CPU intensive search to save on the memory intensive index that wouldn't be used much. - // - // Also note this case can occur when the file is being updated using the WixBindUpdatedFiles extension mechanism. - // That's typically even more rare than companion files so again, no index, just search. - file.File.Version = version; - } - - if (!String.IsNullOrEmpty(file.File.Language) && String.IsNullOrEmpty(language)) - { - Messaging.Instance.OnMessage(WixWarnings.DefaultLanguageUsedForVersionedFile(file.File.SourceLineNumbers, file.File.Language, file.File.File)); - } - else // override the default provided by the user (usually nothing) with the actual language from the file itself. - { - file.File.Language = language; - } - - // Populate the binder variables for this file information if requested. - if (null != this.VariableCache) - { - if (!String.IsNullOrEmpty(file.File.Version)) - { - string key = String.Format(CultureInfo.InvariantCulture, "fileversion.{0}", BindDatabaseCommand.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)); - this.VariableCache[key] = file.File.Version; - } - - if (!String.IsNullOrEmpty(file.File.Language)) - { - string key = String.Format(CultureInfo.InvariantCulture, "filelanguage.{0}", BindDatabaseCommand.Demodularize(this.Output.Type, ModularizationGuid, file.File.File)); - this.VariableCache[key] = file.File.Language; - } - } - } - - // If this is a CLR assembly, load the assembly and get the assembly name information - if (FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType) - { - bool targetNetfx1 = false; - StringDictionary assemblyNameValues = new StringDictionary(); - - ClrInterop.IReferenceIdentity referenceIdentity = null; - Guid referenceIdentityGuid = ClrInterop.ReferenceIdentityGuid; - uint result = ClrInterop.GetAssemblyIdentityFromFile(fileInfo.FullName, ref referenceIdentityGuid, out referenceIdentity); - if (0 == result && null != referenceIdentity) - { - string imageRuntimeVersion = referenceIdentity.GetAttribute(null, "ImageRuntimeVersion"); - if (null != imageRuntimeVersion) - { - targetNetfx1 = imageRuntimeVersion.StartsWith("v1", StringComparison.OrdinalIgnoreCase); - } - - string culture = referenceIdentity.GetAttribute(null, "Culture") ?? "neutral"; - assemblyNameValues.Add("Culture", culture); - - string name = referenceIdentity.GetAttribute(null, "Name"); - if (null != name) - { - assemblyNameValues.Add("Name", name); - } - - string processorArchitecture = referenceIdentity.GetAttribute(null, "ProcessorArchitecture"); - if (null != processorArchitecture) - { - assemblyNameValues.Add("ProcessorArchitecture", processorArchitecture); - } - - string publicKeyToken = referenceIdentity.GetAttribute(null, "PublicKeyToken"); - if (null != publicKeyToken) - { - bool publicKeyIsNeutral = (String.Equals(publicKeyToken, "neutral", StringComparison.OrdinalIgnoreCase)); - - // Managed code expects "null" instead of "neutral", and - // this won't be installed to the GAC since it's not signed anyway. - assemblyNameValues.Add("publicKeyToken", publicKeyIsNeutral ? "null" : publicKeyToken.ToUpperInvariant()); - assemblyNameValues.Add("publicKeyTokenPreservedCase", publicKeyIsNeutral ? "null" : publicKeyToken); - } - else if (file.WixFile.AssemblyApplication == null) - { - throw new WixException(WixErrors.GacAssemblyNoStrongName(file.File.SourceLineNumbers, fileInfo.FullName, file.File.Component)); - } - - string assemblyVersion = referenceIdentity.GetAttribute(null, "Version"); - if (null != version) - { - assemblyNameValues.Add("Version", assemblyVersion); - } - } - else - { - Messaging.Instance.OnMessage(WixErrors.InvalidAssemblyFile(file.File.SourceLineNumbers, fileInfo.FullName, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", result))); - return; - } - - Table assemblyNameTable = this.Output.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); - if (assemblyNameValues.ContainsKey("name")) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "name", assemblyNameValues["name"]); - } - - if (!String.IsNullOrEmpty(version)) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "fileVersion", version); - } - - if (assemblyNameValues.ContainsKey("version")) - { - string assemblyVersion = assemblyNameValues["version"]; - - if (!targetNetfx1) - { - // There is a bug in v1 fusion that requires the assembly's "version" attribute - // to be equal to or longer than the "fileVersion" in length when its present; - // the workaround is to prepend zeroes to the last version number in the assembly - // version. - if (null != version && version.Length > assemblyVersion.Length) - { - string padding = new string('0', version.Length - assemblyVersion.Length); - string[] assemblyVersionNumbers = assemblyVersion.Split('.'); - - if (assemblyVersionNumbers.Length > 0) - { - assemblyVersionNumbers[assemblyVersionNumbers.Length - 1] = String.Concat(padding, assemblyVersionNumbers[assemblyVersionNumbers.Length - 1]); - assemblyVersion = String.Join(".", assemblyVersionNumbers); - } - } - } - - this.SetMsiAssemblyName(assemblyNameTable, file, "version", assemblyVersion); - } - - if (assemblyNameValues.ContainsKey("culture")) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "culture", assemblyNameValues["culture"]); - } - - if (assemblyNameValues.ContainsKey("publicKeyToken")) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "publicKeyToken", assemblyNameValues["publicKeyToken"]); - } - - if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); - } - - if (assemblyNameValues.ContainsKey("processorArchitecture")) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "processorArchitecture", assemblyNameValues["processorArchitecture"]); - } - - // add the assembly name to the information cache - if (null != this.VariableCache) - { - string fileId = BindDatabaseCommand.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File); - string key = String.Concat("assemblyfullname.", fileId); - string assemblyName = String.Concat(assemblyNameValues["name"], ", version=", assemblyNameValues["version"], ", culture=", assemblyNameValues["culture"], ", publicKeyToken=", String.IsNullOrEmpty(assemblyNameValues["publicKeyToken"]) ? "null" : assemblyNameValues["publicKeyToken"]); - if (assemblyNameValues.ContainsKey("processorArchitecture")) - { - assemblyName = String.Concat(assemblyName, ", processorArchitecture=", assemblyNameValues["processorArchitecture"]); - } - - this.VariableCache[key] = assemblyName; - - // Add entries with the preserved case publicKeyToken - string pcAssemblyNameKey = String.Concat("assemblyfullnamepreservedcase.", fileId); - this.VariableCache[pcAssemblyNameKey] = (assemblyNameValues["publicKeyToken"] == assemblyNameValues["publicKeyTokenPreservedCase"]) ? assemblyName : assemblyName.Replace(assemblyNameValues["publicKeyToken"], assemblyNameValues["publicKeyTokenPreservedCase"]); - - string pcPublicKeyTokenKey = String.Concat("assemblypublickeytokenpreservedcase.", fileId); - this.VariableCache[pcPublicKeyTokenKey] = assemblyNameValues["publicKeyTokenPreservedCase"]; - } - } - else if (FileAssemblyType.Win32Assembly == file.WixFile.AssemblyType) - { - // TODO: Consider passing in the this.FileFacades as an indexed collection instead of searching through - // all files like this. Even though this is a rare case it looks like we might be able to index the - // file earlier. - FileFacade fileManifest = this.FileFacades.SingleOrDefault(r => r.File.File.Equals(file.WixFile.AssemblyManifest, StringComparison.Ordinal)); - if (null == fileManifest) - { - Messaging.Instance.OnMessage(WixErrors.MissingManifestForWin32Assembly(file.File.SourceLineNumbers, file.File.File, file.WixFile.AssemblyManifest)); - } - - string win32Type = null; - string win32Name = null; - string win32Version = null; - string win32ProcessorArchitecture = null; - string win32PublicKeyToken = null; - - // loading the dom is expensive we want more performant APIs than the DOM - // Navigator is cheaper than dom. Perhaps there is a cheaper API still. - try - { - XPathDocument doc = new XPathDocument(fileManifest.WixFile.Source); - XPathNavigator nav = doc.CreateNavigator(); - nav.MoveToRoot(); - - // this assumes a particular schema for a win32 manifest and does not - // provide error checking if the file does not conform to schema. - // The fallback case here is that nothing is added to the MsiAssemblyName - // table for an out of tolerance Win32 manifest. Perhaps warnings needed. - if (nav.MoveToFirstChild()) - { - while (nav.NodeType != XPathNodeType.Element || nav.Name != "assembly") - { - nav.MoveToNext(); - } - - if (nav.MoveToFirstChild()) - { - bool hasNextSibling = true; - while (nav.NodeType != XPathNodeType.Element || nav.Name != "assemblyIdentity" && hasNextSibling) - { - hasNextSibling = nav.MoveToNext(); - } - if (!hasNextSibling) - { - Messaging.Instance.OnMessage(WixErrors.InvalidManifestContent(file.File.SourceLineNumbers, fileManifest.WixFile.Source)); - return; - } - - if (nav.MoveToAttribute("type", String.Empty)) - { - win32Type = nav.Value; - nav.MoveToParent(); - } - - if (nav.MoveToAttribute("name", String.Empty)) - { - win32Name = nav.Value; - nav.MoveToParent(); - } - - if (nav.MoveToAttribute("version", String.Empty)) - { - win32Version = nav.Value; - nav.MoveToParent(); - } - - if (nav.MoveToAttribute("processorArchitecture", String.Empty)) - { - win32ProcessorArchitecture = nav.Value; - nav.MoveToParent(); - } - - if (nav.MoveToAttribute("publicKeyToken", String.Empty)) - { - win32PublicKeyToken = nav.Value; - nav.MoveToParent(); - } - } - } - } - catch (FileNotFoundException fe) - { - Messaging.Instance.OnMessage(WixErrors.FileNotFound(new SourceLineNumber(fileManifest.WixFile.Source), fe.FileName, "AssemblyManifest")); - } - catch (XmlException xe) - { - Messaging.Instance.OnMessage(WixErrors.InvalidXml(new SourceLineNumber(fileManifest.WixFile.Source), "manifest", xe.Message)); - } - - Table assemblyNameTable = this.Output.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); - if (!String.IsNullOrEmpty(win32Name)) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "name", win32Name); - } - - if (!String.IsNullOrEmpty(win32Version)) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "version", win32Version); - } - - if (!String.IsNullOrEmpty(win32Type)) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "type", win32Type); - } - - if (!String.IsNullOrEmpty(win32ProcessorArchitecture)) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "processorArchitecture", win32ProcessorArchitecture); - } - - if (!String.IsNullOrEmpty(win32PublicKeyToken)) - { - this.SetMsiAssemblyName(assemblyNameTable, file, "publicKeyToken", win32PublicKeyToken); - } - } - } - - /// - /// Set an MsiAssemblyName row. If it was directly authored, override the value, otherwise - /// create a new row. - /// - /// MsiAssemblyName table. - /// FileFacade containing the assembly read for the MsiAssemblyName row. - /// MsiAssemblyName name. - /// MsiAssemblyName value. - private void SetMsiAssemblyName(Table assemblyNameTable, FileFacade file, string name, string value) - { - // check for null value (this can occur when grabbing the file version from an assembly without one) - if (String.IsNullOrEmpty(value)) - { - Messaging.Instance.OnMessage(WixWarnings.NullMsiAssemblyNameValue(file.File.SourceLineNumbers, file.File.Component, name)); - } - else - { - Row assemblyNameRow = null; - - // override directly authored value - foreach (Row row in assemblyNameTable.Rows) - { - if ((string)row[0] == file.File.Component && (string)row[1] == name) - { - assemblyNameRow = row; - break; - } - } - - // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. - if ("name" == name && FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType && - String.IsNullOrEmpty(file.WixFile.AssemblyApplication) && - !String.Equals(Path.GetFileNameWithoutExtension(file.File.LongFileName), value, StringComparison.OrdinalIgnoreCase)) - { - Messaging.Instance.OnMessage(WixErrors.GACAssemblyIdentityWarning(file.File.SourceLineNumbers, Path.GetFileNameWithoutExtension(file.File.LongFileName), value)); - } - - if (null == assemblyNameRow) - { - assemblyNameRow = assemblyNameTable.CreateRow(file.File.SourceLineNumbers); - assemblyNameRow[0] = file.File.Component; - assemblyNameRow[1] = name; - assemblyNameRow[2] = value; - - // put the MsiAssemblyName row in the same section as the related File row - assemblyNameRow.SectionId = file.File.SectionId; - - if (null == file.AssemblyNames) - { - file.AssemblyNames = new List(); - } - - file.AssemblyNames.Add(assemblyNameRow); - } - else - { - assemblyNameRow[2] = value; - } - - if (this.VariableCache != null) - { - string key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, BindDatabaseCommand.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)).ToLowerInvariant(); - this.VariableCache[key] = (string)assemblyNameRow[2]; - } - } - } - } -} -- cgit v1.2.3-55-g6feb