private void ResolveBundleInstallScope(WixBundleRow bundleInfo, IEnumerable <PackageFacade> facades) { foreach (PackageFacade facade in facades) { if (bundleInfo.PerMachine && YesNoDefaultType.No == facade.Package.PerMachine) { Messaging.Instance.OnMessage(WixVerboses.SwitchingToPerUserPackage(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId)); bundleInfo.PerMachine = false; break; } } foreach (PackageFacade facade in facades) { // Update package scope from bundle scope if default. if (YesNoDefaultType.Default == facade.Package.PerMachine) { facade.Package.PerMachine = bundleInfo.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 (!bundleInfo.PerMachine && YesNoDefaultType.Yes == facade.Package.PerMachine && !facade.Package.Permanent && 0 < facade.Provides.Count) { Messaging.Instance.OnMessage(WixWarnings.NoPerMachineDependencies(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId)); } } }
/// <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(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } } else // default to 1 if the environment variable is not set { this.CabbingThreadCount = 1; } Messaging.Instance.OnMessage(WixVerboses.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } catch (ArgumentException) { throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } catch (FormatException) { throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); } } }
/// <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, Guid bundleId) { if (this.invalidBundle) { return(false); } this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_MAGIC, BURN_SECTION_MAGIC); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_VERSION, BURN_SECTION_VERSION); this.messageHandler.OnMessage(WixVerboses.BundleGuid(bundleId.ToString("B"))); this.binaryWriter.BaseStream.Seek(this.wixburnDataOffset + BURN_SECTION_OFFSET_BUNDLEGUID, SeekOrigin.Begin); this.binaryWriter.Write(bundleId.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> /// 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(WixErrors.UnexpectedExternalUIMessage(message)); } else { throw new WixException(WixErrors.UnexpectedExternalUIMessage(message, action)); } } SourceLineNumberCollection 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.OnMessage(WixErrors.ValidationError(messageSourceLineNumbers, messageParts[0], messageParts[2])); break; case "2": this.OnMessage(WixWarnings.ValidationWarning(messageSourceLineNumbers, messageParts[0], messageParts[2])); break; case "3": this.OnMessage(WixVerboses.ValidationInfo(messageParts[0], messageParts[2])); break; default: throw new WixException(WixErrors.InvalidValidatorMessageType(messageParts[1])); } }
/// <summary> /// Final step in binding that transfers (moves/copies) all files generated into the appropriate /// location in the source image /// </summary> /// <param name="fileTransfers">List of files to transfer.</param> private void LayoutMedia(IEnumerable <FileTransfer> transfers) { if (null != transfers && transfers.Any()) { this.core.OnMessage(WixVerboses.LayingOutMedia()); TransferFilesCommand command = new TransferFilesCommand(); command.FileManagers = this.fileManagers; command.FileTransfers = transfers; command.SuppressAclReset = this.SuppressAclReset; command.Execute(); } }
/// <summary> /// Does any housekeeping after Bind. /// </summary> /// <param name="tidy">Whether or not any actual tidying should be done.</param> public void Cleanup(bool tidy) { if (tidy) { if (!this.DeleteTempFiles()) { this.core.OnMessage(WixWarnings.FailedToDeleteTempDir(this.TempFilesLocation)); } } else { this.core.OnMessage(WixVerboses.BinderTempDirLocatedAt(this.TempFilesLocation)); } }
/// <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) { Messaging.Instance.OnMessage(WixVerboses.CreateCabinet(cabinetWorkItem.CabinetFile)); int maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting ulong maxPreCompressedSizeInBytes = 0; if (MaximumCabinetSizeForLargeFileSplitting != 0) { // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file if (cabinetWorkItem.FileRows.Count == 1) { // 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 (FileRow fileRow in cabinetWorkItem.FileRows) // No other easy way than looping to get the only row { if ((ulong)fileRow.FileSize >= maxPreCompressedSizeInBytes) { // If file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting maxCabinetSize = MaximumCabinetSizeForLargeFileSplitting; } } } } // create the cabinet file string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, cabinetWorkItem.FileRows.Count, maxCabinetSize, cabinetWorkItem.MaxThreshold, cabinetWorkItem.CompressionLevel)) { foreach (FileRow fileRow in cabinetWorkItem.FileRows) { bool retainRangeWarning = false; // TODO: bring this line back when we find a better way to get the binder file manager here. // cabinetWorkItem.BinderFileManager.ResolvePatch(fileRow, out retainRangeWarning); if (retainRangeWarning) { // TODO: get patch family to add to warning message for PatchWiz parity. Messaging.Instance.OnMessage(WixWarnings.RetainRangeMismatch(fileRow.SourceLineNumbers, fileRow.File)); } cab.AddFile(fileRow); } cab.Complete(newCabNamesCallBackAddress); } }
/// <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) { Messaging.Instance.OnMessage(WixVerboses.CreateCabinet(cabinetWorkItem.CabinetFile)); int maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting ulong maxPreCompressedSizeInBytes = 0; if (MaximumCabinetSizeForLargeFileSplitting != 0) { // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file if (1 == cabinetWorkItem.FileFacades.Count()) { // Cabinet has Single File, Check if this is Large File than needs Splitting into Multiple cabs // Get the Value for Max Uncompressed Media Size maxPreCompressedSizeInBytes = (ulong)MaximumUncompressedMediaSize * 1024 * 1024; foreach (FileFacade facade in cabinetWorkItem.FileFacades) // No other easy way than looping to get the only row { if ((ulong)facade.File.FileSize >= maxPreCompressedSizeInBytes) { // If file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting maxCabinetSize = MaximumCabinetSizeForLargeFileSplitting; } } } } // create the cabinet file string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, cabinetWorkItem.FileFacades.Count(), maxCabinetSize, cabinetWorkItem.MaxThreshold, cabinetWorkItem.CompressionLevel)) { foreach (FileFacade facade in cabinetWorkItem.FileFacades) { cab.AddFile(facade); } cab.Complete(newCabNamesCallBackAddress); } }
/// <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.OnMessage(WixVerboses.CreateCabinet(cabinetWorkItem.CabinetFile)); // create the cabinet file string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); try { using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, 0, 0, cabinetWorkItem.CompressionLevel)) { foreach (FileRow fileRow in cabinetWorkItem.FileRows) { cab.AddFile(fileRow.Source, fileRow.File); } } } catch (FileNotFoundException e) { throw new WixException(WixErrors.FileNotFound(null, e.FileName)); } }
public void Execute() { int payloadCount = this.Payloads.Count(); // The number of embedded payloads if (!String.IsNullOrEmpty(this.ManifestFile)) { ++payloadCount; } using (var cab = new WixCreateCab(Path.GetFileName(this.OutputPath), Path.GetDirectoryName(this.OutputPath), payloadCount, 0, 0, this.DefaultCompressionLevel)) { // If a manifest was provided always add it as "payload 0" to the container. if (!String.IsNullOrEmpty(this.ManifestFile)) { cab.AddFile(this.ManifestFile, "0"); } foreach (WixBundlePayloadRow payload in this.Payloads) { Debug.Assert(PackagingType.Embedded == payload.Packaging); Messaging.Instance.OnMessage(WixVerboses.LoadingPayload(payload.FullFileName)); cab.AddFile(payload.FullFileName, payload.EmbeddedId); } cab.Complete(); } // Now that the container is created, set the outputs of the command. FileInfo fileInfo = new FileInfo(this.OutputPath); this.Hash = Common.GetFileHash(fileInfo.FullName); this.Size = fileInfo.Length; }
/// <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.OnMessage(WixVerboses.CreateCabinet(cabinetWorkItem.CabinetFile)); // create the cabinet file string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, cabinetWorkItem.FileRows.Count, 0, cabinetWorkItem.MaxThreshold, cabinetWorkItem.CompressionLevel)) { foreach (FileRow fileRow in cabinetWorkItem.FileRows) { bool retainRangeWarning; cabinetWorkItem.BinderFileManager.ResolvePatch(fileRow, out retainRangeWarning); if (retainRangeWarning) { // TODO: get patch family to add to warning message for PatchWiz parity. this.OnMessage(WixWarnings.RetainRangeMismatch(fileRow.SourceLineNumbers, fileRow.File)); } cab.AddFile(fileRow); } cab.Complete(); } }
/// <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, MediaRow 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) { Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true)); } else { Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName)); } } ResolvedCabinet resolvedCabinet = this.ResolveCabinet(tempCabinetFileX, fileFacades); // create a cabinet work item if it's not being skipped if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) { int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet). cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold, compressionLevel /*, this.FileManager*/); } else // reuse the cabinet from the cabinet cache. { Messaging.Instance.OnMessage(WixVerboses.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, resolvedCabinet.Path)); try { // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output) // causing the project to look like it perpetually needs a rebuild until all of the reused // cabinets get newer timestamps. File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now); } catch (Exception e) { Messaging.Instance.OnMessage(WixWarnings.CannotUpdateCabCache(mediaRow.SourceLineNumbers, resolvedCabinet.Path, e.Message)); } } if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) { Table streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]); Row streamRow = streamsTable.CreateRow(mediaRow.SourceLineNumbers); streamRow[0] = mediaRow.Cabinet.Substring(1); streamRow[1] = resolvedCabinet.Path; } else { string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet); FileTransfer transfer; if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out transfer)) { transfer.Built = true; fileTransfers.Add(transfer); } } return(cabinetWorkItem); }
/// <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 Messaging.Instance.OnMessage(WixVerboses.CabinetsSplitInParallel()); mutex.WaitOne(); // Wait on other thread } string firstCabinetName = firstCabName + ".cab"; string newCabinetName = newCabName; bool transferAdded = false; // Used for Error Handling // Create File Transfer for new Cabinet using transfer of Base Cabinet foreach (FileTransfer transfer in this.FileTransfers) { if (firstCabinetName.Equals(Path.GetFileName(transfer.Source), StringComparison.InvariantCultureIgnoreCase)) { string newCabSourcePath = Path.Combine(Path.GetDirectoryName(transfer.Source), newCabinetName); string newCabTargetPath = Path.Combine(Path.GetDirectoryName(transfer.Destination), newCabinetName); FileTransfer newTransfer; if (FileTransfer.TryCreate(newCabSourcePath, newCabTargetPath, transfer.Move, "Cabinet", transfer.SourceLineNumbers, out newTransfer)) { newTransfer.Built = true; this.fileTransfers.Add(newTransfer); transferAdded = true; break; } } } // Check if File Transfer was added if (!transferAdded) { throw new WixException(WixErrors.SplitCabinetCopyRegistrationFailed(newCabinetName, firstCabinetName)); } // Add the new Cabinets to media table using LastSequence of Base Cabinet Table mediaTable = this.Output.Tables["Media"]; Table wixFileTable = this.Output.Tables["WixFile"]; int diskIDForLastSplitCabAdded = 0; // The DiskID value for the first cab in this cabinet split chain int lastSequenceForLastSplitCabAdded = 0; // The LastSequence value for the first cab in this cabinet split chain bool lastSplitCabinetFound = false; // Used for Error Handling string lastCabinetOfThisSequence = String.Empty; // Get the Value of Last Cabinet Added in this split Sequence from Dictionary if (!this.lastCabinetAddedToMediaTable.TryGetValue(firstCabinetName, out lastCabinetOfThisSequence)) { // If there is no value for this sequence, then use first Cabinet is the last one of this split sequence lastCabinetOfThisSequence = firstCabinetName; } foreach (MediaRow mediaRow in mediaTable.Rows) { // Get details for the Last Cabinet Added in this Split Sequence if ((lastSequenceForLastSplitCabAdded == 0) && lastCabinetOfThisSequence.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) { lastSequenceForLastSplitCabAdded = mediaRow.LastSequence; diskIDForLastSplitCabAdded = mediaRow.DiskId; lastSplitCabinetFound = true; } // Check for Name Collision for the new Cabinet added if (newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) { // Name Collision of generated Split Cabinet Name and user Specified Cab name for current row throw new WixException(WixErrors.SplitCabinetNameCollision(newCabinetName, firstCabinetName)); } } // Check if the last Split Cabinet was found in the Media Table if (!lastSplitCabinetFound) { throw new WixException(WixErrors.SplitCabinetInsertionFailed(newCabinetName, firstCabinetName, lastCabinetOfThisSequence)); } // The new Row has to be inserted just after the last cab in this cabinet split chain according to DiskID Sort // This is because the FDI Extract requires DiskID of Split Cabinets to be continuous. It Fails otherwise with // Error 2350 (FDI Server Error) as next DiskID did not have the right split cabinet during extraction MediaRow newMediaRow = (MediaRow)mediaTable.CreateRow(null); newMediaRow.Cabinet = newCabinetName; newMediaRow.DiskId = diskIDForLastSplitCabAdded + 1; // When Sorted with DiskID, this new Cabinet Row is an Insertion newMediaRow.LastSequence = lastSequenceForLastSplitCabAdded; // Now increment the DiskID for all rows that come after the newly inserted row to Ensure that DiskId is unique foreach (MediaRow mediaRow in mediaTable.Rows) { // Check if this row comes after inserted row and it is not the new cabinet inserted row if (mediaRow.DiskId >= newMediaRow.DiskId && !newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) { mediaRow.DiskId++; // Increment DiskID } } // Now Increment DiskID for All files Rows so that they refer to the right Media Row foreach (WixFileRow wixFileRow in wixFileTable.Rows) { // Check if this row comes after inserted row and if this row is not the file that has to go into the current cabinet // This check will work as we have only one large file in every splitting cabinet // If we want to support splitting cabinet with more large files we need to update this code if (wixFileRow.DiskId >= newMediaRow.DiskId && !wixFileRow.File.Equals(fileToken, StringComparison.InvariantCultureIgnoreCase)) { wixFileRow.DiskId++; // Increment DiskID } } // Update the Last Cabinet Added in the Split Sequence in Dictionary for future callback this.lastCabinetAddedToMediaTable[firstCabinetName] = newCabinetName; mediaTable.ValidateRows(); // Valdiates DiskDIs, throws Exception as Wix Error if validation fails } finally { // Releasing the Mutex here mutex.ReleaseMutex(); } }
public void Execute() { List <string> destinationFiles = new List <string>(); foreach (FileTransfer fileTransfer in this.FileTransfers) { string fileSource = this.ResolveFile(fileTransfer.Source, fileTransfer.Type, fileTransfer.SourceLineNumbers, BindStage.Normal); // If the source and destination are identical, then there's nothing to do here if (0 == String.Compare(fileSource, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) { fileTransfer.Redundant = true; continue; } bool retry = false; do { try { if (fileTransfer.Move) { Messaging.Instance.OnMessage(WixVerboses.MoveFile(fileSource, fileTransfer.Destination)); this.TransferFile(true, fileSource, fileTransfer.Destination); } else { Messaging.Instance.OnMessage(WixVerboses.CopyFile(fileSource, fileTransfer.Destination)); this.TransferFile(false, fileSource, fileTransfer.Destination); } retry = false; destinationFiles.Add(fileTransfer.Destination); } catch (FileNotFoundException e) { throw new WixFileNotFoundException(e.FileName); } catch (DirectoryNotFoundException) { // if we already retried, give up if (retry) { throw; } string directory = Path.GetDirectoryName(fileTransfer.Destination); Messaging.Instance.OnMessage(WixVerboses.CreateDirectory(directory)); Directory.CreateDirectory(directory); retry = true; } catch (UnauthorizedAccessException) { // if we already retried, give up if (retry) { throw; } if (File.Exists(fileTransfer.Destination)) { Messaging.Instance.OnMessage(WixVerboses.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(WixErrors.UnauthorizedAccess(fileTransfer.Destination)); } // try to delete the file try { File.Delete(fileTransfer.Destination); } catch (IOException) { throw new WixException(WixErrors.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)) { Messaging.Instance.OnMessage(WixVerboses.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(WixErrors.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 { Messaging.Instance.OnMessage(WixWarnings.UnableToResetAcls()); } } }
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")); }
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); }
/// <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) { Dictionary <string, string> indexedICEs = new Dictionary <string, string>(); Dictionary <string, string> indexedSuppressedICEs = new Dictionary <string, string>(); 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(); // if we don't have the temporary files object yet, get one if (null == this.tempFiles) { this.tempFiles = new TempFileCollection(); } Directory.CreateDirectory(this.TempFilesLocation); // ensure the base path is there // index the ICEs if (null != this.ices) { foreach (string ice in this.ices) { indexedICEs[ice] = null; } } // index the suppressed ICEs if (null != this.suppressedICEs) { foreach (string suppressedICE in this.suppressedICEs) { indexedSuppressedICEs[suppressedICE] = null; } } // copy the database to a temporary location so it can be manipulated string tempDatabaseFile = Path.Combine(this.TempFilesLocation, 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.OnMessage(WixVerboses.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(WixErrors.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 (!indexedSuppressedICEs.ContainsKey(action)) { actions.Add(action); } } } } if (0 != indexedICEs.Count) { // Walk backwards and remove those that arent in the list for (int i = actions.Count - 1; 0 <= i; i--) { if (!indexedICEs.ContainsKey(actions[i])) { actions.RemoveAt(i); } } } // 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 (!Messaging.Instance.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 (!Messaging.Instance.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.OnMessage(WixErrors.ValidationFailedToOpenDatabase()); } else if (0x64D == e.NativeErrorCode) { this.OnMessage(WixErrors.ValidationFailedDueToLowMsiEngine()); } else if (0x654 == e.NativeErrorCode) { this.OnMessage(WixErrors.ValidationFailedDueToInvalidPackage()); } else if (0x658 == e.NativeErrorCode) { this.OnMessage(WixErrors.ValidationFailedDueToMultilanguageMergeModule()); } else if (0x659 == e.NativeErrorCode) { this.OnMessage(WixWarnings.ValidationFailedDueToSystemPolicy()); } else { string msgTemp = e.Message; if (null != this.actionName) { msgTemp = String.Concat("Action - '", this.actionName, "' ", e.Message); } this.OnMessage(WixErrors.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(); } }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { try { // parse the command line this.ParseCommandLine(args); // exit if there was an error parsing the command line (otherwise the logo appears after error messages) if (this.messageHandler.EncounteredError) { return(this.messageHandler.LastErrorNumber); } if (0 == this.inputFiles.Count) { this.showHelp = true; } if (this.showLogo) { AppCommon.DisplayToolHeader(); } if (this.showHelp) { Console.WriteLine(SmokeStrings.HelpMessage); AppCommon.DisplayToolFooter(); return(this.messageHandler.LastErrorNumber); } foreach (string parameter in this.invalidArgs) { this.messageHandler.Display(this, WixWarnings.UnsupportedCommandLineArgument(parameter)); } this.invalidArgs = null; validator.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); // load any extensions bool validatorExtensionLoaded = false; foreach (string extension in this.extensionList) { WixExtension wixExtension = WixExtension.Load(extension); ValidatorExtension validatorExtension = wixExtension.ValidatorExtension; if (null != validatorExtension) { if (validatorExtensionLoaded) { throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, SmokeStrings.EXP_CannotLoadLinkerExtension, validatorExtension.GetType().ToString(), validator.Extension.ToString()), "ext"); } validator.Extension = validatorExtension; validatorExtensionLoaded = true; } } // set the message handlers validator.Extension.Message += new MessageEventHandler(this.messageHandler.Display); // disable ICE33 and ICE66 by default this.suppressICEs.Add("ICE33"); this.suppressICEs.Add("ICE66"); // set the ICEs string[] iceArray = new string[this.ices.Count]; this.ices.CopyTo(iceArray, 0); validator.ICEs = iceArray; // set the suppressed ICEs string[] suppressICEArray = new string[this.suppressICEs.Count]; this.suppressICEs.CopyTo(suppressICEArray, 0); validator.SuppressedICEs = suppressICEArray; // Load the pdb and assign the Output to the validator if (null != pdbPath) { string pdbFullPath = Path.GetFullPath(pdbPath); Pdb pdb = Pdb.Load(pdbFullPath, false, false); this.validator.Output = pdb.Output; } foreach (string inputFile in this.inputFiles) { // set the default cube file Assembly assembly = Assembly.GetExecutingAssembly(); string appDirectory = Path.GetDirectoryName(assembly.Location); if (this.addDefault) { switch (Path.GetExtension(inputFile).ToLower(CultureInfo.InvariantCulture)) { case msm: validator.AddCubeFile(Path.Combine(appDirectory, "mergemod.cub")); break; case msi: validator.AddCubeFile(Path.Combine(appDirectory, "darice.cub")); break; default: throw new WixException(WixErrors.UnexpectedFileExtension(inputFile, ".msi, .msm")); } } // print friendly message saying what file is being validated Console.WriteLine(Path.GetFileName(inputFile)); Stopwatch stopwatch = Stopwatch.StartNew(); try { validator.Validate(Path.GetFullPath(inputFile)); } catch (UnauthorizedAccessException) { this.messageHandler.Display(this, WixErrors.UnauthorizedAccess(Path.GetFullPath(inputFile))); } finally { stopwatch.Stop(); this.messageHandler.Display(this, WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); if (this.tidy) { if (!validator.DeleteTempFiles()) { Console.WriteLine(SmokeStrings.WAR_FailedToDeleteTempDir, validator.TempFilesLocation); } } else { Console.WriteLine(SmokeStrings.INF_TempDirLocatedAt, validator.TempFilesLocation); } } } } catch (WixException we) { this.messageHandler.Display(this, we.Error); } catch (Exception e) { this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } return(this.messageHandler.LastErrorNumber); }
/// <summary> /// Final step in binding that transfers (moves/copies) all files generated into the appropriate /// location in the source image /// </summary> /// <param name="fileTransfers">Array of files to transfer.</param> /// <param name="fileTransfers">Array of directories to transfer.</param> /// <param name="suppressAclReset">Suppress removing ACLs added during file transfer process.</param> protected void LayoutMedia(ArrayList fileTransfers, bool suppressAclReset) { if (this.core.EncounteredError) { return; } ArrayList destinationFiles = new ArrayList(); for (int i = 0; i < fileTransfers.Count; ++i) { FileTransfer fileTransfer = (FileTransfer)fileTransfers[i]; string fileSource = fileManager.ResolveFile(fileTransfer.Source, fileTransfer.Type, fileTransfer.SourceLineNumbers, BindStage.Normal); // If the source and destination are identical, then there's nothing to do here if (0 == String.Compare(fileSource, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) { fileTransfer.Redundant = true; continue; } bool retry = false; do { try { if (fileTransfer.Move) { this.core.OnMessage(WixVerboses.MoveFile(fileSource, fileTransfer.Destination)); this.FileManager.MoveFile(fileSource, fileTransfer.Destination); } else { this.core.OnMessage(WixVerboses.CopyFile(fileSource, fileTransfer.Destination)); this.FileManager.CopyFile(fileSource, fileTransfer.Destination, true); } retry = false; destinationFiles.Add(fileTransfer.Destination); } catch (FileNotFoundException e) { throw new WixFileNotFoundException(e.FileName); } catch (DirectoryNotFoundException) { // if we already retried, give up if (retry) { throw; } string directory = Path.GetDirectoryName(fileTransfer.Destination); this.core.OnMessage(WixVerboses.CreateDirectory(directory)); Directory.CreateDirectory(directory); retry = true; } catch (UnauthorizedAccessException) { // if we already retried, give up if (retry) { throw; } if (File.Exists(fileTransfer.Destination)) { this.core.OnMessage(WixVerboses.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(WixErrors.UnauthorizedAccess(fileTransfer.Destination)); } // try to delete the file try { File.Delete(fileTransfer.Destination); } catch (IOException) { throw new WixException(WixErrors.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.core.OnMessage(WixVerboses.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(WixErrors.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 && !suppressAclReset) { try { WixToolset.Cab.Interop.NativeMethods.ResetAcls((string[])destinationFiles.ToArray(typeof(string)), (uint)destinationFiles.Count); } catch { this.core.OnMessage(WixWarnings.UnableToResetAcls()); } } }
public void Execute() { Debug.Assert(OutputType.Product == this.Output.Type); Table wixMergeTable = this.Output.Tables["WixMerge"]; Table wixFeatureModulesTable = this.Output.Tables["WixFeatureModules"]; // check for merge rows to see if there is any work to do if (null == wixMergeTable || 0 == wixMergeTable.Rows.Count) { return; } IMsmMerge2 merge = null; bool commit = true; bool logOpen = false; bool databaseOpen = false; string logPath = null; try { merge = MsmInterop.GetMsmMerge(); logPath = Path.Combine(this.TempFilesLocation, "merge.log"); merge.OpenLog(logPath); logOpen = true; merge.OpenDatabase(this.OutputPath); databaseOpen = true; // process all the merge rows foreach (WixMergeRow wixMergeRow in wixMergeTable.Rows) { bool moduleOpen = false; try { short mergeLanguage; try { mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); } catch (System.FormatException) { Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); continue; } Messaging.Instance.OnMessage(WixVerboses.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage)); merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); moduleOpen = true; // If there is merge configuration data, create a callback object to contain it all. ConfigurationCallback callback = null; if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData)) { callback = new ConfigurationCallback(wixMergeRow.ConfigurationData); } // merge the module into the database that's being built Messaging.Instance.OnMessage(WixVerboses.MergingMergeModule(wixMergeRow.SourceFile)); merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback); // connect any non-primary features if (null != wixFeatureModulesTable) { foreach (Row row in wixFeatureModulesTable.Rows) { if (wixMergeRow.Id == (string)row[1]) { Messaging.Instance.OnMessage(WixVerboses.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0])); merge.Connect((string)row[0]); } } } } catch (COMException) { commit = false; } finally { IMsmErrors mergeErrors = merge.Errors; // display all the errors encountered during the merge operations for this module for (int i = 1; i <= mergeErrors.Count; i++) { IMsmError mergeError = mergeErrors[i]; StringBuilder databaseKeys = new StringBuilder(); StringBuilder moduleKeys = new StringBuilder(); // build a string of the database keys for (int j = 1; j <= mergeError.DatabaseKeys.Count; j++) { if (1 != j) { databaseKeys.Append(';'); } databaseKeys.Append(mergeError.DatabaseKeys[j]); } // build a string of the module keys for (int j = 1; j <= mergeError.ModuleKeys.Count; j++) { if (1 != j) { moduleKeys.Append(';'); } moduleKeys.Append(mergeError.ModuleKeys[j]); } // display the merge error based on the msm error type switch (mergeError.Type) { case MsmErrorType.msmErrorExclusion: Messaging.Instance.OnMessage(WixErrors.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleKeys.ToString())); break; case MsmErrorType.msmErrorFeatureRequired: Messaging.Instance.OnMessage(WixErrors.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id)); break; case MsmErrorType.msmErrorLanguageFailed: Messaging.Instance.OnMessage(WixErrors.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorLanguageUnsupported: Messaging.Instance.OnMessage(WixErrors.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorResequenceMerge: Messaging.Instance.OnMessage(WixWarnings.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); break; case MsmErrorType.msmErrorTableMerge: if ("_Validation" != mergeError.DatabaseTable) // ignore merge errors in the _Validation table { Messaging.Instance.OnMessage(WixWarnings.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile)); } break; case MsmErrorType.msmErrorPlatformMismatch: Messaging.Instance.OnMessage(WixErrors.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile)); break; default: Messaging.Instance.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorWithType, Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace)); break; } } if (0 >= mergeErrors.Count && !commit) { Messaging.Instance.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorInSourceFile, wixMergeRow.SourceFile, logPath), "InvalidOperationException", Environment.StackTrace)); } if (moduleOpen) { merge.CloseModule(); } } } } finally { if (databaseOpen) { merge.CloseDatabase(commit); } if (logOpen) { merge.CloseLog(); } } // stop processing if an error previously occurred if (Messaging.Instance.EncounteredError) { return; } using (Database db = new Database(this.OutputPath, OpenDatabase.Direct)) { Table suppressActionTable = this.Output.Tables["WixSuppressAction"]; // suppress individual actions if (null != suppressActionTable) { foreach (Row row in suppressActionTable.Rows) { if (db.TableExists((string)row[0])) { string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]); using (View view = db.OpenExecuteView(query)) { using (Record record = view.Fetch()) { if (null != record) { Messaging.Instance.OnMessage(WixWarnings.SuppressMergedAction((string)row[1], row[0].ToString())); view.Modify(ModifyView.Delete, record); } } } } } } // query for merge module actions in suppressed sequences and drop them foreach (string tableName in this.SuppressedTableNames) { if (!db.TableExists(tableName)) { continue; } using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) { while (true) { using (Record resultRecord = view.Fetch()) { if (null == resultRecord) { break; } Messaging.Instance.OnMessage(WixWarnings.SuppressMergedAction(resultRecord.GetString(1), tableName)); } } } // drop suppressed sequences using (View view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName))) { } // delete the validation rows using (View view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?"))) { using (Record record = new Record(1)) { record.SetString(1, tableName); view.Execute(record); } } } // now update the Attributes column for the files from the Merge Modules Messaging.Instance.OnMessage(WixVerboses.ResequencingMergeModuleFiles()); using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) { foreach (FileFacade file in this.FileFacades) { if (!file.FromModule) { continue; } using (Record record = new Record(1)) { record.SetString(1, file.File.File); view.Execute(record); } using (Record recordUpdate = view.Fetch()) { if (null == recordUpdate) { throw new InvalidOperationException("Failed to fetch a File row from the database that was merged in from a module."); } recordUpdate.SetInteger(1, file.File.Sequence); // update the file attributes to match the compression specified // on the Merge element or on the Package element int attributes = 0; // get the current value if its not null if (!recordUpdate.IsNull(2)) { attributes = recordUpdate.GetInteger(2); } if (YesNoType.Yes == file.File.Compressed) { // these are mutually exclusive attributes |= MsiInterop.MsidbFileAttributesCompressed; attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; } else if (YesNoType.No == file.File.Compressed) { // these are mutually exclusive attributes |= MsiInterop.MsidbFileAttributesNoncompressed; attributes &= ~MsiInterop.MsidbFileAttributesCompressed; } else // not specified { Debug.Assert(YesNoType.NotSet == file.File.Compressed); // clear any compression bits attributes &= ~MsiInterop.MsidbFileAttributesCompressed; attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; } recordUpdate.SetInteger(2, attributes); view.Modify(ModifyView.Update, recordUpdate); } } } db.Commit(); } }
/// <summary> /// Sends a verbose message. /// </summary> /// <param name="verboseLevel">Level of the verbose message.</param> /// <param name="verboseMessage">Verbose message string.</param> public void OnExtensionVerbose(VerboseLevel verboseLevel, string verboseMessage) { this.OnMessage(WixVerboses.DecompilerExtensionVerbose(verboseLevel, verboseMessage)); }
public void Execute() { throw new NotImplementedException(); #if TODO this.FileTransfers = Enumerable.Empty <FileTransfer>(); this.ContentFilePaths = Enumerable.Empty <string>(); // First look for data we expect to find... Chain, WixGroups, etc. // We shouldn't really get past the linker phase if there are // no group items... that means that there's no UX, no Chain, // *and* no Containers! Table chainPackageTable = this.GetRequiredTable("WixBundlePackage"); Table wixGroupTable = this.GetRequiredTable("WixGroup"); // Ensure there is one and only one row in the WixBundle table. // The compiler and linker behavior should have colluded to get // this behavior. WixBundleRow bundleRow = (WixBundleRow)this.GetSingleRowTable("WixBundle"); bundleRow.PerMachine = true; // default to per-machine but the first-per user package wil flip the bundle per-user. // Ensure there is one and only one row in the WixBootstrapperApplication table. // The compiler and linker behavior should have colluded to get // this behavior. Row baRow = this.GetSingleRowTable("WixBootstrapperApplication"); // Ensure there is one and only one row in the WixChain table. // The compiler and linker behavior should have colluded to get // this behavior. WixChainRow chainRow = (WixChainRow)this.GetSingleRowTable("WixChain"); if (Messaging.Instance.EncounteredError) { return; } // If there are any fields to resolve later, create the cache to populate during bind. IDictionary <string, string> variableCache = null; if (this.DelayedFields.Any()) { variableCache = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase); } // TODO: Although the WixSearch tables are defined in the Util extension, // the Bundle Binder has to know all about them. We hope to revisit all // of this in the 4.0 timeframe. IEnumerable <WixSearchInfo> orderedSearches = this.OrderSearches(); // Extract files that come from cabinet files (this does not extract files from merge modules). { var extractEmbeddedFilesCommand = new ExtractEmbeddedFilesCommand(); extractEmbeddedFilesCommand.FilesWithEmbeddedFiles = ExpectedEmbeddedFiles; extractEmbeddedFilesCommand.Execute(); } // Get the explicit payloads. RowDictionary <WixBundlePayloadRow> payloads = new RowDictionary <WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]); // Update explicitly authored payloads with their parent package and container (as appropriate) // to make it easier to gather the payloads later. foreach (WixGroupRow row in wixGroupTable.RowsAs <WixGroupRow>()) { if (ComplexReferenceChildType.Payload == row.ChildType) { WixBundlePayloadRow payload = payloads.Get(row.ChildId); if (ComplexReferenceParentType.Package == row.ParentType) { Debug.Assert(String.IsNullOrEmpty(payload.Package)); payload.Package = row.ParentId; } else if (ComplexReferenceParentType.Container == row.ParentType) { Debug.Assert(String.IsNullOrEmpty(payload.Container)); payload.Container = row.ParentId; } else if (ComplexReferenceParentType.Layout == row.ParentType) { payload.LayoutOnly = true; } } } List <FileTransfer> fileTransfers = new List <FileTransfer>(); string layoutDirectory = Path.GetDirectoryName(this.OutputPath); // Process the explicitly authored payloads. ISet <string> processedPayloads; { ProcessPayloadsCommand command = new ProcessPayloadsCommand(); command.Payloads = payloads.Values; command.DefaultPackaging = bundleRow.DefaultPackagingType; command.LayoutDirectory = layoutDirectory; command.Execute(); fileTransfers.AddRange(command.FileTransfers); processedPayloads = new HashSet <string>(payloads.Keys); } IDictionary <string, PackageFacade> facades; { GetPackageFacadesCommand command = new GetPackageFacadesCommand(); command.PackageTable = chainPackageTable; command.ExePackageTable = this.Output.Tables["WixBundleExePackage"]; command.MsiPackageTable = this.Output.Tables["WixBundleMsiPackage"]; command.MspPackageTable = this.Output.Tables["WixBundleMspPackage"]; command.MsuPackageTable = this.Output.Tables["WixBundleMsuPackage"]; command.Execute(); facades = command.PackageFacades; } // Process each package facade. Note this is likely to add payloads and other rows to tables so // note that any indexes created above may be out of date now. foreach (PackageFacade facade in facades.Values) { switch (facade.Package.Type) { case WixBundlePackageType.Exe: { ProcessExePackageCommand command = new ProcessExePackageCommand(); command.AuthoredPayloads = payloads; command.Facade = facade; command.Execute(); // ? variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.ExePackage.Manufacturer); } break; case WixBundlePackageType.Msi: { var command = new ProcessMsiPackageCommand(); command.AuthoredPayloads = payloads; command.Facade = facade; command.BackendExtensions = this.BackendExtensions; command.MsiFeatureTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiFeature"]); command.MsiPropertyTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiProperty"]); command.PayloadTable = this.Output.Tables["WixBundlePayload"]; command.RelatedPackageTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleRelatedPackage"]); command.Execute(); if (null != variableCache) { variableCache.Add(String.Concat("packageLanguage.", facade.Package.WixChainItemId), facade.MsiPackage.ProductLanguage.ToString()); if (null != facade.MsiPackage.Manufacturer) { variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.MsiPackage.Manufacturer); } } } break; case WixBundlePackageType.Msp: { ProcessMspPackageCommand command = new ProcessMspPackageCommand(); command.AuthoredPayloads = payloads; command.Facade = facade; command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]); command.Execute(); } break; case WixBundlePackageType.Msu: { ProcessMsuPackageCommand command = new ProcessMsuPackageCommand(); command.Facade = facade; command.Execute(); } break; } if (null != variableCache) { BindBundleCommand.PopulatePackageVariableCache(facade.Package, variableCache); } } // Reindex the payloads now that all the payloads (minus the manifest payloads that will be created later) // are present. payloads = new RowDictionary <WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]); // Process the payloads that were added by processing the packages. { ProcessPayloadsCommand command = new ProcessPayloadsCommand(); command.Payloads = payloads.Values.Where(r => !processedPayloads.Contains(r.Id)).ToList(); command.DefaultPackaging = bundleRow.DefaultPackagingType; command.LayoutDirectory = layoutDirectory; command.Execute(); fileTransfers.AddRange(command.FileTransfers); processedPayloads = null; } // Set the package metadata from the payloads now that we have the complete payload information. ILookup <string, WixBundlePayloadRow> payloadsByPackage = payloads.Values.ToLookup(p => p.Package); { foreach (PackageFacade facade in facades.Values) { facade.Package.Size = 0; IEnumerable <WixBundlePayloadRow> packagePayloads = payloadsByPackage[facade.Package.WixChainItemId]; foreach (WixBundlePayloadRow payload in packagePayloads) { facade.Package.Size += payload.FileSize; } if (!facade.Package.InstallSize.HasValue) { facade.Package.InstallSize = facade.Package.Size; } WixBundlePayloadRow packagePayload = payloads[facade.Package.PackagePayload]; if (String.IsNullOrEmpty(facade.Package.Description)) { facade.Package.Description = packagePayload.Description; } if (String.IsNullOrEmpty(facade.Package.DisplayName)) { facade.Package.DisplayName = packagePayload.DisplayName; } } } // Give the UX payloads their embedded IDs... int uxPayloadIndex = 0; { foreach (WixBundlePayloadRow payload in payloads.Values.Where(p => Compiler.BurnUXContainerId == p.Container)) { // In theory, UX payloads could be embedded in the UX CAB, external to the bundle EXE, or even // downloaded. The current engine requires the UX to be fully present before any downloading starts, // so that rules out downloading. Also, the burn engine does not currently copy external UX payloads // into the temporary UX directory correctly, so we don't allow external either. if (PackagingType.Embedded != payload.Packaging) { Messaging.Instance.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.FullFileName)); payload.Packaging = PackagingType.Embedded; } payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, uxPayloadIndex); ++uxPayloadIndex; } if (0 == uxPayloadIndex) { // If we didn't get any UX payloads, it's an error! throw new WixException(WixErrors.MissingBundleInformation("BootstrapperApplication")); } // Give the embedded payloads without an embedded id yet an embedded id. int payloadIndex = 0; foreach (WixBundlePayloadRow payload in payloads.Values) { Debug.Assert(PackagingType.Unknown != payload.Packaging); if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.EmbeddedId)) { payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnAttachedContainerEmbeddedIdFormat, payloadIndex); ++payloadIndex; } } } // Determine patches to automatically slipstream. { AutomaticallySlipstreamPatchesCommand command = new AutomaticallySlipstreamPatchesCommand(); command.PackageFacades = facades.Values; command.SlipstreamMspTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleSlipstreamMsp"]); command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]); command.Execute(); } // If catalog files exist, non-embedded payloads should validate with the catalogs. IEnumerable <WixBundleCatalogRow> catalogs = this.Output.Tables["WixBundleCatalog"].RowsAs <WixBundleCatalogRow>(); if (catalogs.Any()) { VerifyPayloadsWithCatalogCommand command = new VerifyPayloadsWithCatalogCommand(); command.Catalogs = catalogs; command.Payloads = payloads.Values; command.Execute(); } if (Messaging.Instance.EncounteredError) { return; } IEnumerable <PackageFacade> orderedFacades; IEnumerable <WixBundleRollbackBoundaryRow> boundaries; { OrderPackagesAndRollbackBoundariesCommand command = new OrderPackagesAndRollbackBoundariesCommand(); command.Boundaries = new RowDictionary <WixBundleRollbackBoundaryRow>(this.Output.Tables["WixBundleRollbackBoundary"]); command.PackageFacades = facades; command.WixGroupTable = wixGroupTable; command.Execute(); orderedFacades = command.OrderedPackageFacades; boundaries = command.UsedRollbackBoundaries; } // Resolve any delayed fields before generating the manifest. if (this.DelayedFields.Any()) { var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(); resolveDelayedFieldsCommand.OutputType = this.Output.Type; resolveDelayedFieldsCommand.DelayedFields = this.DelayedFields; resolveDelayedFieldsCommand.ModularizationGuid = null; resolveDelayedFieldsCommand.VariableCache = variableCache; resolveDelayedFieldsCommand.Execute(); } // Set the overridable bundle provider key. this.SetBundleProviderKey(this.Output, bundleRow); // Import or generate dependency providers for packages in the manifest. this.ProcessDependencyProviders(this.Output, facades); // Update the bundle per-machine/per-user scope based on the chained packages. this.ResolveBundleInstallScope(bundleRow, orderedFacades); // Generate the core-defined BA manifest tables... { CreateBootstrapperApplicationManifestCommand command = new CreateBootstrapperApplicationManifestCommand(); command.BundleRow = bundleRow; command.ChainPackages = orderedFacades; command.LastUXPayloadIndex = uxPayloadIndex; command.MsiFeatures = this.Output.Tables["WixBundleMsiFeature"].RowsAs <WixBundleMsiFeatureRow>(); command.Output = this.Output; command.Payloads = payloads; command.TableDefinitions = this.TableDefinitions; command.TempFilesLocation = this.IntermediateFolder; command.Execute(); WixBundlePayloadRow baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; payloads.Add(baManifestPayload); } //foreach (BinderExtension extension in this.Extensions) //{ // extension.PostBind(this.Context); //} // Create all the containers except the UX container first so the manifest (that goes in the UX container) // can contain all size and hash information about the non-UX containers. RowDictionary <WixBundleContainerRow> containers = new RowDictionary <WixBundleContainerRow>(this.Output.Tables["WixBundleContainer"]); ILookup <string, WixBundlePayloadRow> payloadsByContainer = payloads.Values.ToLookup(p => p.Container); int attachedContainerIndex = 1; // count starts at one because UX container is "0". IEnumerable <WixBundlePayloadRow> uxContainerPayloads = Enumerable.Empty <WixBundlePayloadRow>(); foreach (WixBundleContainerRow container in containers.Values) { IEnumerable <WixBundlePayloadRow> containerPayloads = payloadsByContainer[container.Id]; if (!containerPayloads.Any()) { if (container.Id != Compiler.BurnDefaultAttachedContainerId) { // TODO: display warning that we're ignoring container that ended up with no paylods in it. } } else if (Compiler.BurnUXContainerId == container.Id) { container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); container.AttachedContainerIndex = 0; // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first // in the list since that is the Payload that Burn attempts to load. List <WixBundlePayloadRow> uxPayloads = new List <WixBundlePayloadRow>(); string baPayloadId = baRow.FieldAsString(0); foreach (WixBundlePayloadRow uxPayload in containerPayloads) { if (uxPayload.Id == baPayloadId) { uxPayloads.Insert(0, uxPayload); } else { uxPayloads.Add(uxPayload); } } uxContainerPayloads = uxPayloads; } else { container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); // Add detached containers to the list of file transfers. if (ContainerType.Detached == container.Type) { FileTransfer transfer; if (FileTransfer.TryCreate(container.WorkingPath, Path.Combine(layoutDirectory, container.Name), true, "Container", container.SourceLineNumbers, out transfer)) { transfer.Built = true; fileTransfers.Add(transfer); } } else // update the attached container index. { Debug.Assert(ContainerType.Attached == container.Type); container.AttachedContainerIndex = attachedContainerIndex; ++attachedContainerIndex; } this.CreateContainer(container, containerPayloads, null); } } // Create the bundle manifest then UX container. string manifestPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml"); { var command = new CreateBurnManifestCommand(); command.BackendExtensions = this.BackendExtensions; command.Output = this.Output; command.BundleInfo = bundleRow; command.Chain = chainRow; command.Containers = containers; command.Catalogs = catalogs; command.ExecutableName = Path.GetFileName(this.OutputPath); command.OrderedPackages = orderedFacades; command.OutputPath = manifestPath; command.RollbackBoundaries = boundaries; command.OrderedSearches = orderedSearches; command.Payloads = payloads; command.UXContainerPayloads = uxContainerPayloads; command.Execute(); } WixBundleContainerRow uxContainer = containers[Compiler.BurnUXContainerId]; this.CreateContainer(uxContainer, uxContainerPayloads, manifestPath); // Copy the burn.exe to a writable location then mark it to be moved to its final build location. Note // that today, the x64 Burn uses the x86 stub. string stubPlatform = (Platform.X64 == bundleRow.Platform) ? "x86" : bundleRow.Platform.ToString(); string stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe"); string bundleTempPath = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); Messaging.Instance.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile)); string bundleFilename = Path.GetFileName(this.OutputPath); if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase)) { Messaging.Instance.OnMessage(WixErrors.InsecureBundleFilename(bundleFilename)); } FileTransfer bundleTransfer; if (FileTransfer.TryCreate(bundleTempPath, this.OutputPath, true, "Bundle", bundleRow.SourceLineNumbers, out bundleTransfer)) { bundleTransfer.Built = true; fileTransfers.Add(bundleTransfer); } File.Copy(stubFile, bundleTempPath, true); File.SetAttributes(bundleTempPath, FileAttributes.Normal); this.UpdateBurnResources(bundleTempPath, this.OutputPath, bundleRow); // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers // if they should be attached. using (BurnWriter writer = BurnWriter.Open(bundleTempPath)) { FileInfo burnStubFile = new FileInfo(bundleTempPath); writer.InitializeBundleSectionData(burnStubFile.Length, bundleRow.BundleId); // Always attach the UX container first writer.AppendContainer(uxContainer.WorkingPath, BurnWriter.Container.UX); // Now append all other attached containers foreach (WixBundleContainerRow container in containers.Values) { if (ContainerType.Attached == container.Type) { // The container was only created if it had payloads. if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id) { writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached); } } } } if (null != this.PdbFile) { Pdb pdb = new Pdb(); pdb.Output = Output; pdb.Save(this.PdbFile); } this.FileTransfers = fileTransfers; this.ContentFilePaths = payloads.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList(); }
/// <summary> /// Sends a verbose message. /// </summary> /// <param name="sourceLineNumbers">Source line numbers.</param> /// <param name="verboseLevel">Level of the verbose message.</param> /// <param name="verboseMessage">Verbose message string.</param> public void OnExtensionVerbose(SourceLineNumberCollection sourceLineNumbers, VerboseLevel verboseLevel, string verboseMessage) { this.OnMessage(WixVerboses.CompilerExtensionVerbose(sourceLineNumbers, verboseLevel, verboseMessage)); }
/// <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)) { BindPath bindPath = CommandLine.GetBindPath(parameter, args, ++i); if (null == bindPath) { break; } 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; } this.DefaultCompressionLevel = WixCreateCab.CompressionLevelFromString(defaultCompressionLevel); } else if (parameter.StartsWith("d", StringComparison.Ordinal)) { parameter = arg.Substring(2); string[] value = parameter.Split("=".ToCharArray(), 2); string preexisting; if (1 == value.Length) { Messaging.Instance.OnMessage(WixErrors.ExpectedWixVariableValue(value[0])); } else if (this.Variables.TryGetValue(value[0], out preexisting)) { Messaging.Instance.OnMessage(WixErrors.WixVariableCollision(null, value[0])); } else { this.Variables.Add(value[0], value[1]); } } else if (parameter.Equals("ext", StringComparison.Ordinal)) { if (!CommandLine.IsValidArg(args, ++i)) { Messaging.Instance.OnMessage(WixErrors.TypeSpecificationForExtensionRequired("-ext")); break; } this.Extensions.Add(args[i]); } else if (parameter.Equals("loc", StringComparison.Ordinal)) { string locFile = CommandLine.GetFile(parameter, 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 = CommandLine.GetFile(parameter, 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 = CommandLine.GetFile(parameter, 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 = CommandLine.GetDirectory(parameter, args, ++i); if (String.IsNullOrEmpty(this.CabCachePath)) { break; } } else if (parameter.Equals("ct", StringComparison.Ordinal)) { if (!CommandLine.IsValidArg(args, ++i)) { Messaging.Instance.OnMessage(WixErrors.IllegalCabbingThreadCount(String.Empty)); break; } int ct = 0; if (!Int32.TryParse(args[i], out ct) || 0 >= ct) { Messaging.Instance.OnMessage(WixErrors.IllegalCabbingThreadCount(args[i])); break; } this.CabbingThreadCount = ct; Messaging.Instance.OnMessage(WixVerboses.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } else if (parameter.Equals("cub", StringComparison.Ordinal)) { string cubeFile = CommandLine.GetFile(parameter, args, ++i); if (String.IsNullOrEmpty(cubeFile)) { break; } this.CubeFiles.Add(cubeFile); } else if (parameter.Equals("eav", StringComparison.Ordinal)) { Messaging.Instance.OnMessage(WixWarnings.DeprecatedCommandLineSwitch(arg)); } else if (parameter.StartsWith("ice:", StringComparison.Ordinal)) { this.Ices.Add(parameter.Substring(4)); } else if (parameter.Equals("contentsfile", StringComparison.Ordinal)) { this.ContentsFile = CommandLine.GetFile(parameter, args, ++i); if (String.IsNullOrEmpty(this.ContentsFile)) { break; } } else if (parameter.Equals("outputsfile", StringComparison.Ordinal)) { this.OutputsFile = CommandLine.GetFile(parameter, args, ++i); if (String.IsNullOrEmpty(this.OutputsFile)) { break; } } else if (parameter.Equals("builtoutputsfile", StringComparison.Ordinal)) { this.BuiltOutputsFile = CommandLine.GetFile(parameter, args, ++i); if (String.IsNullOrEmpty(this.BuiltOutputsFile)) { break; } } else if (parameter.Equals("wixprojectfile", StringComparison.Ordinal)) { this.WixprojectFile = CommandLine.GetFile(parameter, args, ++i); if (String.IsNullOrEmpty(this.WixprojectFile)) { break; } } else if (parameter.Equals("pdbout", StringComparison.Ordinal)) { this.PdbFile = CommandLine.GetFile(parameter, args, ++i); if (String.IsNullOrEmpty(this.PdbFile)) { break; } } else if (parameter.Equals("reusecab", StringComparison.Ordinal)) { Messaging.Instance.OnMessage(WixWarnings.DeprecatedCommandLineSwitch(arg, "-cc")); } 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) { Messaging.Instance.SuppressAllWarnings = true; } else { int suppressWarning = 0; if (!Int32.TryParse(paramArg, out suppressWarning) || 0 >= suppressWarning) { Messaging.Instance.OnMessage(WixErrors.IllegalSuppressWarningId(paramArg)); } else { Messaging.Instance.SuppressWarningMessage(suppressWarning); } } } else if (parameter.StartsWith("wx", StringComparison.Ordinal)) { string paramArg = parameter.Substring(2); if (0 == paramArg.Length) { Messaging.Instance.WarningsAsError = true; } else { int elevateWarning = 0; if (!Int32.TryParse(paramArg, out elevateWarning) || 0 >= elevateWarning) { Messaging.Instance.OnMessage(WixErrors.IllegalWarningIdAsError(paramArg)); } else { Messaging.Instance.ElevateWarningMessage(elevateWarning); } } } else if ("v" == parameter) { Messaging.Instance.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()); }