Ejemplo n.º 1
0
        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));
                }
            }
        }
Ejemplo n.º 2
0
        /// <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));
                }
            }
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        /// <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]));
            }
        }
Ejemplo n.º 5
0
        /// <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();
            }
        }
Ejemplo n.º 6
0
 /// <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));
     }
 }
Ejemplo n.º 7
0
        /// <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);
            }
        }
Ejemplo n.º 8
0
        /// <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);
            }
        }
Ejemplo n.º 9
0
        /// <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));
            }
        }
Ejemplo n.º 10
0
        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;
        }
Ejemplo n.º 11
0
        /// <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();
            }
        }
Ejemplo n.º 12
0
        /// <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);
        }
Ejemplo n.º 13
0
        /// <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();
            }
        }
Ejemplo n.º 14
0
        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());
                }
            }
        }
Ejemplo n.º 15
0
        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"));
        }
Ejemplo n.º 16
0
        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);
        }
Ejemplo n.º 17
0
        /// <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();
            }
        }
Ejemplo n.º 18
0
        /// <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);
        }
Ejemplo n.º 19
0
        /// <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());
                }
            }
        }
Ejemplo n.º 20
0
        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();
            }
        }
Ejemplo n.º 21
0
 /// <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));
 }
Ejemplo n.º 22
0
        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();
        }
Ejemplo n.º 23
0
 /// <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());
        }