public void Execute() { this.Messaging = this.ServiceProvider.GetService <IMessaging>(); var extensionManager = this.ServiceProvider.GetService <IExtensionManager>(); var context = this.ServiceProvider.GetService <ILayoutContext>(); context.Messaging = this.Messaging; context.Extensions = extensionManager.Create <ILayoutExtension>(); context.FileTransfers = this.FileTransfers; context.ContentFilePaths = this.ContentFilePaths; context.ContentsFile = this.ContentsFile; context.OutputPdbPath = this.OutputsFile; context.BuiltOutputsFile = this.BuiltOutputsFile; context.SuppressAclReset = this.SuppressAclReset; // Pre-layout. // foreach (var extension in context.Extensions) { extension.PreLayout(context); } try { // Final step in binding that transfers (moves/copies) all files generated into the appropriate // location in the source image. if (context.FileTransfers?.Any() == true) { this.Messaging.Write(VerboseMessages.LayingOutMedia()); var command = new TransferFilesCommand(context.Messaging, context.Extensions, context.FileTransfers, context.SuppressAclReset); command.Execute(); } } finally { if (!String.IsNullOrEmpty(context.ContentsFile) && context.ContentFilePaths != null) { this.CreateContentsFile(context.ContentsFile, context.ContentFilePaths); } if (!String.IsNullOrEmpty(context.OutputsFile) && context.FileTransfers != null) { this.CreateOutputsFile(context.OutputsFile, context.FileTransfers, context.OutputPdbPath); } if (!String.IsNullOrEmpty(context.BuiltOutputsFile) && context.FileTransfers != null) { this.CreateBuiltOutputsFile(context.BuiltOutputsFile, context.FileTransfers, context.OutputPdbPath); } } // Post-layout. foreach (var extension in context.Extensions) { extension.PostLayout(); } }
/// <summary> /// Update the ".wixburn" section data. /// </summary> /// <param name="stubSize">Size of the stub engine "burn.exe".</param> /// <param name="bundleId">Unique identifier for this bundle.</param> /// <returns></returns> public bool InitializeBundleSectionData(long stubSize, string bundleId) { if (this.invalidBundle) { return(false); } var bundleGuid = Guid.Parse(bundleId); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_MAGIC, BURN_SECTION_MAGIC); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_VERSION, BURN_SECTION_VERSION); this.messaging.Write(VerboseMessages.BundleGuid(bundleId)); this.binaryWriter.BaseStream.Seek(this.wixburnDataOffset + BURN_SECTION_OFFSET_BUNDLEGUID, SeekOrigin.Begin); this.binaryWriter.Write(bundleGuid.ToByteArray()); this.StubSize = (uint)stubSize; this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_STUBSIZE, this.StubSize); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALCHECKSUM, 0); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET, 0); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE, 0); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_FORMAT, 1); // Hard-coded to CAB for now. this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_COUNT, 0); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_UXSIZE, 0); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE, 0); this.binaryWriter.BaseStream.Flush(); this.EngineSize = this.StubSize; return(true); }
/// <summary> /// Sets the thead count to the number of processors if the current thread count is set to 0. /// </summary> /// <remarks>The thread count value must be greater than 0 otherwise and exception will be thrown.</remarks> 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(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } } else // default to 1 if the environment variable is not set { this.CabbingThreadCount = 1; } this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } catch (ArgumentException) { throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } catch (FormatException) { throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } } }
private void ResolveBundleInstallScope(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable <PackageFacade> facades) { var dependencySymbolsById = section.Symbols.OfType <WixDependencyProviderSymbol>().ToDictionary(t => t.Id.Id); foreach (var facade in facades) { if (bundleSymbol.PerMachine && YesNoDefaultType.No == facade.PackageSymbol.PerMachine) { this.Messaging.Write(VerboseMessages.SwitchingToPerUserPackage(facade.PackageSymbol.SourceLineNumbers, facade.PackageId)); bundleSymbol.Attributes &= ~WixBundleAttributes.PerMachine; break; } } foreach (var facade in facades) { // Update package scope from bundle scope if default. if (YesNoDefaultType.Default == facade.PackageSymbol.PerMachine) { facade.PackageSymbol.PerMachine = bundleSymbol.PerMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No; } // We will only register packages in the same scope as the bundle. Warn if any packages with providers // are in a different scope and not permanent (permanents typically don't need a ref-count). if (!bundleSymbol.PerMachine && YesNoDefaultType.Yes == facade.PackageSymbol.PerMachine && !facade.PackageSymbol.Permanent && dependencySymbolsById.ContainsKey(facade.PackageId)) { this.Messaging.Write(WarningMessages.NoPerMachineDependencies(facade.PackageSymbol.SourceLineNumbers, facade.PackageId)); } } }
private int CalculateCabbingThreadCount() { var cabbingThreadCount = 1; // default to 1 if the environment variable is not set. var numberOfProcessors = Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"); try { if (!String.IsNullOrEmpty(numberOfProcessors)) { cabbingThreadCount = Convert.ToInt32(numberOfProcessors, CultureInfo.InvariantCulture.NumberFormat); if (cabbingThreadCount <= 0) { throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } } this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } catch (ArgumentException) { throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } catch (FormatException) { throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } return(cabbingThreadCount); }
private void LogValidationMessage(ValidationMessage message) { var messageSourceLineNumbers = this.OutputSourceLineNumber; if (!String.IsNullOrEmpty(message.Table) && !String.IsNullOrEmpty(message.Column) && message.PrimaryKeys != null) { messageSourceLineNumbers = this.GetSourceLineNumbers(message.Table, message.PrimaryKeys); } switch (message.Type) { case ValidationMessageType.InternalFailure: case ValidationMessageType.Error: this.Messaging.Write(ErrorMessages.ValidationError(messageSourceLineNumbers, message.IceName, message.Description)); break; case ValidationMessageType.Warning: this.Messaging.Write(WarningMessages.ValidationWarning(messageSourceLineNumbers, message.IceName, message.Description)); break; case ValidationMessageType.Info: this.Messaging.Write(VerboseMessages.ValidationInfo(message.IceName, message.Description)); break; default: throw new WixException(ErrorMessages.InvalidValidatorMessageType(message.Type.ToString())); } }
public void Execute() { var bundleFilename = Path.GetFileName(this.OutputPath); // Copy the burn.exe to a writable location then mark it to be moved to its final build location. var stubPlatform = this.BundleSymbol.Platform.ToString(); var stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe"); if (stubPlatform != "X86") { this.Messaging.Write(WarningMessages.ExperimentalBundlePlatform(stubPlatform)); } var bundleTempPath = Path.Combine(this.IntermediateFolder, bundleFilename); this.Messaging.Write(VerboseMessages.GeneratingBundle(bundleTempPath, stubFile)); if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase)) { this.Messaging.Write(ErrorMessages.InsecureBundleFilename(bundleFilename)); } this.Transfer = this.BackendHelper.CreateFileTransfer(bundleTempPath, this.OutputPath, true, this.BundleSymbol.SourceLineNumbers); File.Copy(stubFile, bundleTempPath, true); File.SetAttributes(bundleTempPath, FileAttributes.Normal); var windowsAssemblyVersion = GetWindowsAssemblyVersion(this.BundleSymbol); var applicationManifestData = GenerateApplicationManifest(this.BundleSymbol, this.BootstrapperApplicationDllSymbol, this.OutputPath, windowsAssemblyVersion); UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol, windowsAssemblyVersion, applicationManifestData); // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers // if they should be attached. using (var writer = BurnWriter.Open(this.Messaging, bundleTempPath)) { var burnStubFile = new FileInfo(bundleTempPath); writer.InitializeBundleSectionData(burnStubFile.Length, this.BundleSymbol.BundleId); // Always attach the UX container first writer.AppendContainer(this.UXContainer.WorkingPath, BurnWriter.Container.UX); // Now append all other attached containers foreach (var container in this.Containers) { if (ContainerType.Attached == container.Type) { // The container was only created if it had payloads. if (!String.IsNullOrEmpty(container.WorkingPath) && BurnConstants.BurnUXContainerName != container.Id.Id) { writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached); } } } } }
/// <summary> /// Logs a message from the <see cref="Validator"/>. /// </summary> /// <param name="message">A <see cref="String"/> of tab-delmited tokens /// in the validation message.</param> /// <param name="action">The name of the action to which the message /// belongs.</param> /// <exception cref="ArgumentNullException">The message cannot be null. /// </exception> /// <exception cref="WixException">The message does not contain four (4) /// or more tab-delimited tokens.</exception> /// <remarks> /// <para><paramref name="message"/> a tab-delimited set of tokens, /// formatted according to Windows Installer guidelines for ICE /// message. The following table lists what each token by index /// should mean.</para> /// <para><paramref name="action"/> a name that represents the ICE /// action that was executed (e.g. 'ICE08').</para> /// <list type="table"> /// <listheader> /// <term>Index</term> /// <description>Description</description> /// </listheader> /// <item> /// <term>0</term> /// <description>Name of the ICE.</description> /// </item> /// <item> /// <term>1</term> /// <description>Message type. See the following list.</description> /// </item> /// <item> /// <term>2</term> /// <description>Detailed description.</description> /// </item> /// <item> /// <term>3</term> /// <description>Help URL or location.</description> /// </item> /// <item> /// <term>4</term> /// <description>Table name.</description> /// </item> /// <item> /// <term>5</term> /// <description>Column name.</description> /// </item> /// <item> /// <term>6</term> /// <description>This and remaining fields are primary keys /// to identify a row.</description> /// </item> /// </list> /// <para>The message types are one of the following value.</para> /// <list type="table"> /// <listheader> /// <term>Value</term> /// <description>Message Type</description> /// </listheader> /// <item> /// <term>0</term> /// <description>Failure message reporting the failure of the /// ICE custom action.</description> /// </item> /// <item> /// <term>1</term> /// <description>Error message reporting database authoring that /// case incorrect behavior.</description> /// </item> /// <item> /// <term>2</term> /// <description>Warning message reporting database authoring that /// causes incorrect behavior in certain cases. Warnings can also /// report unexpected side-effects of database authoring. /// </description> /// </item> /// <item> /// <term>3</term> /// <description>Informational message.</description> /// </item> /// </list> /// </remarks> public virtual void Log(string message, string action) { if (message == null) { throw new ArgumentNullException("message"); } string[] messageParts = message.Split('\t'); if (3 > messageParts.Length) { if (null == action) { throw new WixException(ErrorMessages.UnexpectedExternalUIMessage(message)); } else { throw new WixException(ErrorMessages.UnexpectedExternalUIMessage(message, action)); } } SourceLineNumber messageSourceLineNumbers = null; if (6 < messageParts.Length) { string[] primaryKeys = new string[messageParts.Length - 6]; Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length); messageSourceLineNumbers = this.GetSourceLineNumbers(messageParts[4], primaryKeys); } else // use the file name as the source line information { messageSourceLineNumbers = this.sourceLineNumbers; } switch (messageParts[1]) { case "0": case "1": this.messaging.Write(ErrorMessages.ValidationError(messageSourceLineNumbers, messageParts[0], messageParts[2])); break; case "2": this.messaging.Write(WarningMessages.ValidationWarning(messageSourceLineNumbers, messageParts[0], messageParts[2])); break; case "3": this.messaging.Write(VerboseMessages.ValidationInfo(messageParts[0], messageParts[2])); break; default: throw new WixException(ErrorMessages.InvalidValidatorMessageType(messageParts[1])); } }
public void Layout(ILayoutContext context) { // Pre-layout. // foreach (var extension in context.Extensions) { extension.PreLayout(context); } try { // Final step in binding that transfers (moves/copies) all files generated into the appropriate // location in the source image. if (context.FileTransfers?.Any() == true) { this.Messaging.Write(VerboseMessages.LayingOutMedia()); var command = new TransferFilesCommand(this.Messaging, context.Extensions, context.FileTransfers, context.SuppressAclReset); command.Execute(); } if (context.TrackedFiles != null) { this.CleanTempFiles(context.IntermediateFolder, context.TrackedFiles); } } finally { if (context.TrackedFiles != null) { if (!String.IsNullOrEmpty(context.ContentsFile)) { this.CreateContentsFile(context.ContentsFile, context.TrackedFiles); } if (!String.IsNullOrEmpty(context.OutputsFile)) { this.CreateOutputsFile(context.OutputsFile, context.TrackedFiles); } if (!String.IsNullOrEmpty(context.BuiltOutputsFile)) { this.CreateBuiltOutputsFile(context.BuiltOutputsFile, context.TrackedFiles); } } } // Post-layout. foreach (var extension in context.Extensions) { extension.PostLayout(); } }
/// <summary> /// Creates a cabinet using the wixcab.dll interop layer. /// </summary> /// <param name="cabinetWorkItem">CabinetWorkItem containing information about the cabinet to create.</param> private void CreateCabinet(CabinetWorkItem cabinetWorkItem) { this.Messaging.Write(VerboseMessages.CreateCabinet(cabinetWorkItem.CabinetFile)); int maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting ulong maxPreCompressedSizeInBytes = 0; if (this.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 = this.MaximumCabinetSizeForLargeFileSplitting; } } } } // create the cabinet file var cabinetPath = Path.GetFullPath(cabinetWorkItem.CabinetFile); string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); var files = cabinetWorkItem.FileFacades .Select(facade => facade.Hash == null ? new CabinetCompressFile(facade.WixFile.Source.Path, facade.File.File) : new CabinetCompressFile(facade.WixFile.Source.Path, facade.File.File, facade.Hash.HashPart1, facade.Hash.HashPart2, facade.Hash.HashPart3, facade.Hash.HashPart4)) .ToList(); var cabinetCompressionLevel = (CabinetCompressionLevel)cabinetWorkItem.CompressionLevel; var cab = new Cabinet(cabinetPath); cab.Compress(files, cabinetCompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold); // TODO: Handle newCabNamesCallBackAddress from compression. }
public void Execute() { this.lastCabinetAddedToMediaTable = new Dictionary <string, string>(); // If the cabbing thread count wasn't provided, default the number of cabbing threads to the number of processors. if (this.CabbingThreadCount <= 0) { this.CabbingThreadCount = this.CalculateCabbingThreadCount(); this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } // Send Binder object to Facilitate NewCabNamesCallBack Callback var cabinetBuilder = new CabinetBuilder(this.Messaging, this.CabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack)); // Supply Compile MediaTemplate Attributes to Cabinet Builder this.GetMediaTemplateAttributes(out var maximumCabinetSizeForLargeFileSplitting, out var maximumUncompressedMediaSize); cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = maximumCabinetSizeForLargeFileSplitting; cabinetBuilder.MaximumUncompressedMediaSize = maximumUncompressedMediaSize; foreach (var entry in this.FileFacadesByCabinet) { var mediaSymbol = entry.Key; var files = entry.Value; var compressionLevel = mediaSymbol.CompressionLevel ?? this.DefaultCompressionLevel ?? CompressionLevel.Medium; var cabinetDir = this.ResolveMedia(mediaSymbol, mediaSymbol.Layout, this.LayoutDirectory); var cabinetWorkItem = this.CreateCabinetWorkItem(this.Data, cabinetDir, mediaSymbol, compressionLevel, files); if (null != cabinetWorkItem) { cabinetBuilder.Enqueue(cabinetWorkItem); } } // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return; } // create queued cabinets with multiple threads cabinetBuilder.CreateQueuedCabinets(); if (this.Messaging.EncounteredError) { return; } }
public static bool ConfigVerboseMessages( XmlElement xmlElem, string name, ref VerboseMessages verbose, bool compulsory) { XmlNode xmlNode = XMLReader.GetNode(xmlElem, name); if (xmlNode == null && compulsory == false) { return(false); } else if (xmlNode == null && compulsory == true) { throw new ConfigNotFoundException(name); } ConfigBool((XmlElement)xmlNode, "AllFileOps", ref verbose.AllFileOps, compulsory); ConfigBool((XmlElement)xmlNode, "Deadlock", ref verbose.Deadlock, compulsory); ConfigBool((XmlElement)xmlNode, "FileOps", ref verbose.FileOps, compulsory); ConfigBool((XmlElement)xmlNode, "Recovery", ref verbose.Recovery, compulsory); ConfigBool((XmlElement)xmlNode, "Register", ref verbose.Register, compulsory); ConfigBool((XmlElement)xmlNode, "Replication", ref verbose.Replication, compulsory); ConfigBool((XmlElement)xmlNode, "ReplicationElection", ref verbose.ReplicationElection, compulsory); ConfigBool((XmlElement)xmlNode, "ReplicationLease", ref verbose.ReplicationLease, compulsory); ConfigBool((XmlElement)xmlNode, "ReplicationMessages", ref verbose.ReplicationMessages, compulsory); ConfigBool((XmlElement)xmlNode, "ReplicationMisc", ref verbose.ReplicationMisc, compulsory); ConfigBool((XmlElement)xmlNode, "ReplicationSync", ref verbose.ReplicationSync, compulsory); ConfigBool((XmlElement)xmlNode, "RepMgrConnectionFailure", ref verbose.RepMgrConnectionFailure, compulsory); ConfigBool((XmlElement)xmlNode, "RepMgrMisc", ref verbose.RepMgrMisc, compulsory); ConfigBool((XmlElement)xmlNode, "WaitsForTable", ref verbose.WaitsForTable, compulsory); return(true); }
/// <summary> /// Creates a cabinet using the wixcab.dll interop layer. /// </summary> /// <param name="cabinetWorkItem">CabinetWorkItem containing information about the cabinet to create.</param> private void CreateCabinet(CabinetWorkItem cabinetWorkItem) { this.Messaging.Write(VerboseMessages.CreateCabinet(cabinetWorkItem.CabinetFile)); var maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting ulong maxPreCompressedSizeInBytes = 0; if (this.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)this.MaximumUncompressedMediaSize * 1024 * 1024; var facade = cabinetWorkItem.FileFacades.First(); // If the file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting if ((ulong)facade.FileSize >= maxPreCompressedSizeInBytes) { maxCabinetSize = this.MaximumCabinetSizeForLargeFileSplitting; } } } // create the cabinet file var cabinetPath = Path.GetFullPath(cabinetWorkItem.CabinetFile); var files = cabinetWorkItem.FileFacades .OrderBy(f => f.Sequence) .Select(facade => facade.Hash == null ? new CabinetCompressFile(facade.SourcePath, facade.Id + cabinetWorkItem.ModularizationSuffix) : new CabinetCompressFile(facade.SourcePath, facade.Id + cabinetWorkItem.ModularizationSuffix, facade.Hash.HashPart1, facade.Hash.HashPart2, facade.Hash.HashPart3, facade.Hash.HashPart4)) .ToList(); var cab = new Cabinet(cabinetPath); cab.Compress(files, cabinetWorkItem.CompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold); // TODO: Handle newCabNamesCallBackAddress from compression. }
public void Execute() { var trackedFiles = new List <ITrackedFile>(); var stopwatch = Stopwatch.StartNew(); this.Messaging.Write(VerboseMessages.ValidatingDatabase()); // Ensure the temporary files can be created the working folder. var workingFolder = Path.Combine(this.IntermediateFolder, "_validate"); Directory.CreateDirectory(workingFolder); // Copy the database to a temporary location so it can be manipulated. // Ensure it is not read-only. var workingDatabasePath = Path.Combine(workingFolder, Path.GetFileName(this.OutputPath)); FileSystem.CopyFile(this.OutputPath, workingDatabasePath, allowHardlink: false); var trackWorkingDatabase = this.BackendHelper.TrackFile(workingDatabasePath, TrackedFileType.Temporary); trackedFiles.Add(trackWorkingDatabase); var attributes = File.GetAttributes(workingDatabasePath); File.SetAttributes(workingDatabasePath, attributes & ~FileAttributes.ReadOnly); var validator = new WindowsInstallerValidator(this, workingDatabasePath, this.CubeFiles, this.Ices, this.SuppressedIces); validator.Execute(); stopwatch.Stop(); this.Messaging.Write(VerboseMessages.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); this.TrackedFiles = trackedFiles; }
public IBindResult Execute() { if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) && !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved)) { this.Messaging.Write(ErrorMessages.IntermediatesMustBeResolved(this.Intermediate.Id)); } var section = this.Intermediate.Sections.Single(); var fileTransfers = new List <IFileTransfer>(); var trackedFiles = new List <ITrackedFile>(); var containsMergeModules = false; // If there are any fields to resolve later, create the cache to populate during bind. var variableCache = this.DelayedFields.Any() ? new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase) : null; // Load standard tables, authored custom tables, and extension custom tables. TableDefinitionCollection tableDefinitions; { var command = new LoadTableDefinitionsCommand(this.Messaging, section, this.BackendExtensions); command.Execute(); tableDefinitions = command.TableDefinitions; } // Process the summary information table before the other tables. bool compressed; bool longNames; int installerVersion; string modularizationSuffix; { var command = new BindSummaryInfoCommand(section); command.Execute(); compressed = command.Compressed; longNames = command.LongNames; installerVersion = command.InstallerVersion; modularizationSuffix = command.ModularizationSuffix; } // Add binder variables for all properties. if (SectionType.Product == section.Type || variableCache != null) { foreach (var propertyRow in section.Symbols.OfType <PropertySymbol>()) { // Set the ProductCode if it is to be generated. if ("ProductCode".Equals(propertyRow.Id.Id, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal)) { propertyRow.Value = Common.GenerateGuid(); #if TODO_PATCHING // Is this still necessary? // Update the target ProductCode in any instance transforms. foreach (SubStorage subStorage in this.Output.SubStorages) { Output subStorageOutput = subStorage.Data; if (OutputType.Transform != subStorageOutput.Type) { continue; } Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; foreach (Row row in instanceSummaryInformationTable.Rows) { if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) { row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); break; } } } #endif } // Add the property name and value to the variableCache. if (variableCache != null) { var key = String.Concat("property.", propertyRow.Id.Id); variableCache[key] = propertyRow.Value; } } } // Sequence all the actions. { var command = new SequenceActionsCommand(this.Messaging, section); command.Execute(); } { var command = new CreateSpecialPropertiesCommand(section); command.Execute(); } #if TODO_PATCHING ////if (OutputType.Patch == this.Output.Type) ////{ //// foreach (SubStorage substorage in this.Output.SubStorages) //// { //// Output transform = substorage.Data; //// ResolveFieldsCommand command = new ResolveFieldsCommand(); //// command.Tables = transform.Tables; //// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; //// command.FileManagerCore = this.FileManagerCore; //// command.FileManagers = this.FileManagers; //// command.SupportDelayedResolution = false; //// command.TempFilesLocation = this.TempFilesLocation; //// command.WixVariableResolver = this.WixVariableResolver; //// command.Execute(); //// this.MergeUnrealTables(transform.Tables); //// } ////} #endif if (this.Messaging.EncounteredError) { return(null); } this.Intermediate.UpdateLevel(Data.WindowsInstaller.IntermediateLevels.FullyBound); this.Messaging.Write(VerboseMessages.UpdatingFileInformation()); // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). { var command = new ExtractEmbeddedFilesCommand(this.BackendHelper, this.ExpectedEmbeddedFiles); command.Execute(); trackedFiles.AddRange(command.TrackedFiles); } // This must occur after all variables and source paths have been resolved. List <FileFacade> fileFacades; if (SectionType.Patch == section.Type) { var command = new GetFileFacadesFromTransforms(this.Messaging, this.FileSystemManager, this.SubStorages); command.Execute(); fileFacades = command.FileFacades; } else { var command = new GetFileFacadesCommand(section); command.Execute(); fileFacades = command.FileFacades; } // Retrieve file information from merge modules. if (SectionType.Product == section.Type) { var wixMergeSymbols = section.Symbols.OfType <WixMergeSymbol>().ToList(); if (wixMergeSymbols.Any()) { containsMergeModules = true; var command = new ExtractMergeModuleFilesCommand(this.Messaging, wixMergeSymbols, fileFacades, installerVersion, this.IntermediateFolder, this.SuppressLayout); command.Execute(); fileFacades.AddRange(command.MergeModulesFileFacades); } } // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return(null); } // Gather information about files that do not come from merge modules. { var command = new UpdateFileFacadesCommand(this.Messaging, section, fileFacades, fileFacades.Where(f => !f.FromModule), variableCache, overwriteHash: true); command.Execute(); } // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return(null); } // Now that the variable cache is populated, resolve any delayed fields. if (this.DelayedFields.Any()) { var command = new ResolveDelayedFieldsCommand(this.Messaging, this.DelayedFields, variableCache); command.Execute(); } #if TODO_FINISH_UPDATE // use symbols instead of rows // Extended binder extensions can be called now that fields are resolved. { Table updatedFiles = this.Output.EnsureTable(this.TableDefinitions["WixBindUpdatedFiles"]); foreach (IBinderExtension extension in this.Extensions) { extension.AfterResolvedFields(this.Output); } List <FileFacade> updatedFileFacades = new List <FileFacade>(); foreach (Row updatedFile in updatedFiles.Rows) { string updatedId = updatedFile.FieldAsString(0); FileFacade updatedFacade = fileFacades.First(f => f.File.File.Equals(updatedId)); updatedFileFacades.Add(updatedFacade); } if (updatedFileFacades.Any()) { UpdateFileFacadesCommand command = new UpdateFileFacadesCommand(this.Messaging, section, fileFacades, updateFileFacades, variableCache, overwriteHash: false); //command.FileFacades = fileFacades; //command.UpdateFileFacades = updatedFileFacades; //command.ModularizationGuid = modularizationGuid; //command.Output = this.Output; //command.OverwriteHash = true; //command.TableDefinitions = this.TableDefinitions; //command.VariableCache = variableCache; command.Execute(); } } #endif // Set generated component guids. { var command = new CalculateComponentGuids(this.Messaging, this.BackendHelper, this.PathResolver, section); command.Execute(); } { var command = new ValidateComponentGuidsCommand(this.Messaging, section); command.Execute(); } // Add missing CreateFolder symbols to null-keypath components. { var command = new AddCreateFoldersCommand(section); command.Execute(); } // Update symbols that reference text files on disk. { var command = new UpdateFromTextFilesCommand(this.Messaging, section); command.Execute(); } // Assign files to media and update file sequences. Dictionary <MediaSymbol, IEnumerable <FileFacade> > filesByCabinetMedia; IEnumerable <FileFacade> uncompressedFiles; { var order = new OptimizeFileFacadesOrderCommand(fileFacades); order.Execute(); fileFacades = order.FileFacades; var assign = new AssignMediaCommand(section, this.Messaging, fileFacades, compressed); assign.Execute(); filesByCabinetMedia = assign.FileFacadesByCabinetMedia; uncompressedFiles = assign.UncompressedFileFacades; var update = new UpdateMediaSequencesCommand(section, fileFacades); update.Execute(); } // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return(null); } // Time to create the output object. Try to put as much above here as possible, updating the IR is better. WindowsInstallerData output; { var command = new CreateOutputFromIRCommand(this.Messaging, section, tableDefinitions, this.BackendExtensions, this.WindowsInstallerBackendHelper); command.Execute(); output = command.Output; } IEnumerable <string> suppressedTableNames = null; if (output.Type == OutputType.Module) { // Modularize identifiers. var modularize = new ModularizeCommand(output, modularizationSuffix, section.Symbols.OfType <WixSuppressModularizationSymbol>()); modularize.Execute(); // Ensure all sequence tables in place because, mergemod.dll requires them. var unsuppress = new AddBackSuppressedSequenceTablesCommand(output, tableDefinitions); suppressedTableNames = unsuppress.Execute(); } else if (output.Type == OutputType.Patch) { foreach (var storage in this.SubStorages) { output.SubStorages.Add(storage); } } // Stop processing if an error previously occurred. if (this.Messaging.EncounteredError) { return(null); } // Ensure the intermediate folder is created since delta patches will be // created there. Directory.CreateDirectory(this.IntermediateFolder); if (SectionType.Patch == section.Type && this.DeltaBinaryPatch) { var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Symbols.OfType <WixPatchIdSymbol>().FirstOrDefault()); command.Execute(); } // create cabinet files and process uncompressed files var layoutDirectory = Path.GetDirectoryName(this.OutputPath); if (!this.SuppressLayout || OutputType.Module == output.Type) { this.Messaging.Write(VerboseMessages.CreatingCabinetFiles()); var mediaTemplate = section.Symbols.OfType <WixMediaTemplateSymbol>().FirstOrDefault(); var command = new CreateCabinetsCommand(this.ServiceProvider, this.BackendHelper, mediaTemplate); command.CabbingThreadCount = this.CabbingThreadCount; command.CabCachePath = this.CabCachePath; command.DefaultCompressionLevel = this.DefaultCompressionLevel; command.Output = output; command.Messaging = this.Messaging; command.BackendExtensions = this.BackendExtensions; command.LayoutDirectory = layoutDirectory; command.Compressed = compressed; command.ModularizationSuffix = modularizationSuffix; command.FileFacadesByCabinet = filesByCabinetMedia; command.ResolveMedia = this.ResolveMedia; command.TableDefinitions = tableDefinitions; command.IntermediateFolder = this.IntermediateFolder; command.Execute(); fileTransfers.AddRange(command.FileTransfers); trackedFiles.AddRange(command.TrackedFiles); } // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return(null); } // We can create instance transforms since Component Guids and Outputs are created. if (output.Type == OutputType.Product) { var command = new CreateInstanceTransformsCommand(section, output, tableDefinitions, this.BackendHelper); command.Execute(); } else if (output.Type == OutputType.Patch) { // Copy output data back into the transforms. var command = new UpdateTransformsWithFileFacades(this.Messaging, output, this.SubStorages, tableDefinitions, fileFacades); command.Execute(); } // Generate database file. this.Messaging.Write(VerboseMessages.GeneratingDatabase()); { var trackMsi = this.BackendHelper.TrackFile(this.OutputPath, TrackedFileType.Final); trackedFiles.Add(trackMsi); var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, trackMsi.Path, tableDefinitions, this.IntermediateFolder, this.Codepage, keepAddedColumns: false, this.SuppressAddingValidationRows, useSubdirectory: false); command.Execute(); trackedFiles.AddRange(command.GeneratedTemporaryFiles); } // Stop processing if an error previously occurred. if (this.Messaging.EncounteredError) { return(null); } // Merge modules. if (containsMergeModules) { this.Messaging.Write(VerboseMessages.MergingModules()); var command = new MergeModulesCommand(this.Messaging, fileFacades, section, suppressedTableNames, this.OutputPath, this.IntermediateFolder); command.Execute(); } if (this.Messaging.EncounteredError) { return(null); } #if TODO_FINISH_VALIDATION // Validate the output if there is an MSI validator. if (null != this.Validator) { Stopwatch stopwatch = Stopwatch.StartNew(); // set the output file for source line information this.Validator.Output = this.Output; Messaging.Instance.Write(WixVerboses.ValidatingDatabase()); this.Validator.Validate(this.OutputPath); stopwatch.Stop(); Messaging.Instance.Write(WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); // Stop processing if an error occurred. if (Messaging.Instance.EncounteredError) { return; } } #endif // Process uncompressed files. if (!this.Messaging.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any()) { var command = new ProcessUncompressedFilesCommand(section, this.BackendHelper, this.PathResolver); command.Compressed = compressed; command.FileFacades = uncompressedFiles; command.LayoutDirectory = layoutDirectory; command.LongNamesInImage = longNames; command.ResolveMedia = this.ResolveMedia; command.DatabasePath = this.OutputPath; command.Execute(); fileTransfers.AddRange(command.FileTransfers); trackedFiles.AddRange(command.TrackedFiles); } // TODO: this is not sufficient to collect all Input files (for example, it misses Binary and Icon tables). trackedFiles.AddRange(fileFacades.Select(f => this.BackendHelper.TrackFile(f.SourcePath, TrackedFileType.Input, f.SourceLineNumber))); var result = this.ServiceProvider.GetService <IBindResult>(); result.FileTransfers = fileTransfers; result.TrackedFiles = trackedFiles; result.Wixout = this.CreateWixout(trackedFiles, this.Intermediate, output); return(result); }
public void LogVerbose(string data) { Messages.Enqueue(data); VerboseMessages.Enqueue(data); DumpMessage("TRACE", data); }
/// <summary> /// Validate a database. /// </summary> /// <param name="databaseFile">The database to validate.</param> /// <returns>true if validation succeeded; false otherwise.</returns> public void Validate(string databaseFile) { int previousUILevel = (int)InstallUILevels.Basic; IntPtr previousHwnd = IntPtr.Zero; InstallUIHandler previousUIHandler = null; if (null == databaseFile) { throw new ArgumentNullException("databaseFile"); } // initialize the validator extension this.extension.DatabaseFile = databaseFile; this.extension.Output = this.output; this.extension.InitializeValidator(); // Ensure the temporary files can be created. Directory.CreateDirectory(this.IntermediateFolder); // copy the database to a temporary location so it can be manipulated string tempDatabaseFile = Path.Combine(this.IntermediateFolder, Path.GetFileName(databaseFile)); File.Copy(databaseFile, tempDatabaseFile); // remove the read-only property from the temporary database FileAttributes attributes = File.GetAttributes(tempDatabaseFile); File.SetAttributes(tempDatabaseFile, attributes & ~FileAttributes.ReadOnly); Mutex mutex = new Mutex(false, "WixValidator"); try { if (!mutex.WaitOne(0, false)) { this.messaging.Write(VerboseMessages.ValidationSerialized()); mutex.WaitOne(); } using (Database database = new Database(tempDatabaseFile, OpenDatabase.Direct)) { bool propertyTableExists = database.TableExists("Property"); string productCode = null; // remove the product code from the database before opening a session to prevent opening an installed product if (propertyTableExists) { using (View view = database.OpenExecuteView("SELECT `Value` FROM `Property` WHERE Property = 'ProductCode'")) { using (Record record = view.Fetch()) { if (null != record) { productCode = record.GetString(1); using (View dropProductCodeView = database.OpenExecuteView("DELETE FROM `Property` WHERE `Property` = 'ProductCode'")) { } } } } } // merge in the cube databases foreach (string cubeFile in this.cubeFiles) { try { using (Database cubeDatabase = new Database(cubeFile, OpenDatabase.ReadOnly)) { try { database.Merge(cubeDatabase, "MergeConflicts"); } catch { // ignore merge errors since they are expected in the _Validation table } } } catch (Win32Exception e) { if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED { throw new WixException(ErrorMessages.CubeFileNotFound(cubeFile)); } throw; } } // commit the database before proceeding to ensure the streams don't get confused database.Commit(); // the property table may have been added to the database // from a cub database without the proper validation rows if (!propertyTableExists) { using (View view = database.OpenExecuteView("DROP table `Property`")) { } } // get all the action names for ICEs which have not been suppressed List <string> actions = new List <string>(); using (View view = database.OpenExecuteView("SELECT `Action` FROM `_ICESequence` ORDER BY `Sequence`")) { while (true) { using (Record record = view.Fetch()) { if (null == record) { break; } string action = record.GetString(1); if ((this.SuppressedICEs == null || !this.SuppressedICEs.Contains(action)) && (this.ICEs == null || this.ICEs.Contains(action))) { actions.Add(action); } } } } // disable the internal UI handler and set an external UI handler previousUILevel = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd); previousUIHandler = Installer.SetExternalUI(this.validationUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero); // create a session for running the ICEs this.validationSessionComplete = false; using (Session session = new Session(database)) { // add the product code back into the database if (null != productCode) { // some CUBs erroneously have a ProductCode property, so delete it if we just picked one up using (View dropProductCodeView = database.OpenExecuteView("DELETE FROM `Property` WHERE `Property` = 'ProductCode'")) { } using (View view = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "INSERT INTO `Property` (`Property`, `Value`) VALUES ('ProductCode', '{0}')", productCode))) { } } foreach (string action in actions) { this.actionName = action; try { session.DoAction(action); } catch (Win32Exception e) { if (!this.messaging.EncounteredError) { throw e; } // TODO: Review why this was clearing the error state when an exception had happened but an error was already encountered. That's weird. //else //{ // this.encounteredError = false; //} } this.actionName = null; } // Mark the validation session complete so we ignore any messages that MSI may fire // during session clean-up. this.validationSessionComplete = true; } } } catch (Win32Exception e) { // avoid displaying errors twice since one may have already occurred in the UI handler if (!this.messaging.EncounteredError) { if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED { // databaseFile is not passed since during light // this would be the temporary copy and there would be // no final output since the error occured; during smoke // they should know the path passed into smoke this.messaging.Write(ErrorMessages.ValidationFailedToOpenDatabase()); } else if (0x64D == e.NativeErrorCode) { this.messaging.Write(ErrorMessages.ValidationFailedDueToLowMsiEngine()); } else if (0x654 == e.NativeErrorCode) { this.messaging.Write(ErrorMessages.ValidationFailedDueToInvalidPackage()); } else if (0x658 == e.NativeErrorCode) { this.messaging.Write(ErrorMessages.ValidationFailedDueToMultilanguageMergeModule()); } else if (0x659 == e.NativeErrorCode) { this.messaging.Write(WarningMessages.ValidationFailedDueToSystemPolicy()); } else { string msgTemp = e.Message; if (null != this.actionName) { msgTemp = String.Concat("Action - '", this.actionName, "' ", e.Message); } this.messaging.Write(ErrorMessages.Win32Exception(e.NativeErrorCode, msgTemp)); } } } finally { Installer.SetExternalUI(previousUIHandler, 0, IntPtr.Zero); Installer.SetInternalUI(previousUILevel, ref previousHwnd); this.validationSessionComplete = false; // no validation session at this point, so reset the completion flag. mutex.ReleaseMutex(); this.cubeFiles.Clear(); this.extension.FinalizeValidator(); } }
public void Verbose(string message) { VerboseMessages.Add(message); }
public void Execute() { var wixMergeSymbols = this.Section.Symbols.OfType <WixMergeSymbol>().ToList(); if (!wixMergeSymbols.Any()) { return; } IMsmMerge2 merge = null; var commit = true; var logOpen = false; var databaseOpen = false; var logPath = Path.Combine(this.IntermediateFolder, "merge.log"); try { merge = MsmInterop.GetMsmMerge(); merge.OpenLog(logPath); logOpen = true; merge.OpenDatabase(this.OutputPath); databaseOpen = true; var featureModulesByMergeId = this.Section.Symbols.OfType <WixFeatureModulesSymbol>().GroupBy(t => t.WixMergeRef).ToDictionary(g => g.Key); // process all the merge rows foreach (var wixMergeRow in wixMergeSymbols) { var moduleOpen = false; try { short mergeLanguage; try { mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); } catch (FormatException) { this.Messaging.Write(ErrorMessages.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, wixMergeRow.Language.ToString())); continue; } this.Messaging.Write(VerboseMessages.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. this.Messaging.Write(VerboseMessages.MergingMergeModule(wixMergeRow.SourceFile)); merge.MergeEx(wixMergeRow.FeatureRef, wixMergeRow.DirectoryRef, callback); // Connect any non-primary features. if (featureModulesByMergeId.TryGetValue(wixMergeRow.Id.Id, out var featureModules)) { foreach (var featureModule in featureModules) { this.Messaging.Write(VerboseMessages.ConnectingMergeModule(wixMergeRow.SourceFile, featureModule.FeatureRef)); merge.Connect(featureModule.FeatureRef); } } } catch (COMException) { commit = false; } finally { var mergeErrors = merge.Errors; // display all the errors encountered during the merge operations for this module for (var i = 1; i <= mergeErrors.Count; i++) { var mergeError = mergeErrors[i]; var databaseKeys = new StringBuilder(); var moduleKeys = new StringBuilder(); // build a string of the database keys for (var 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 (var 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: this.Messaging.Write(ErrorMessages.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, moduleKeys.ToString())); break; case MsmErrorType.msmErrorFeatureRequired: this.Messaging.Write(ErrorMessages.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id.Id)); break; case MsmErrorType.msmErrorLanguageFailed: this.Messaging.Write(ErrorMessages.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorLanguageUnsupported: this.Messaging.Write(ErrorMessages.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorResequenceMerge: this.Messaging.Write(WarningMessages.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorTableMerge: if ("_Validation" != mergeError.DatabaseTable) // ignore merge errors in the _Validation table { this.Messaging.Write(WarningMessages.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); } break; case MsmErrorType.msmErrorPlatformMismatch: this.Messaging.Write(ErrorMessages.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile)); break; default: this.Messaging.Write(ErrorMessages.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, "Encountered an unexpected merge error of type '{0}' for which there is currently no error message to display. More information about the merge and the failure can be found in the merge log: '{1}'", Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace)); break; } } if (0 >= mergeErrors.Count && !commit) { this.Messaging.Write(ErrorMessages.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, "Encountered an unexpected error while merging '{0}'. More information about the merge and the failure can be found in the merge log: '{1}'", 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 (this.Messaging.EncounteredError) { return; } using (var db = new Database(this.OutputPath, OpenDatabase.Direct)) { // Suppress individual actions. foreach (var suppressAction in this.Section.Symbols.OfType <WixSuppressActionSymbol>()) { var tableName = suppressAction.SequenceTable.WindowsInstallerTableName(); if (db.TableExists(tableName)) { var query = $"SELECT * FROM {tableName} WHERE `Action` = '{suppressAction.Action}'"; using (var view = db.OpenExecuteView(query)) using (var record = view.Fetch()) { if (null != record) { this.Messaging.Write(WarningMessages.SuppressMergedAction(suppressAction.Action, tableName)); view.Modify(ModifyView.Delete, record); } } } } // Query for merge module actions in suppressed sequences and drop them. foreach (var tableName in this.SuppressedTableNames) { if (!db.TableExists(tableName)) { continue; } using (var view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) { foreach (var resultRecord in view.Records) { this.Messaging.Write(WarningMessages.SuppressMergedAction(resultRecord.GetString(1), tableName)); } } // drop suppressed sequences using (var view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName))) { } // delete the validation rows using (var view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?"))) using (var record = new Record(1)) { record.SetString(1, tableName); view.Execute(record); } } // now update the Attributes column for the files from the Merge Modules this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles()); using (var view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) { foreach (var file in this.FileFacades) { if (!file.FromModule) { continue; } using (var record = new Record(1)) { record.SetString(1, file.Id); view.Execute(record); } using (var 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.Sequence); // Update the file attributes to match the compression specified // on the Merge element or on the Package element. var attributes = 0; // Get the current value if its not null. if (!recordUpdate.IsNull(2)) { attributes = recordUpdate.GetInteger(2); } if (file.Compressed) { attributes |= WindowsInstallerConstants.MsidbFileAttributesCompressed; attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed; } else if (file.Uncompressed) { attributes |= WindowsInstallerConstants.MsidbFileAttributesNoncompressed; attributes &= ~WindowsInstallerConstants.MsidbFileAttributesCompressed; } else // clear all compression bits. { attributes &= ~WindowsInstallerConstants.MsidbFileAttributesCompressed; attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed; } recordUpdate.SetInteger(2, attributes); view.Modify(ModifyView.Update, recordUpdate); } } } db.Commit(); } }
/// <summary> /// Parse the commandline arguments. /// </summary> /// <param name="args">Commandline arguments.</param> public string[] Parse(string[] args) { List <string> unprocessed = new List <string>(); for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (String.IsNullOrEmpty(arg)) // skip blank arguments { continue; } if (1 == arg.Length) // treat '-' and '@' as filenames when by themselves. { unprocessed.Add(arg); } else if ('-' == arg[0] || '/' == arg[0]) { string parameter = arg.Substring(1); if (parameter.Equals("b", StringComparison.Ordinal)) { if (!CommandLineHelper.IsValidArg(args, ++i)) { break; } var bindPath = BindPath.Parse(args[i]); this.BindPaths.Add(bindPath); } else if (parameter.StartsWith("cultures:", StringComparison.Ordinal)) { string culturesString = arg.Substring(10).ToLower(CultureInfo.InvariantCulture); // When null is used treat it as if cultures wasn't specified. // This is needed for batching over the light task when using MSBuild which doesn't // support empty items if (culturesString.Equals("null", StringComparison.OrdinalIgnoreCase)) { this.Cultures = null; } else { this.Cultures = culturesString.Split(';', ','); for (int c = 0; c < this.Cultures.Length; ++c) { // Neutral is different from null. For neutral we still want to do WXL filtering. // Set the culture to the empty string = identifier for the invariant culture if (this.Cultures[c].Equals("neutral", StringComparison.OrdinalIgnoreCase)) { this.Cultures[c] = String.Empty; } } } } else if (parameter.StartsWith("dcl:", StringComparison.Ordinal)) { string defaultCompressionLevel = arg.Substring(5); if (String.IsNullOrEmpty(defaultCompressionLevel)) { break; } else if (Enum.TryParse(defaultCompressionLevel, true, out CompressionLevel compressionLevel)) { this.DefaultCompressionLevel = compressionLevel; } } else if (parameter.StartsWith("d", StringComparison.Ordinal)) { parameter = arg.Substring(2); string[] value = parameter.Split("=".ToCharArray(), 2); string preexisting; if (1 == value.Length) { this.Messaging.Write(ErrorMessages.ExpectedWixVariableValue(value[0])); } else if (this.Variables.TryGetValue(value[0], out preexisting)) { this.Messaging.Write(ErrorMessages.WixVariableCollision(null, value[0])); } else { this.Variables.Add(value[0], value[1]); } } else if (parameter.Equals("ext", StringComparison.Ordinal)) { if (!CommandLineHelper.IsValidArg(args, ++i)) { this.Messaging.Write(ErrorMessages.TypeSpecificationForExtensionRequired("-ext")); break; } this.Extensions.Add(args[i]); } else if (parameter.Equals("loc", StringComparison.Ordinal)) { string locFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(locFile)) { break; } this.LocalizationFiles.Add(locFile); } else if (parameter.Equals("nologo", StringComparison.Ordinal)) { this.ShowLogo = false; } else if (parameter.Equals("notidy", StringComparison.Ordinal)) { this.Tidy = false; } else if ("o" == parameter || "out" == parameter) { this.OutputFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.OutputFile)) { break; } } else if (parameter.Equals("pedantic", StringComparison.Ordinal)) { this.ShowPedanticMessages = true; } else if (parameter.Equals("sloc", StringComparison.Ordinal)) { this.SuppressLocalization = true; } else if (parameter.Equals("usf", StringComparison.Ordinal)) { this.UnreferencedSymbolsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.UnreferencedSymbolsFile)) { break; } } else if (parameter.Equals("xo", StringComparison.Ordinal)) { this.OutputXml = true; } else if (parameter.Equals("cc", StringComparison.Ordinal)) { this.CabCachePath = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.CabCachePath)) { break; } } else if (parameter.Equals("ct", StringComparison.Ordinal)) { if (!CommandLineHelper.IsValidArg(args, ++i)) { this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(String.Empty)); break; } int ct = 0; if (!Int32.TryParse(args[i], out ct) || 0 >= ct) { this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(args[i])); break; } this.CabbingThreadCount = ct; this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } else if (parameter.Equals("cub", StringComparison.Ordinal)) { string cubeFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(cubeFile)) { break; } this.CubeFiles.Add(cubeFile); } else if (parameter.StartsWith("ice:", StringComparison.Ordinal)) { this.Ices.Add(parameter.Substring(4)); } else if (parameter.Equals("intermediatefolder", StringComparison.OrdinalIgnoreCase)) { this.IntermediateFolder = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.IntermediateFolder)) { break; } } else if (parameter.Equals("contentsfile", StringComparison.Ordinal)) { this.ContentsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.ContentsFile)) { break; } } else if (parameter.Equals("outputsfile", StringComparison.Ordinal)) { this.OutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.OutputsFile)) { break; } } else if (parameter.Equals("builtoutputsfile", StringComparison.Ordinal)) { this.BuiltOutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.BuiltOutputsFile)) { break; } } else if (parameter.Equals("wixprojectfile", StringComparison.Ordinal)) { this.WixprojectFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.WixprojectFile)) { break; } } else if (parameter.Equals("pdbout", StringComparison.Ordinal)) { this.PdbFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); if (String.IsNullOrEmpty(this.PdbFile)) { break; } } else if (parameter.StartsWith("sice:", StringComparison.Ordinal)) { this.SuppressIces.Add(parameter.Substring(5)); } else if (parameter.Equals("sl", StringComparison.Ordinal)) { this.SuppressLayout = true; } else if (parameter.Equals("spdb", StringComparison.Ordinal)) { this.SuppressWixPdb = true; } else if (parameter.Equals("sacl", StringComparison.Ordinal)) { this.SuppressAclReset = true; } else if (parameter.Equals("sval", StringComparison.Ordinal)) { this.SuppressValidation = true; } else if ("sv" == parameter) { this.SuppressVersionCheck = true; } else if (parameter.StartsWith("sw", StringComparison.Ordinal)) { string paramArg = parameter.Substring(2); if (0 == paramArg.Length) { this.Messaging.SuppressAllWarnings = true; } else { int suppressWarning = 0; if (!Int32.TryParse(paramArg, out suppressWarning) || 0 >= suppressWarning) { this.Messaging.Write(ErrorMessages.IllegalSuppressWarningId(paramArg)); } else { this.Messaging.SuppressWarningMessage(suppressWarning); } } } else if (parameter.StartsWith("wx", StringComparison.Ordinal)) { string paramArg = parameter.Substring(2); if (0 == paramArg.Length) { this.Messaging.WarningsAsError = true; } else { int elevateWarning = 0; if (!Int32.TryParse(paramArg, out elevateWarning) || 0 >= elevateWarning) { this.Messaging.Write(ErrorMessages.IllegalWarningIdAsError(paramArg)); } else { this.Messaging.ElevateWarningMessage(elevateWarning); } } } else if ("v" == parameter) { this.Messaging.ShowVerboseMessages = true; } else if ("?" == parameter || "help" == parameter) { this.ShowHelp = true; break; } else { unprocessed.Add(arg); } } else if ('@' == arg[0]) { string[] parsedArgs = CommandLineResponseFile.Parse(arg.Substring(1)); string[] unparsedArgs = this.Parse(parsedArgs); unprocessed.AddRange(unparsedArgs); } else { unprocessed.Add(arg); } } return(unprocessed.ToArray()); }
/// <summary> /// Creates a work item to create a cabinet. /// </summary> /// <param name="output">Output for the current database.</param> /// <param name="cabinetDir">Directory to create cabinet in.</param> /// <param name="mediaSymbol">Media symbol containing information about the cabinet.</param> /// <param name="fileFacades">Collection of files in this cabinet.</param> /// <returns>created CabinetWorkItem object</returns> private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData output, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable <FileFacade> fileFacades) { CabinetWorkItem cabinetWorkItem = null; var tempCabinetFileX = Path.Combine(this.IntermediateFolder, mediaSymbol.Cabinet); // check for an empty cabinet if (!fileFacades.Any()) { // Remove the leading '#' from the embedded cabinet name to make the warning easier to understand var cabinetName = mediaSymbol.Cabinet.TrimStart('#'); // If building a patch, remind them to run -p for torch. if (OutputType.Patch == output.Type) { this.Messaging.Write(WarningMessages.EmptyCabinet(mediaSymbol.SourceLineNumbers, cabinetName, true)); } else { this.Messaging.Write(WarningMessages.EmptyCabinet(mediaSymbol.SourceLineNumbers, cabinetName)); } } var cabinetResolver = new CabinetResolver(this.ServiceProvider, this.CabCachePath, this.BackendExtensions); var resolvedCabinet = cabinetResolver.ResolveCabinet(tempCabinetFileX, fileFacades); // create a cabinet work item if it's not being skipped if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) { // Default to the threshold for best smartcabbing (makes smallest cabinet). cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold: 0, compressionLevel, this.ModularizationSuffix /*, this.FileManager*/); } else // reuse the cabinet from the cabinet cache. { this.Messaging.Write(VerboseMessages.ReusingCabCache(mediaSymbol.SourceLineNumbers, mediaSymbol.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) { this.Messaging.Write(WarningMessages.CannotUpdateCabCache(mediaSymbol.SourceLineNumbers, resolvedCabinet.Path, e.Message)); } } var trackResolvedCabinet = this.BackendHelper.TrackFile(resolvedCabinet.Path, TrackedFileType.Intermediate, mediaSymbol.SourceLineNumbers); this.trackedFiles.Add(trackResolvedCabinet); if (mediaSymbol.Cabinet.StartsWith("#", StringComparison.Ordinal)) { var streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]); var streamRow = streamsTable.CreateRow(mediaSymbol.SourceLineNumbers); streamRow[0] = mediaSymbol.Cabinet.Substring(1); streamRow[1] = resolvedCabinet.Path; } else { var trackDestination = this.BackendHelper.TrackFile(Path.Combine(cabinetDir, mediaSymbol.Cabinet), TrackedFileType.Final, mediaSymbol.SourceLineNumbers); this.trackedFiles.Add(trackDestination); var transfer = this.BackendHelper.CreateFileTransfer(resolvedCabinet.Path, trackDestination.Path, resolvedCabinet.BuildOption == CabinetBuildOption.BuildAndMove, mediaSymbol.SourceLineNumbers); this.fileTransfers.Add(transfer); } return(cabinetWorkItem); }
/// <summary> /// Creates a work item to create a cabinet. /// </summary> /// <param name="output">Output for the current database.</param> /// <param name="cabinetDir">Directory to create cabinet in.</param> /// <param name="mediaRow">MediaRow containing information about the cabinet.</param> /// <param name="fileFacades">Collection of files in this cabinet.</param> /// <param name="fileTransfers">Array of files to be transfered.</param> /// <returns>created CabinetWorkItem object</returns> private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaTuple mediaRow, CompressionLevel compressionLevel, IEnumerable <FileFacade> fileFacades, List <FileTransfer> 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) { this.Messaging.Write(WarningMessages.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true)); } else { this.Messaging.Write(WarningMessages.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName)); } } var cabinetResolver = new CabinetResolver(this.CabCachePath, this.BackendExtensions); ResolvedCabinet resolvedCabinet = cabinetResolver.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. { this.Messaging.Write(VerboseMessages.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) { this.Messaging.Write(WarningMessages.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); if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out var transfer)) { transfer.Built = true; fileTransfers.Add(transfer); } } return(cabinetWorkItem); }
public void Execute() { var section = this.Intermediate.Sections.Single(); var fileTransfers = new List <FileTransfer>(); var containsMergeModules = false; var suppressedTableNames = new HashSet <string>(); // If there are any fields to resolve later, create the cache to populate during bind. var variableCache = this.DelayedFields.Any() ? new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase) : null; // Process the summary information table before the other tables. bool compressed; bool longNames; int installerVersion; string modularizationGuid; { var command = new BindSummaryInfoCommand(section); command.Execute(); compressed = command.Compressed; longNames = command.LongNames; installerVersion = command.InstallerVersion; modularizationGuid = command.ModularizationGuid; } // Add binder variables for all properties. if (SectionType.Product == section.Type || variableCache != null) { foreach (var propertyRow in section.Tuples.OfType <PropertyTuple>()) { // Set the ProductCode if it is to be generated. if ("ProductCode".Equals(propertyRow.Property, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal)) { propertyRow.Value = Common.GenerateGuid(); #if TODO_FIX_INSTANCE_TRANSFORM // Is this still necessary? // Update the target ProductCode in any instance transforms. foreach (SubStorage subStorage in this.Output.SubStorages) { Output subStorageOutput = subStorage.Data; if (OutputType.Transform != subStorageOutput.Type) { continue; } Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; foreach (Row row in instanceSummaryInformationTable.Rows) { if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) { row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); break; } } } #endif } // Add the property name and value to the variableCache. if (variableCache != null) { var key = String.Concat("property.", propertyRow.Property); variableCache[key] = propertyRow.Value; } } } // Sequence all the actions. { var command = new SequenceActionsCommand(section); command.Messaging = this.Messaging; command.Execute(); } { var command = new CreateSpecialPropertiesCommand(section); command.Execute(); } #if TODO_FINISH_PATCH ////if (OutputType.Patch == this.Output.Type) ////{ //// foreach (SubStorage substorage in this.Output.SubStorages) //// { //// Output transform = substorage.Data; //// ResolveFieldsCommand command = new ResolveFieldsCommand(); //// command.Tables = transform.Tables; //// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; //// command.FileManagerCore = this.FileManagerCore; //// command.FileManagers = this.FileManagers; //// command.SupportDelayedResolution = false; //// command.TempFilesLocation = this.TempFilesLocation; //// command.WixVariableResolver = this.WixVariableResolver; //// command.Execute(); //// this.MergeUnrealTables(transform.Tables); //// } ////} #endif if (this.Messaging.EncounteredError) { return; } this.Messaging.Write(VerboseMessages.UpdatingFileInformation()); // This must occur after all variables and source paths have been resolved. List <FileFacade> fileFacades; { var command = new GetFileFacadesCommand(section); command.Execute(); fileFacades = command.FileFacades; } // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). { var command = new ExtractEmbeddedFilesCommand(this.ExpectedEmbeddedFiles); command.Execute(); } // Gather information about files that do not come from merge modules. { var command = new UpdateFileFacadesCommand(this.Messaging, section); command.FileFacades = fileFacades; command.UpdateFileFacades = fileFacades.Where(f => !f.FromModule); command.OverwriteHash = true; command.TableDefinitions = this.TableDefinitions; command.VariableCache = variableCache; command.Execute(); } // Now that the variable cache is populated, resolve any delayed fields. if (this.DelayedFields.Any()) { var command = new ResolveDelayedFieldsCommand(this.Messaging, this.DelayedFields, variableCache); command.Execute(); } // Set generated component guids. { var command = new CalculateComponentGuids(this.Messaging, section); command.Execute(); } // Retrieve file information from merge modules. if (SectionType.Product == section.Type) { var wixMergeTuples = section.Tuples.OfType <WixMergeTuple>().ToList(); if (wixMergeTuples.Any()) { containsMergeModules = true; var command = new ExtractMergeModuleFilesCommand(this.Messaging, section, wixMergeTuples); command.FileFacades = fileFacades; command.OutputInstallerVersion = installerVersion; command.SuppressLayout = this.SuppressLayout; command.IntermediateFolder = this.IntermediateFolder; command.Execute(); fileFacades.AddRange(command.MergeModulesFileFacades); } } #if TODO_FINISH_PATCH else if (OutputType.Patch == this.Output.Type) { // Merge transform data into the output object. IEnumerable <FileFacade> filesFromTransform = this.CopyFromTransformData(this.Output); fileFacades.AddRange(filesFromTransform); } #endif // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return; } // Assign files to media. Dictionary <int, MediaTuple> assignedMediaRows; Dictionary <MediaTuple, IEnumerable <FileFacade> > filesByCabinetMedia; IEnumerable <FileFacade> uncompressedFiles; { var command = new AssignMediaCommand(section, this.Messaging); command.FileFacades = fileFacades; command.FilesCompressed = compressed; command.Execute(); assignedMediaRows = command.MediaRows; filesByCabinetMedia = command.FileFacadesByCabinetMedia; uncompressedFiles = command.UncompressedFileFacades; } // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return; } // Time to create the output object. Try to put as much above here as possible, updating the IR is better. Output output; { var command = new CreateOutputFromIRCommand(section, this.TableDefinitions, this.BackendExtensions); command.Execute(); output = command.Output; } // Update file sequence. { var command = new UpdateMediaSequencesCommand(output, fileFacades, assignedMediaRows); command.Execute(); } // Modularize identifiers. if (OutputType.Module == output.Type) { var command = new ModularizeCommand(output, modularizationGuid, section.Tuples.OfType <WixSuppressModularizationTuple>()); command.Execute(); } else // we can create instance transforms since Component Guids are set. { #if TODO_FIX_INSTANCE_TRANSFORM this.CreateInstanceTransforms(this.Output); #endif } #if TODO_FINISH_UPDATE // Extended binder extensions can be called now that fields are resolved. { Table updatedFiles = this.Output.EnsureTable(this.TableDefinitions["WixBindUpdatedFiles"]); foreach (IBinderExtension extension in this.Extensions) { extension.AfterResolvedFields(this.Output); } List <FileFacade> updatedFileFacades = new List <FileFacade>(); foreach (Row updatedFile in updatedFiles.Rows) { string updatedId = updatedFile.FieldAsString(0); FileFacade updatedFacade = fileFacades.First(f => f.File.File.Equals(updatedId)); updatedFileFacades.Add(updatedFacade); } if (updatedFileFacades.Any()) { UpdateFileFacadesCommand command = new UpdateFileFacadesCommand(); command.FileFacades = fileFacades; command.UpdateFileFacades = updatedFileFacades; command.ModularizationGuid = modularizationGuid; command.Output = this.Output; command.OverwriteHash = true; command.TableDefinitions = this.TableDefinitions; command.VariableCache = variableCache; command.Execute(); } } #endif // Stop processing if an error previously occurred. if (this.Messaging.EncounteredError) { return; } // Ensure the intermediate folder is created since delta patches will be // created there. Directory.CreateDirectory(this.IntermediateFolder); if (SectionType.Patch == section.Type && this.DeltaBinaryPatch) { var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Tuples.OfType <WixPatchIdTuple>().FirstOrDefault()); command.Execute(); } // create cabinet files and process uncompressed files var layoutDirectory = Path.GetDirectoryName(this.OutputPath); if (!this.SuppressLayout || OutputType.Module == output.Type) { this.Messaging.Write(VerboseMessages.CreatingCabinetFiles()); var command = new CreateCabinetsCommand(); command.CabbingThreadCount = this.CabbingThreadCount; command.CabCachePath = this.CabCachePath; command.DefaultCompressionLevel = this.DefaultCompressionLevel; command.Output = output; command.Messaging = this.Messaging; command.BackendExtensions = this.BackendExtensions; command.LayoutDirectory = layoutDirectory; command.Compressed = compressed; command.FileRowsByCabinet = filesByCabinetMedia; command.ResolveMedia = this.ResolveMedia; command.TableDefinitions = this.TableDefinitions; command.TempFilesLocation = this.IntermediateFolder; command.WixMediaTuples = section.Tuples.OfType <WixMediaTuple>(); command.Execute(); fileTransfers.AddRange(command.FileTransfers); } #if TODO_FINISH_PATCH if (OutputType.Patch == this.Output.Type) { // copy output data back into the transforms this.CopyToTransformData(this.Output); } #endif this.ValidateComponentGuids(output); // stop processing if an error previously occurred if (this.Messaging.EncounteredError) { return; } // Generate database file. this.Messaging.Write(VerboseMessages.GeneratingDatabase()); string tempDatabaseFile = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); this.GenerateDatabase(output, tempDatabaseFile, false, false); if (FileTransfer.TryCreate(tempDatabaseFile, this.OutputPath, true, output.Type.ToString(), null, out var transfer)) // note where this database needs to move in the future { transfer.Built = true; fileTransfers.Add(transfer); } // Stop processing if an error previously occurred. if (this.Messaging.EncounteredError) { return; } // Merge modules. if (containsMergeModules) { this.Messaging.Write(VerboseMessages.MergingModules()); // Add back possibly suppressed sequence tables since all sequence tables must be present // for the merge process to work. We'll drop the suppressed sequence tables again as // necessary. foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) { var sequenceTableName = sequence.ToString(); var sequenceTable = output.Tables[sequenceTableName]; if (null == sequenceTable) { sequenceTable = output.EnsureTable(this.TableDefinitions[sequenceTableName]); } if (0 == sequenceTable.Rows.Count) { suppressedTableNames.Add(sequenceTableName); } } var command = new MergeModulesCommand(); command.FileFacades = fileFacades; command.Output = output; command.OutputPath = tempDatabaseFile; command.SuppressedTableNames = suppressedTableNames; command.Execute(); } if (this.Messaging.EncounteredError) { return; } #if TODO_FINISH_VALIDATION // Validate the output if there is an MSI validator. if (null != this.Validator) { Stopwatch stopwatch = Stopwatch.StartNew(); // set the output file for source line information this.Validator.Output = this.Output; Messaging.Instance.Write(WixVerboses.ValidatingDatabase()); this.Validator.Validate(tempDatabaseFile); stopwatch.Stop(); Messaging.Instance.Write(WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); // Stop processing if an error occurred. if (Messaging.Instance.EncounteredError) { return; } } #endif // Process uncompressed files. if (!this.Messaging.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any()) { var command = new ProcessUncompressedFilesCommand(section); command.Compressed = compressed; command.FileFacades = uncompressedFiles; command.LayoutDirectory = layoutDirectory; command.LongNamesInImage = longNames; command.ResolveMedia = this.ResolveMedia; command.DatabasePath = tempDatabaseFile; command.Execute(); fileTransfers.AddRange(command.FileTransfers); } this.FileTransfers = fileTransfers; this.ContentFilePaths = fileFacades.Select(r => r.WixFile.Source.Path).ToList(); this.Pdb = new Pdb { Output = output }; // TODO: Eventually this gets removed var intermediate = new Intermediate(this.Intermediate.Id, new[] { section }, this.Intermediate.Localizations.ToDictionary(l => l.Culture, StringComparer.OrdinalIgnoreCase), this.Intermediate.EmbedFilePaths); intermediate.Save(Path.ChangeExtension(this.OutputPath, "wir")); }
protected override void WriteVerbose(string message) { VerboseMessages.Add(message); }
public void Execute() { var destinationFiles = new List <string>(); foreach (var fileTransfer in this.FileTransfers) { // If the source and destination are identical, then there's nothing to do here if (0 == String.Compare(fileTransfer.Source, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) { fileTransfer.Redundant = true; continue; } var retry = false; do { try { if (fileTransfer.Move) { this.Messaging.Write(VerboseMessages.MoveFile(fileTransfer.Source, fileTransfer.Destination)); this.MoveFile(fileTransfer.Source, fileTransfer.Destination); } else { this.Messaging.Write(VerboseMessages.CopyFile(fileTransfer.Source, fileTransfer.Destination)); this.CopyFile(fileTransfer.Source, fileTransfer.Destination); } retry = false; destinationFiles.Add(fileTransfer.Destination); } catch (FileNotFoundException e) { throw new WixException(ErrorMessages.FileNotFound(fileTransfer.SourceLineNumbers, e.FileName)); } catch (DirectoryNotFoundException) { // if we already retried, give up if (retry) { throw; } var directory = Path.GetDirectoryName(fileTransfer.Destination); this.Messaging.Write(VerboseMessages.CreateDirectory(directory)); Directory.CreateDirectory(directory); retry = true; } catch (UnauthorizedAccessException) { // if we already retried, give up if (retry) { throw; } if (File.Exists(fileTransfer.Destination)) { this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination)); // try to ensure the file is not read-only var attributes = File.GetAttributes(fileTransfer.Destination); try { File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly); } catch (ArgumentException) // thrown for unauthorized access errors { throw new WixException(ErrorMessages.UnauthorizedAccess(fileTransfer.Destination)); } // try to delete the file try { File.Delete(fileTransfer.Destination); } catch (IOException) { throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination)); } retry = true; } else // no idea what just happened, bail { throw; } } catch (IOException) { // if we already retried, give up if (retry) { throw; } if (File.Exists(fileTransfer.Destination)) { this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination)); // ensure the file is not read-only, then delete it var attributes = File.GetAttributes(fileTransfer.Destination); File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly); try { File.Delete(fileTransfer.Destination); } catch (IOException) { throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination)); } retry = true; } else // no idea what just happened, bail { throw; } } } while (retry); } // Finally, if directed then reset remove ACLs that may may have been picked up // during the file transfer process. if (this.ResetAcls && 0 < destinationFiles.Count) { try { FileSystem.ResetAcls(destinationFiles); } catch (Exception e) { this.Messaging.Write(WarningMessages.UnableToResetAcls(e.Message)); } } }
public void Execute() { List <string> destinationFiles = new List <string>(); foreach (var fileTransfer in this.FileTransfers) { // If the source and destination are identical, then there's nothing to do here if (0 == String.Compare(fileTransfer.Source, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) { fileTransfer.Redundant = true; continue; } bool retry = false; do { try { if (fileTransfer.Move) { this.Messaging.Write(VerboseMessages.MoveFile(fileTransfer.Source, fileTransfer.Destination)); this.TransferFile(true, fileTransfer.Source, fileTransfer.Destination); } else { this.Messaging.Write(VerboseMessages.CopyFile(fileTransfer.Source, fileTransfer.Destination)); this.TransferFile(false, fileTransfer.Source, fileTransfer.Destination); } retry = false; destinationFiles.Add(fileTransfer.Destination); } catch (FileNotFoundException e) { throw new WixFileNotFoundException(fileTransfer.SourceLineNumbers, e.FileName); } catch (DirectoryNotFoundException) { // if we already retried, give up if (retry) { throw; } string directory = Path.GetDirectoryName(fileTransfer.Destination); this.Messaging.Write(VerboseMessages.CreateDirectory(directory)); Directory.CreateDirectory(directory); retry = true; } catch (UnauthorizedAccessException) { // if we already retried, give up if (retry) { throw; } if (File.Exists(fileTransfer.Destination)) { this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination)); // try to ensure the file is not read-only FileAttributes attributes = File.GetAttributes(fileTransfer.Destination); try { File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly); } catch (ArgumentException) // thrown for unauthorized access errors { throw new WixException(ErrorMessages.UnauthorizedAccess(fileTransfer.Destination)); } // try to delete the file try { File.Delete(fileTransfer.Destination); } catch (IOException) { throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination)); } retry = true; } else // no idea what just happened, bail { throw; } } catch (IOException) { // if we already retried, give up if (retry) { throw; } if (File.Exists(fileTransfer.Destination)) { this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination)); // ensure the file is not read-only, then delete it FileAttributes attributes = File.GetAttributes(fileTransfer.Destination); File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly); try { File.Delete(fileTransfer.Destination); } catch (IOException) { throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination)); } retry = true; } else // no idea what just happened, bail { throw; } } } while (retry); } // Finally, if there were any files remove the ACL that may have been added to // during the file transfer process. if (0 < destinationFiles.Count && !this.SuppressAclReset) { var aclReset = new FileSecurity(); aclReset.SetAccessRuleProtection(false, false); try { //WixToolset.Core.Native.NativeMethods.ResetAcls(destinationFiles.ToArray(), (uint)destinationFiles.Count); foreach (var file in destinationFiles) { new FileInfo(file).SetAccessControl(aclReset); } } catch { this.Messaging.Write(WarningMessages.UnableToResetAcls()); } } }
public void Execute() { 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.IntermediateFolder, "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 (FormatException) { this.Messaging.Write(ErrorMessages.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); continue; } this.Messaging.Write(VerboseMessages.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 this.Messaging.Write(VerboseMessages.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]) { this.Messaging.Write(VerboseMessages.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: this.Messaging.Write(ErrorMessages.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleKeys.ToString())); break; case MsmErrorType.msmErrorFeatureRequired: this.Messaging.Write(ErrorMessages.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id)); break; case MsmErrorType.msmErrorLanguageFailed: this.Messaging.Write(ErrorMessages.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorLanguageUnsupported: this.Messaging.Write(ErrorMessages.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorResequenceMerge: this.Messaging.Write(WarningMessages.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorTableMerge: if ("_Validation" != mergeError.DatabaseTable) // ignore merge errors in the _Validation table { this.Messaging.Write(WarningMessages.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); } break; case MsmErrorType.msmErrorPlatformMismatch: this.Messaging.Write(ErrorMessages.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile)); break; default: this.Messaging.Write(ErrorMessages.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorWithType, Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace)); break; } } if (0 >= mergeErrors.Count && !commit) { this.Messaging.Write(ErrorMessages.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 (this.Messaging.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) { this.Messaging.Write(WarningMessages.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; } this.Messaging.Write(WarningMessages.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 this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles()); using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) { foreach (var 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); throw new NotImplementedException(); // Update the file attributes to match the compression specified // on the Merge element or on the Package element. var attributes = 0; // Get the current value if its not null. if (!recordUpdate.IsNull(2)) { attributes = recordUpdate.GetInteger(2); } if (!file.File.Compressed.HasValue) { // Clear all compression bits. attributes &= ~MsiInterop.MsidbFileAttributesCompressed; attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; } else if (file.File.Compressed.Value) { attributes |= MsiInterop.MsidbFileAttributesCompressed; attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; } else if (!file.File.Compressed.Value) { attributes |= MsiInterop.MsidbFileAttributesNoncompressed; attributes &= ~MsiInterop.MsidbFileAttributesCompressed; } recordUpdate.SetInteger(2, attributes); view.Modify(ModifyView.Update, recordUpdate); } } } db.Commit(); } }
/// <summary> /// 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 /// </summary> /// <param name="firstCabName">The name of splitting cabinet without extention e.g. "cab1".</param> /// <param name="newCabName">The name of the new cabinet that would be formed by splitting e.g. "cab1b.cab"</param> /// <param name="fileToken">The file token of the first file present in the splitting cabinet</param> 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 this.Messaging.Write(VerboseMessages.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(ErrorMessages.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(ErrorMessages.SplitCabinetNameCollision(newCabinetName, firstCabinetName)); } } // Check if the last Split Cabinet was found in the Media Table if (!lastSplitCabinetFound) { throw new WixException(ErrorMessages.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(); } }
public void Verbose(LogType logType, string message, params object[] items) { VerboseMessages.Enqueue(message); _logger.Verbose(message, items); }
public void Verbose(string message, params object[] items) { VerboseMessages.Add(message); _logger.Verbose(message, items); }