예제 #1
0
파일: Layout.cs 프로젝트: slamj1/Core-4
        public void Execute()
        {
            this.Messaging = this.ServiceProvider.GetService <IMessaging>();

            var extensionManager = this.ServiceProvider.GetService <IExtensionManager>();

            var context = this.ServiceProvider.GetService <ILayoutContext>();

            context.Messaging        = this.Messaging;
            context.Extensions       = extensionManager.Create <ILayoutExtension>();
            context.FileTransfers    = this.FileTransfers;
            context.ContentFilePaths = this.ContentFilePaths;
            context.ContentsFile     = this.ContentsFile;
            context.OutputPdbPath    = this.OutputsFile;
            context.BuiltOutputsFile = this.BuiltOutputsFile;
            context.SuppressAclReset = this.SuppressAclReset;

            // Pre-layout.
            //
            foreach (var extension in context.Extensions)
            {
                extension.PreLayout(context);
            }

            try
            {
                // Final step in binding that transfers (moves/copies) all files generated into the appropriate
                // location in the source image.
                if (context.FileTransfers?.Any() == true)
                {
                    this.Messaging.Write(VerboseMessages.LayingOutMedia());

                    var command = new TransferFilesCommand(context.Messaging, context.Extensions, context.FileTransfers, context.SuppressAclReset);
                    command.Execute();
                }
            }
            finally
            {
                if (!String.IsNullOrEmpty(context.ContentsFile) && context.ContentFilePaths != null)
                {
                    this.CreateContentsFile(context.ContentsFile, context.ContentFilePaths);
                }

                if (!String.IsNullOrEmpty(context.OutputsFile) && context.FileTransfers != null)
                {
                    this.CreateOutputsFile(context.OutputsFile, context.FileTransfers, context.OutputPdbPath);
                }

                if (!String.IsNullOrEmpty(context.BuiltOutputsFile) && context.FileTransfers != null)
                {
                    this.CreateBuiltOutputsFile(context.BuiltOutputsFile, context.FileTransfers, context.OutputPdbPath);
                }
            }

            // Post-layout.
            foreach (var extension in context.Extensions)
            {
                extension.PostLayout();
            }
        }
예제 #2
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, string bundleId)
        {
            if (this.invalidBundle)
            {
                return(false);
            }

            var bundleGuid = Guid.Parse(bundleId);

            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_MAGIC, BURN_SECTION_MAGIC);
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_VERSION, BURN_SECTION_VERSION);

            this.messaging.Write(VerboseMessages.BundleGuid(bundleId));
            this.binaryWriter.BaseStream.Seek(this.wixburnDataOffset + BURN_SECTION_OFFSET_BUNDLEGUID, SeekOrigin.Begin);
            this.binaryWriter.Write(bundleGuid.ToByteArray());

            this.StubSize = (uint)stubSize;

            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_STUBSIZE, this.StubSize);
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALCHECKSUM, 0);
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET, 0);
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE, 0);
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_FORMAT, 1); // Hard-coded to CAB for now.
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_COUNT, 0);
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_UXSIZE, 0);
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE, 0);
            this.binaryWriter.BaseStream.Flush();

            this.EngineSize = this.StubSize;

            return(true);
        }
예제 #3
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(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors));
                        }
                    }
                    else // default to 1 if the environment variable is not set
                    {
                        this.CabbingThreadCount = 1;
                    }

                    this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString()));
                }
                catch (ArgumentException)
                {
                    throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors));
                }
                catch (FormatException)
                {
                    throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors));
                }
            }
        }
예제 #4
0
        private void ResolveBundleInstallScope(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable <PackageFacade> facades)
        {
            var dependencySymbolsById = section.Symbols.OfType <WixDependencyProviderSymbol>().ToDictionary(t => t.Id.Id);

            foreach (var facade in facades)
            {
                if (bundleSymbol.PerMachine && YesNoDefaultType.No == facade.PackageSymbol.PerMachine)
                {
                    this.Messaging.Write(VerboseMessages.SwitchingToPerUserPackage(facade.PackageSymbol.SourceLineNumbers, facade.PackageId));

                    bundleSymbol.Attributes &= ~WixBundleAttributes.PerMachine;
                    break;
                }
            }

            foreach (var facade in facades)
            {
                // Update package scope from bundle scope if default.
                if (YesNoDefaultType.Default == facade.PackageSymbol.PerMachine)
                {
                    facade.PackageSymbol.PerMachine = bundleSymbol.PerMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No;
                }

                // We will only register packages in the same scope as the bundle. Warn if any packages with providers
                // are in a different scope and not permanent (permanents typically don't need a ref-count).
                if (!bundleSymbol.PerMachine &&
                    YesNoDefaultType.Yes == facade.PackageSymbol.PerMachine &&
                    !facade.PackageSymbol.Permanent &&
                    dependencySymbolsById.ContainsKey(facade.PackageId))
                {
                    this.Messaging.Write(WarningMessages.NoPerMachineDependencies(facade.PackageSymbol.SourceLineNumbers, facade.PackageId));
                }
            }
        }
예제 #5
0
        private int CalculateCabbingThreadCount()
        {
            var cabbingThreadCount = 1;  // default to 1 if the environment variable is not set.

            var numberOfProcessors = Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS");

            try
            {
                if (!String.IsNullOrEmpty(numberOfProcessors))
                {
                    cabbingThreadCount = Convert.ToInt32(numberOfProcessors, CultureInfo.InvariantCulture.NumberFormat);

                    if (cabbingThreadCount <= 0)
                    {
                        throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors));
                    }
                }

                this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString()));
            }
            catch (ArgumentException)
            {
                throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors));
            }
            catch (FormatException)
            {
                throw new WixException(ErrorMessages.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors));
            }

            return(cabbingThreadCount);
        }
        private void LogValidationMessage(ValidationMessage message)
        {
            var messageSourceLineNumbers = this.OutputSourceLineNumber;

            if (!String.IsNullOrEmpty(message.Table) && !String.IsNullOrEmpty(message.Column) && message.PrimaryKeys != null)
            {
                messageSourceLineNumbers = this.GetSourceLineNumbers(message.Table, message.PrimaryKeys);
            }

            switch (message.Type)
            {
            case ValidationMessageType.InternalFailure:
            case ValidationMessageType.Error:
                this.Messaging.Write(ErrorMessages.ValidationError(messageSourceLineNumbers, message.IceName, message.Description));
                break;

            case ValidationMessageType.Warning:
                this.Messaging.Write(WarningMessages.ValidationWarning(messageSourceLineNumbers, message.IceName, message.Description));
                break;

            case ValidationMessageType.Info:
                this.Messaging.Write(VerboseMessages.ValidationInfo(message.IceName, message.Description));
                break;

            default:
                throw new WixException(ErrorMessages.InvalidValidatorMessageType(message.Type.ToString()));
            }
        }
        public void Execute()
        {
            var bundleFilename = Path.GetFileName(this.OutputPath);

            // Copy the burn.exe to a writable location then mark it to be moved to its final build location.

            var stubPlatform = this.BundleSymbol.Platform.ToString();
            var stubFile     = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe");

            if (stubPlatform != "X86")
            {
                this.Messaging.Write(WarningMessages.ExperimentalBundlePlatform(stubPlatform));
            }

            var bundleTempPath = Path.Combine(this.IntermediateFolder, bundleFilename);

            this.Messaging.Write(VerboseMessages.GeneratingBundle(bundleTempPath, stubFile));

            if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase))
            {
                this.Messaging.Write(ErrorMessages.InsecureBundleFilename(bundleFilename));
            }

            this.Transfer = this.BackendHelper.CreateFileTransfer(bundleTempPath, this.OutputPath, true, this.BundleSymbol.SourceLineNumbers);

            File.Copy(stubFile, bundleTempPath, true);
            File.SetAttributes(bundleTempPath, FileAttributes.Normal);

            var windowsAssemblyVersion = GetWindowsAssemblyVersion(this.BundleSymbol);

            var applicationManifestData = GenerateApplicationManifest(this.BundleSymbol, this.BootstrapperApplicationDllSymbol, this.OutputPath, windowsAssemblyVersion);

            UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol, windowsAssemblyVersion, applicationManifestData);

            // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers
            // if they should be attached.
            using (var writer = BurnWriter.Open(this.Messaging, bundleTempPath))
            {
                var burnStubFile = new FileInfo(bundleTempPath);
                writer.InitializeBundleSectionData(burnStubFile.Length, this.BundleSymbol.BundleId);

                // Always attach the UX container first
                writer.AppendContainer(this.UXContainer.WorkingPath, BurnWriter.Container.UX);

                // Now append all other attached containers
                foreach (var container in this.Containers)
                {
                    if (ContainerType.Attached == container.Type)
                    {
                        // The container was only created if it had payloads.
                        if (!String.IsNullOrEmpty(container.WorkingPath) && BurnConstants.BurnUXContainerName != container.Id.Id)
                        {
                            writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached);
                        }
                    }
                }
            }
        }
예제 #8
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(ErrorMessages.UnexpectedExternalUIMessage(message));
                }
                else
                {
                    throw new WixException(ErrorMessages.UnexpectedExternalUIMessage(message, action));
                }
            }

            SourceLineNumber messageSourceLineNumbers = null;

            if (6 < messageParts.Length)
            {
                string[] primaryKeys = new string[messageParts.Length - 6];

                Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length);

                messageSourceLineNumbers = this.GetSourceLineNumbers(messageParts[4], primaryKeys);
            }
            else // use the file name as the source line information
            {
                messageSourceLineNumbers = this.sourceLineNumbers;
            }

            switch (messageParts[1])
            {
            case "0":
            case "1":
                this.messaging.Write(ErrorMessages.ValidationError(messageSourceLineNumbers, messageParts[0], messageParts[2]));
                break;

            case "2":
                this.messaging.Write(WarningMessages.ValidationWarning(messageSourceLineNumbers, messageParts[0], messageParts[2]));
                break;

            case "3":
                this.messaging.Write(VerboseMessages.ValidationInfo(messageParts[0], messageParts[2]));
                break;

            default:
                throw new WixException(ErrorMessages.InvalidValidatorMessageType(messageParts[1]));
            }
        }
예제 #9
0
        public void Layout(ILayoutContext context)
        {
            // Pre-layout.
            //
            foreach (var extension in context.Extensions)
            {
                extension.PreLayout(context);
            }

            try
            {
                // Final step in binding that transfers (moves/copies) all files generated into the appropriate
                // location in the source image.
                if (context.FileTransfers?.Any() == true)
                {
                    this.Messaging.Write(VerboseMessages.LayingOutMedia());

                    var command = new TransferFilesCommand(this.Messaging, context.Extensions, context.FileTransfers, context.SuppressAclReset);
                    command.Execute();
                }

                if (context.TrackedFiles != null)
                {
                    this.CleanTempFiles(context.IntermediateFolder, context.TrackedFiles);
                }
            }
            finally
            {
                if (context.TrackedFiles != null)
                {
                    if (!String.IsNullOrEmpty(context.ContentsFile))
                    {
                        this.CreateContentsFile(context.ContentsFile, context.TrackedFiles);
                    }

                    if (!String.IsNullOrEmpty(context.OutputsFile))
                    {
                        this.CreateOutputsFile(context.OutputsFile, context.TrackedFiles);
                    }

                    if (!String.IsNullOrEmpty(context.BuiltOutputsFile))
                    {
                        this.CreateBuiltOutputsFile(context.BuiltOutputsFile, context.TrackedFiles);
                    }
                }
            }

            // Post-layout.
            foreach (var extension in context.Extensions)
            {
                extension.PostLayout();
            }
        }
예제 #10
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.Messaging.Write(VerboseMessages.CreateCabinet(cabinetWorkItem.CabinetFile));

            int   maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting
            ulong maxPreCompressedSizeInBytes = 0;

            if (this.MaximumCabinetSizeForLargeFileSplitting != 0)
            {
                // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize
                // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file
                if (1 == cabinetWorkItem.FileFacades.Count())
                {
                    // Cabinet has Single File, Check if this is Large File than needs Splitting into Multiple cabs
                    // Get the Value for Max Uncompressed Media Size
                    maxPreCompressedSizeInBytes = (ulong)MaximumUncompressedMediaSize * 1024 * 1024;

                    foreach (FileFacade facade in cabinetWorkItem.FileFacades) // No other easy way than looping to get the only row
                    {
                        if ((ulong)facade.File.FileSize >= maxPreCompressedSizeInBytes)
                        {
                            // If file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting
                            maxCabinetSize = this.MaximumCabinetSizeForLargeFileSplitting;
                        }
                    }
                }
            }

            // create the cabinet file
            var    cabinetPath      = Path.GetFullPath(cabinetWorkItem.CabinetFile);
            string cabinetFileName  = Path.GetFileName(cabinetWorkItem.CabinetFile);
            string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile);

            var files = cabinetWorkItem.FileFacades
                        .Select(facade => facade.Hash == null ?
                                new CabinetCompressFile(facade.WixFile.Source.Path, facade.File.File) :
                                new CabinetCompressFile(facade.WixFile.Source.Path, facade.File.File, facade.Hash.HashPart1, facade.Hash.HashPart2, facade.Hash.HashPart3, facade.Hash.HashPart4))
                        .ToList();

            var cabinetCompressionLevel = (CabinetCompressionLevel)cabinetWorkItem.CompressionLevel;

            var cab = new Cabinet(cabinetPath);

            cab.Compress(files, cabinetCompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold);

            // TODO: Handle newCabNamesCallBackAddress from compression.
        }
        public void Execute()
        {
            this.lastCabinetAddedToMediaTable = new Dictionary <string, string>();

            // If the cabbing thread count wasn't provided, default the number of cabbing threads to the number of processors.
            if (this.CabbingThreadCount <= 0)
            {
                this.CabbingThreadCount = this.CalculateCabbingThreadCount();

                this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString()));
            }

            // Send Binder object to Facilitate NewCabNamesCallBack Callback
            var cabinetBuilder = new CabinetBuilder(this.Messaging, this.CabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack));

            // Supply Compile MediaTemplate Attributes to Cabinet Builder
            this.GetMediaTemplateAttributes(out var maximumCabinetSizeForLargeFileSplitting, out var maximumUncompressedMediaSize);
            cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = maximumCabinetSizeForLargeFileSplitting;
            cabinetBuilder.MaximumUncompressedMediaSize            = maximumUncompressedMediaSize;

            foreach (var entry in this.FileFacadesByCabinet)
            {
                var mediaSymbol      = entry.Key;
                var files            = entry.Value;
                var compressionLevel = mediaSymbol.CompressionLevel ?? this.DefaultCompressionLevel ?? CompressionLevel.Medium;
                var cabinetDir       = this.ResolveMedia(mediaSymbol, mediaSymbol.Layout, this.LayoutDirectory);

                var cabinetWorkItem = this.CreateCabinetWorkItem(this.Data, cabinetDir, mediaSymbol, compressionLevel, files);
                if (null != cabinetWorkItem)
                {
                    cabinetBuilder.Enqueue(cabinetWorkItem);
                }
            }

            // stop processing if an error previously occurred
            if (this.Messaging.EncounteredError)
            {
                return;
            }

            // create queued cabinets with multiple threads
            cabinetBuilder.CreateQueuedCabinets();
            if (this.Messaging.EncounteredError)
            {
                return;
            }
        }
예제 #12
0
        public static bool ConfigVerboseMessages(
            XmlElement xmlElem, string name,
            ref VerboseMessages verbose, bool compulsory)
        {
            XmlNode xmlNode = XMLReader.GetNode(xmlElem,
                                                name);

            if (xmlNode == null && compulsory == false)
            {
                return(false);
            }
            else if (xmlNode == null && compulsory == true)
            {
                throw new ConfigNotFoundException(name);
            }

            ConfigBool((XmlElement)xmlNode, "AllFileOps",
                       ref verbose.AllFileOps, compulsory);
            ConfigBool((XmlElement)xmlNode, "Deadlock",
                       ref verbose.Deadlock, compulsory);
            ConfigBool((XmlElement)xmlNode, "FileOps",
                       ref verbose.FileOps, compulsory);
            ConfigBool((XmlElement)xmlNode, "Recovery",
                       ref verbose.Recovery, compulsory);
            ConfigBool((XmlElement)xmlNode, "Register",
                       ref verbose.Register, compulsory);
            ConfigBool((XmlElement)xmlNode, "Replication",
                       ref verbose.Replication, compulsory);
            ConfigBool((XmlElement)xmlNode, "ReplicationElection",
                       ref verbose.ReplicationElection, compulsory);
            ConfigBool((XmlElement)xmlNode, "ReplicationLease",
                       ref verbose.ReplicationLease, compulsory);
            ConfigBool((XmlElement)xmlNode, "ReplicationMessages",
                       ref verbose.ReplicationMessages, compulsory);
            ConfigBool((XmlElement)xmlNode, "ReplicationMisc",
                       ref verbose.ReplicationMisc, compulsory);
            ConfigBool((XmlElement)xmlNode, "ReplicationSync",
                       ref verbose.ReplicationSync, compulsory);
            ConfigBool((XmlElement)xmlNode, "RepMgrConnectionFailure",
                       ref verbose.RepMgrConnectionFailure, compulsory);
            ConfigBool((XmlElement)xmlNode, "RepMgrMisc",
                       ref verbose.RepMgrMisc, compulsory);
            ConfigBool((XmlElement)xmlNode, "WaitsForTable",
                       ref verbose.WaitsForTable, compulsory);
            return(true);
        }
예제 #13
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.Messaging.Write(VerboseMessages.CreateCabinet(cabinetWorkItem.CabinetFile));

            var   maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting
            ulong maxPreCompressedSizeInBytes = 0;

            if (this.MaximumCabinetSizeForLargeFileSplitting != 0)
            {
                // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize
                // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file
                if (1 == cabinetWorkItem.FileFacades.Count())
                {
                    // Cabinet has Single File, Check if this is Large File than needs Splitting into Multiple cabs
                    // Get the Value for Max Uncompressed Media Size
                    maxPreCompressedSizeInBytes = (ulong)this.MaximumUncompressedMediaSize * 1024 * 1024;

                    var facade = cabinetWorkItem.FileFacades.First();

                    // If the file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting
                    if ((ulong)facade.FileSize >= maxPreCompressedSizeInBytes)
                    {
                        maxCabinetSize = this.MaximumCabinetSizeForLargeFileSplitting;
                    }
                }
            }

            // create the cabinet file
            var cabinetPath = Path.GetFullPath(cabinetWorkItem.CabinetFile);

            var files = cabinetWorkItem.FileFacades
                        .OrderBy(f => f.Sequence)
                        .Select(facade => facade.Hash == null ?
                                new CabinetCompressFile(facade.SourcePath, facade.Id + cabinetWorkItem.ModularizationSuffix) :
                                new CabinetCompressFile(facade.SourcePath, facade.Id + cabinetWorkItem.ModularizationSuffix, facade.Hash.HashPart1, facade.Hash.HashPart2, facade.Hash.HashPart3, facade.Hash.HashPart4))
                        .ToList();

            var cab = new Cabinet(cabinetPath);

            cab.Compress(files, cabinetWorkItem.CompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold);

            // TODO: Handle newCabNamesCallBackAddress from compression.
        }
        public void Execute()
        {
            var trackedFiles = new List <ITrackedFile>();
            var stopwatch    = Stopwatch.StartNew();

            this.Messaging.Write(VerboseMessages.ValidatingDatabase());

            // Ensure the temporary files can be created the working folder.
            var workingFolder = Path.Combine(this.IntermediateFolder, "_validate");

            Directory.CreateDirectory(workingFolder);

            // Copy the database to a temporary location so it can be manipulated.
            // Ensure it is not read-only.
            var workingDatabasePath = Path.Combine(workingFolder, Path.GetFileName(this.OutputPath));

            FileSystem.CopyFile(this.OutputPath, workingDatabasePath, allowHardlink: false);

            var trackWorkingDatabase = this.BackendHelper.TrackFile(workingDatabasePath, TrackedFileType.Temporary);

            trackedFiles.Add(trackWorkingDatabase);

            var attributes = File.GetAttributes(workingDatabasePath);

            File.SetAttributes(workingDatabasePath, attributes & ~FileAttributes.ReadOnly);

            var validator = new WindowsInstallerValidator(this, workingDatabasePath, this.CubeFiles, this.Ices, this.SuppressedIces);

            validator.Execute();

            stopwatch.Stop();
            this.Messaging.Write(VerboseMessages.ValidatedDatabase(stopwatch.ElapsedMilliseconds));


            this.TrackedFiles = trackedFiles;
        }
예제 #15
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);
        }
예제 #16
0
 public void LogVerbose(string data)
 {
     Messages.Enqueue(data);
     VerboseMessages.Enqueue(data);
     DumpMessage("TRACE", data);
 }
예제 #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)
        {
            int              previousUILevel   = (int)InstallUILevels.Basic;
            IntPtr           previousHwnd      = IntPtr.Zero;
            InstallUIHandler previousUIHandler = null;

            if (null == databaseFile)
            {
                throw new ArgumentNullException("databaseFile");
            }

            // initialize the validator extension
            this.extension.DatabaseFile = databaseFile;
            this.extension.Output       = this.output;
            this.extension.InitializeValidator();

            // Ensure the temporary files can be created.
            Directory.CreateDirectory(this.IntermediateFolder);

            // copy the database to a temporary location so it can be manipulated
            string tempDatabaseFile = Path.Combine(this.IntermediateFolder, Path.GetFileName(databaseFile));

            File.Copy(databaseFile, tempDatabaseFile);

            // remove the read-only property from the temporary database
            FileAttributes attributes = File.GetAttributes(tempDatabaseFile);

            File.SetAttributes(tempDatabaseFile, attributes & ~FileAttributes.ReadOnly);

            Mutex mutex = new Mutex(false, "WixValidator");

            try
            {
                if (!mutex.WaitOne(0, false))
                {
                    this.messaging.Write(VerboseMessages.ValidationSerialized());
                    mutex.WaitOne();
                }

                using (Database database = new Database(tempDatabaseFile, OpenDatabase.Direct))
                {
                    bool   propertyTableExists = database.TableExists("Property");
                    string productCode         = null;

                    // remove the product code from the database before opening a session to prevent opening an installed product
                    if (propertyTableExists)
                    {
                        using (View view = database.OpenExecuteView("SELECT `Value` FROM `Property` WHERE Property = 'ProductCode'"))
                        {
                            using (Record record = view.Fetch())
                            {
                                if (null != record)
                                {
                                    productCode = record.GetString(1);

                                    using (View dropProductCodeView = database.OpenExecuteView("DELETE FROM `Property` WHERE `Property` = 'ProductCode'"))
                                    {
                                    }
                                }
                            }
                        }
                    }

                    // merge in the cube databases
                    foreach (string cubeFile in this.cubeFiles)
                    {
                        try
                        {
                            using (Database cubeDatabase = new Database(cubeFile, OpenDatabase.ReadOnly))
                            {
                                try
                                {
                                    database.Merge(cubeDatabase, "MergeConflicts");
                                }
                                catch
                                {
                                    // ignore merge errors since they are expected in the _Validation table
                                }
                            }
                        }
                        catch (Win32Exception e)
                        {
                            if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED
                            {
                                throw new WixException(ErrorMessages.CubeFileNotFound(cubeFile));
                            }

                            throw;
                        }
                    }

                    // commit the database before proceeding to ensure the streams don't get confused
                    database.Commit();

                    // the property table may have been added to the database
                    // from a cub database without the proper validation rows
                    if (!propertyTableExists)
                    {
                        using (View view = database.OpenExecuteView("DROP table `Property`"))
                        {
                        }
                    }

                    // get all the action names for ICEs which have not been suppressed
                    List <string> actions = new List <string>();
                    using (View view = database.OpenExecuteView("SELECT `Action` FROM `_ICESequence` ORDER BY `Sequence`"))
                    {
                        while (true)
                        {
                            using (Record record = view.Fetch())
                            {
                                if (null == record)
                                {
                                    break;
                                }

                                string action = record.GetString(1);

                                if ((this.SuppressedICEs == null || !this.SuppressedICEs.Contains(action)) && (this.ICEs == null || this.ICEs.Contains(action)))
                                {
                                    actions.Add(action);
                                }
                            }
                        }
                    }

                    // disable the internal UI handler and set an external UI handler
                    previousUILevel   = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd);
                    previousUIHandler = Installer.SetExternalUI(this.validationUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero);

                    // create a session for running the ICEs
                    this.validationSessionComplete = false;
                    using (Session session = new Session(database))
                    {
                        // add the product code back into the database
                        if (null != productCode)
                        {
                            // some CUBs erroneously have a ProductCode property, so delete it if we just picked one up
                            using (View dropProductCodeView = database.OpenExecuteView("DELETE FROM `Property` WHERE `Property` = 'ProductCode'"))
                            {
                            }

                            using (View view = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "INSERT INTO `Property` (`Property`, `Value`) VALUES ('ProductCode', '{0}')", productCode)))
                            {
                            }
                        }

                        foreach (string action in actions)
                        {
                            this.actionName = action;
                            try
                            {
                                session.DoAction(action);
                            }
                            catch (Win32Exception e)
                            {
                                if (!this.messaging.EncounteredError)
                                {
                                    throw e;
                                }
                                // TODO: Review why this was clearing the error state when an exception had happened but an error was already encountered. That's weird.
                                //else
                                //{
                                //    this.encounteredError = false;
                                //}
                            }
                            this.actionName = null;
                        }

                        // Mark the validation session complete so we ignore any messages that MSI may fire
                        // during session clean-up.
                        this.validationSessionComplete = true;
                    }
                }
            }
            catch (Win32Exception e)
            {
                // avoid displaying errors twice since one may have already occurred in the UI handler
                if (!this.messaging.EncounteredError)
                {
                    if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED
                    {
                        // databaseFile is not passed since during light
                        // this would be the temporary copy and there would be
                        // no final output since the error occured; during smoke
                        // they should know the path passed into smoke
                        this.messaging.Write(ErrorMessages.ValidationFailedToOpenDatabase());
                    }
                    else if (0x64D == e.NativeErrorCode)
                    {
                        this.messaging.Write(ErrorMessages.ValidationFailedDueToLowMsiEngine());
                    }
                    else if (0x654 == e.NativeErrorCode)
                    {
                        this.messaging.Write(ErrorMessages.ValidationFailedDueToInvalidPackage());
                    }
                    else if (0x658 == e.NativeErrorCode)
                    {
                        this.messaging.Write(ErrorMessages.ValidationFailedDueToMultilanguageMergeModule());
                    }
                    else if (0x659 == e.NativeErrorCode)
                    {
                        this.messaging.Write(WarningMessages.ValidationFailedDueToSystemPolicy());
                    }
                    else
                    {
                        string msgTemp = e.Message;

                        if (null != this.actionName)
                        {
                            msgTemp = String.Concat("Action - '", this.actionName, "' ", e.Message);
                        }

                        this.messaging.Write(ErrorMessages.Win32Exception(e.NativeErrorCode, msgTemp));
                    }
                }
            }
            finally
            {
                Installer.SetExternalUI(previousUIHandler, 0, IntPtr.Zero);
                Installer.SetInternalUI(previousUILevel, ref previousHwnd);

                this.validationSessionComplete = false; // no validation session at this point, so reset the completion flag.

                mutex.ReleaseMutex();
                this.cubeFiles.Clear();
                this.extension.FinalizeValidator();
            }
        }
예제 #18
0
 public void Verbose(string message)
 {
     VerboseMessages.Add(message);
 }
예제 #19
0
        public void Execute()
        {
            var wixMergeSymbols = this.Section.Symbols.OfType <WixMergeSymbol>().ToList();

            if (!wixMergeSymbols.Any())
            {
                return;
            }

            IMsmMerge2 merge        = null;
            var        commit       = true;
            var        logOpen      = false;
            var        databaseOpen = false;
            var        logPath      = Path.Combine(this.IntermediateFolder, "merge.log");

            try
            {
                merge = MsmInterop.GetMsmMerge();

                merge.OpenLog(logPath);
                logOpen = true;

                merge.OpenDatabase(this.OutputPath);
                databaseOpen = true;

                var featureModulesByMergeId = this.Section.Symbols.OfType <WixFeatureModulesSymbol>().GroupBy(t => t.WixMergeRef).ToDictionary(g => g.Key);

                // process all the merge rows
                foreach (var wixMergeRow in wixMergeSymbols)
                {
                    var moduleOpen = false;

                    try
                    {
                        short mergeLanguage;

                        try
                        {
                            mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture);
                        }
                        catch (FormatException)
                        {
                            this.Messaging.Write(ErrorMessages.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, wixMergeRow.Language.ToString()));
                            continue;
                        }

                        this.Messaging.Write(VerboseMessages.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage));
                        merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
                        moduleOpen = true;

                        // If there is merge configuration data, create a callback object to contain it all.
                        ConfigurationCallback callback = null;
                        if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData))
                        {
                            callback = new ConfigurationCallback(wixMergeRow.ConfigurationData);
                        }

                        // Merge the module into the database that's being built.
                        this.Messaging.Write(VerboseMessages.MergingMergeModule(wixMergeRow.SourceFile));
                        merge.MergeEx(wixMergeRow.FeatureRef, wixMergeRow.DirectoryRef, callback);

                        // Connect any non-primary features.
                        if (featureModulesByMergeId.TryGetValue(wixMergeRow.Id.Id, out var featureModules))
                        {
                            foreach (var featureModule in featureModules)
                            {
                                this.Messaging.Write(VerboseMessages.ConnectingMergeModule(wixMergeRow.SourceFile, featureModule.FeatureRef));
                                merge.Connect(featureModule.FeatureRef);
                            }
                        }
                    }
                    catch (COMException)
                    {
                        commit = false;
                    }
                    finally
                    {
                        var mergeErrors = merge.Errors;

                        // display all the errors encountered during the merge operations for this module
                        for (var i = 1; i <= mergeErrors.Count; i++)
                        {
                            var mergeError   = mergeErrors[i];
                            var databaseKeys = new StringBuilder();
                            var moduleKeys   = new StringBuilder();

                            // build a string of the database keys
                            for (var j = 1; j <= mergeError.DatabaseKeys.Count; j++)
                            {
                                if (1 != j)
                                {
                                    databaseKeys.Append(';');
                                }
                                databaseKeys.Append(mergeError.DatabaseKeys[j]);
                            }

                            // build a string of the module keys
                            for (var j = 1; j <= mergeError.ModuleKeys.Count; j++)
                            {
                                if (1 != j)
                                {
                                    moduleKeys.Append(';');
                                }
                                moduleKeys.Append(mergeError.ModuleKeys[j]);
                            }

                            // display the merge error based on the msm error type
                            switch (mergeError.Type)
                            {
                            case MsmErrorType.msmErrorExclusion:
                                this.Messaging.Write(ErrorMessages.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, moduleKeys.ToString()));
                                break;

                            case MsmErrorType.msmErrorFeatureRequired:
                                this.Messaging.Write(ErrorMessages.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id.Id));
                                break;

                            case MsmErrorType.msmErrorLanguageFailed:
                                this.Messaging.Write(ErrorMessages.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
                                break;

                            case MsmErrorType.msmErrorLanguageUnsupported:
                                this.Messaging.Write(ErrorMessages.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
                                break;

                            case MsmErrorType.msmErrorResequenceMerge:
                                this.Messaging.Write(WarningMessages.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
                                break;

                            case MsmErrorType.msmErrorTableMerge:
                                if ("_Validation" != mergeError.DatabaseTable)     // ignore merge errors in the _Validation table
                                {
                                    this.Messaging.Write(WarningMessages.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
                                }
                                break;

                            case MsmErrorType.msmErrorPlatformMismatch:
                                this.Messaging.Write(ErrorMessages.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile));
                                break;

                            default:
                                this.Messaging.Write(ErrorMessages.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, "Encountered an unexpected merge error of type '{0}' for which there is currently no error message to display.  More information about the merge and the failure can be found in the merge log: '{1}'", Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace));
                                break;
                            }
                        }

                        if (0 >= mergeErrors.Count && !commit)
                        {
                            this.Messaging.Write(ErrorMessages.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, "Encountered an unexpected error while merging '{0}'. More information about the merge and the failure can be found in the merge log: '{1}'", wixMergeRow.SourceFile, logPath), "InvalidOperationException", Environment.StackTrace));
                        }

                        if (moduleOpen)
                        {
                            merge.CloseModule();
                        }
                    }
                }
            }
            finally
            {
                if (databaseOpen)
                {
                    merge.CloseDatabase(commit);
                }

                if (logOpen)
                {
                    merge.CloseLog();
                }
            }

            // stop processing if an error previously occurred
            if (this.Messaging.EncounteredError)
            {
                return;
            }

            using (var db = new Database(this.OutputPath, OpenDatabase.Direct))
            {
                // Suppress individual actions.
                foreach (var suppressAction in this.Section.Symbols.OfType <WixSuppressActionSymbol>())
                {
                    var tableName = suppressAction.SequenceTable.WindowsInstallerTableName();
                    if (db.TableExists(tableName))
                    {
                        var query = $"SELECT * FROM {tableName} WHERE `Action` = '{suppressAction.Action}'";

                        using (var view = db.OpenExecuteView(query))
                            using (var record = view.Fetch())
                            {
                                if (null != record)
                                {
                                    this.Messaging.Write(WarningMessages.SuppressMergedAction(suppressAction.Action, tableName));
                                    view.Modify(ModifyView.Delete, record);
                                }
                            }
                    }
                }

                // Query for merge module actions in suppressed sequences and drop them.
                foreach (var tableName in this.SuppressedTableNames)
                {
                    if (!db.TableExists(tableName))
                    {
                        continue;
                    }

                    using (var view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName)))
                    {
                        foreach (var resultRecord in view.Records)
                        {
                            this.Messaging.Write(WarningMessages.SuppressMergedAction(resultRecord.GetString(1), tableName));
                        }
                    }

                    // drop suppressed sequences
                    using (var view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName)))
                    {
                    }

                    // delete the validation rows
                    using (var view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?")))
                        using (var record = new Record(1))
                        {
                            record.SetString(1, tableName);
                            view.Execute(record);
                        }
                }

                // now update the Attributes column for the files from the Merge Modules
                this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles());
                using (var view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?"))
                {
                    foreach (var file in this.FileFacades)
                    {
                        if (!file.FromModule)
                        {
                            continue;
                        }

                        using (var record = new Record(1))
                        {
                            record.SetString(1, file.Id);
                            view.Execute(record);
                        }

                        using (var recordUpdate = view.Fetch())
                        {
                            if (null == recordUpdate)
                            {
                                throw new InvalidOperationException("Failed to fetch a File row from the database that was merged in from a module.");
                            }

                            recordUpdate.SetInteger(1, file.Sequence);

                            // Update the file attributes to match the compression specified
                            // on the Merge element or on the Package element.
                            var attributes = 0;

                            // Get the current value if its not null.
                            if (!recordUpdate.IsNull(2))
                            {
                                attributes = recordUpdate.GetInteger(2);
                            }

                            if (file.Compressed)
                            {
                                attributes |= WindowsInstallerConstants.MsidbFileAttributesCompressed;
                                attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
                            }
                            else if (file.Uncompressed)
                            {
                                attributes |= WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
                                attributes &= ~WindowsInstallerConstants.MsidbFileAttributesCompressed;
                            }
                            else // clear all compression bits.
                            {
                                attributes &= ~WindowsInstallerConstants.MsidbFileAttributesCompressed;
                                attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
                            }

                            recordUpdate.SetInteger(2, attributes);

                            view.Modify(ModifyView.Update, recordUpdate);
                        }
                    }
                }

                db.Commit();
            }
        }
예제 #20
0
        /// <summary>
        /// Parse the commandline arguments.
        /// </summary>
        /// <param name="args">Commandline arguments.</param>
        public string[] Parse(string[] args)
        {
            List <string> unprocessed = new List <string>();

            for (int i = 0; i < args.Length; ++i)
            {
                string arg = args[i];
                if (String.IsNullOrEmpty(arg)) // skip blank arguments
                {
                    continue;
                }

                if (1 == arg.Length) // treat '-' and '@' as filenames when by themselves.
                {
                    unprocessed.Add(arg);
                }
                else if ('-' == arg[0] || '/' == arg[0])
                {
                    string parameter = arg.Substring(1);
                    if (parameter.Equals("b", StringComparison.Ordinal))
                    {
                        if (!CommandLineHelper.IsValidArg(args, ++i))
                        {
                            break;
                        }

                        var bindPath = BindPath.Parse(args[i]);

                        this.BindPaths.Add(bindPath);
                    }
                    else if (parameter.StartsWith("cultures:", StringComparison.Ordinal))
                    {
                        string culturesString = arg.Substring(10).ToLower(CultureInfo.InvariantCulture);

                        // When null is used treat it as if cultures wasn't specified.
                        // This is needed for batching over the light task when using MSBuild which doesn't
                        // support empty items
                        if (culturesString.Equals("null", StringComparison.OrdinalIgnoreCase))
                        {
                            this.Cultures = null;
                        }
                        else
                        {
                            this.Cultures = culturesString.Split(';', ',');

                            for (int c = 0; c < this.Cultures.Length; ++c)
                            {
                                // Neutral is different from null. For neutral we still want to do WXL filtering.
                                // Set the culture to the empty string = identifier for the invariant culture
                                if (this.Cultures[c].Equals("neutral", StringComparison.OrdinalIgnoreCase))
                                {
                                    this.Cultures[c] = String.Empty;
                                }
                            }
                        }
                    }
                    else if (parameter.StartsWith("dcl:", StringComparison.Ordinal))
                    {
                        string defaultCompressionLevel = arg.Substring(5);

                        if (String.IsNullOrEmpty(defaultCompressionLevel))
                        {
                            break;
                        }
                        else if (Enum.TryParse(defaultCompressionLevel, true, out CompressionLevel compressionLevel))
                        {
                            this.DefaultCompressionLevel = compressionLevel;
                        }
                    }
                    else if (parameter.StartsWith("d", StringComparison.Ordinal))
                    {
                        parameter = arg.Substring(2);
                        string[] value = parameter.Split("=".ToCharArray(), 2);

                        string preexisting;
                        if (1 == value.Length)
                        {
                            this.Messaging.Write(ErrorMessages.ExpectedWixVariableValue(value[0]));
                        }
                        else if (this.Variables.TryGetValue(value[0], out preexisting))
                        {
                            this.Messaging.Write(ErrorMessages.WixVariableCollision(null, value[0]));
                        }
                        else
                        {
                            this.Variables.Add(value[0], value[1]);
                        }
                    }
                    else if (parameter.Equals("ext", StringComparison.Ordinal))
                    {
                        if (!CommandLineHelper.IsValidArg(args, ++i))
                        {
                            this.Messaging.Write(ErrorMessages.TypeSpecificationForExtensionRequired("-ext"));
                            break;
                        }

                        this.Extensions.Add(args[i]);
                    }
                    else if (parameter.Equals("loc", StringComparison.Ordinal))
                    {
                        string locFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
                        if (String.IsNullOrEmpty(locFile))
                        {
                            break;
                        }

                        this.LocalizationFiles.Add(locFile);
                    }
                    else if (parameter.Equals("nologo", StringComparison.Ordinal))
                    {
                        this.ShowLogo = false;
                    }
                    else if (parameter.Equals("notidy", StringComparison.Ordinal))
                    {
                        this.Tidy = false;
                    }
                    else if ("o" == parameter || "out" == parameter)
                    {
                        this.OutputFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
                        if (String.IsNullOrEmpty(this.OutputFile))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("pedantic", StringComparison.Ordinal))
                    {
                        this.ShowPedanticMessages = true;
                    }
                    else if (parameter.Equals("sloc", StringComparison.Ordinal))
                    {
                        this.SuppressLocalization = true;
                    }
                    else if (parameter.Equals("usf", StringComparison.Ordinal))
                    {
                        this.UnreferencedSymbolsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.UnreferencedSymbolsFile))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("xo", StringComparison.Ordinal))
                    {
                        this.OutputXml = true;
                    }
                    else if (parameter.Equals("cc", StringComparison.Ordinal))
                    {
                        this.CabCachePath = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.CabCachePath))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("ct", StringComparison.Ordinal))
                    {
                        if (!CommandLineHelper.IsValidArg(args, ++i))
                        {
                            this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(String.Empty));
                            break;
                        }

                        int ct = 0;
                        if (!Int32.TryParse(args[i], out ct) || 0 >= ct)
                        {
                            this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(args[i]));
                            break;
                        }

                        this.CabbingThreadCount = ct;
                        this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString()));
                    }
                    else if (parameter.Equals("cub", StringComparison.Ordinal))
                    {
                        string cubeFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(cubeFile))
                        {
                            break;
                        }

                        this.CubeFiles.Add(cubeFile);
                    }
                    else if (parameter.StartsWith("ice:", StringComparison.Ordinal))
                    {
                        this.Ices.Add(parameter.Substring(4));
                    }
                    else if (parameter.Equals("intermediatefolder", StringComparison.OrdinalIgnoreCase))
                    {
                        this.IntermediateFolder = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.IntermediateFolder))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("contentsfile", StringComparison.Ordinal))
                    {
                        this.ContentsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.ContentsFile))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("outputsfile", StringComparison.Ordinal))
                    {
                        this.OutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.OutputsFile))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("builtoutputsfile", StringComparison.Ordinal))
                    {
                        this.BuiltOutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.BuiltOutputsFile))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("wixprojectfile", StringComparison.Ordinal))
                    {
                        this.WixprojectFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.WixprojectFile))
                        {
                            break;
                        }
                    }
                    else if (parameter.Equals("pdbout", StringComparison.Ordinal))
                    {
                        this.PdbFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);

                        if (String.IsNullOrEmpty(this.PdbFile))
                        {
                            break;
                        }
                    }
                    else if (parameter.StartsWith("sice:", StringComparison.Ordinal))
                    {
                        this.SuppressIces.Add(parameter.Substring(5));
                    }
                    else if (parameter.Equals("sl", StringComparison.Ordinal))
                    {
                        this.SuppressLayout = true;
                    }
                    else if (parameter.Equals("spdb", StringComparison.Ordinal))
                    {
                        this.SuppressWixPdb = true;
                    }
                    else if (parameter.Equals("sacl", StringComparison.Ordinal))
                    {
                        this.SuppressAclReset = true;
                    }
                    else if (parameter.Equals("sval", StringComparison.Ordinal))
                    {
                        this.SuppressValidation = true;
                    }
                    else if ("sv" == parameter)
                    {
                        this.SuppressVersionCheck = true;
                    }
                    else if (parameter.StartsWith("sw", StringComparison.Ordinal))
                    {
                        string paramArg = parameter.Substring(2);
                        if (0 == paramArg.Length)
                        {
                            this.Messaging.SuppressAllWarnings = true;
                        }
                        else
                        {
                            int suppressWarning = 0;
                            if (!Int32.TryParse(paramArg, out suppressWarning) || 0 >= suppressWarning)
                            {
                                this.Messaging.Write(ErrorMessages.IllegalSuppressWarningId(paramArg));
                            }
                            else
                            {
                                this.Messaging.SuppressWarningMessage(suppressWarning);
                            }
                        }
                    }
                    else if (parameter.StartsWith("wx", StringComparison.Ordinal))
                    {
                        string paramArg = parameter.Substring(2);
                        if (0 == paramArg.Length)
                        {
                            this.Messaging.WarningsAsError = true;
                        }
                        else
                        {
                            int elevateWarning = 0;
                            if (!Int32.TryParse(paramArg, out elevateWarning) || 0 >= elevateWarning)
                            {
                                this.Messaging.Write(ErrorMessages.IllegalWarningIdAsError(paramArg));
                            }
                            else
                            {
                                this.Messaging.ElevateWarningMessage(elevateWarning);
                            }
                        }
                    }
                    else if ("v" == parameter)
                    {
                        this.Messaging.ShowVerboseMessages = true;
                    }
                    else if ("?" == parameter || "help" == parameter)
                    {
                        this.ShowHelp = true;
                        break;
                    }
                    else
                    {
                        unprocessed.Add(arg);
                    }
                }
                else if ('@' == arg[0])
                {
                    string[] parsedArgs   = CommandLineResponseFile.Parse(arg.Substring(1));
                    string[] unparsedArgs = this.Parse(parsedArgs);
                    unprocessed.AddRange(unparsedArgs);
                }
                else
                {
                    unprocessed.Add(arg);
                }
            }

            return(unprocessed.ToArray());
        }
예제 #21
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="mediaSymbol">Media symbol containing information about the cabinet.</param>
        /// <param name="fileFacades">Collection of files in this cabinet.</param>
        /// <returns>created CabinetWorkItem object</returns>
        private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData output, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable <FileFacade> fileFacades)
        {
            CabinetWorkItem cabinetWorkItem  = null;
            var             tempCabinetFileX = Path.Combine(this.IntermediateFolder, mediaSymbol.Cabinet);

            // check for an empty cabinet
            if (!fileFacades.Any())
            {
                // Remove the leading '#' from the embedded cabinet name to make the warning easier to understand
                var cabinetName = mediaSymbol.Cabinet.TrimStart('#');

                // If building a patch, remind them to run -p for torch.
                if (OutputType.Patch == output.Type)
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaSymbol.SourceLineNumbers, cabinetName, true));
                }
                else
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaSymbol.SourceLineNumbers, cabinetName));
                }
            }

            var cabinetResolver = new CabinetResolver(this.ServiceProvider, this.CabCachePath, this.BackendExtensions);

            var resolvedCabinet = cabinetResolver.ResolveCabinet(tempCabinetFileX, fileFacades);

            // create a cabinet work item if it's not being skipped
            if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption)
            {
                // Default to the threshold for best smartcabbing (makes smallest cabinet).
                cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold: 0, compressionLevel, this.ModularizationSuffix /*, this.FileManager*/);
            }
            else // reuse the cabinet from the cabinet cache.
            {
                this.Messaging.Write(VerboseMessages.ReusingCabCache(mediaSymbol.SourceLineNumbers, mediaSymbol.Cabinet, resolvedCabinet.Path));

                try
                {
                    // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The
                    // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that
                    // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from
                    // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output)
                    // causing the project to look like it perpetually needs a rebuild until all of the reused
                    // cabinets get newer timestamps.
                    File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now);
                }
                catch (Exception e)
                {
                    this.Messaging.Write(WarningMessages.CannotUpdateCabCache(mediaSymbol.SourceLineNumbers, resolvedCabinet.Path, e.Message));
                }
            }

            var trackResolvedCabinet = this.BackendHelper.TrackFile(resolvedCabinet.Path, TrackedFileType.Intermediate, mediaSymbol.SourceLineNumbers);

            this.trackedFiles.Add(trackResolvedCabinet);

            if (mediaSymbol.Cabinet.StartsWith("#", StringComparison.Ordinal))
            {
                var streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]);

                var streamRow = streamsTable.CreateRow(mediaSymbol.SourceLineNumbers);
                streamRow[0] = mediaSymbol.Cabinet.Substring(1);
                streamRow[1] = resolvedCabinet.Path;
            }
            else
            {
                var trackDestination = this.BackendHelper.TrackFile(Path.Combine(cabinetDir, mediaSymbol.Cabinet), TrackedFileType.Final, mediaSymbol.SourceLineNumbers);
                this.trackedFiles.Add(trackDestination);

                var transfer = this.BackendHelper.CreateFileTransfer(resolvedCabinet.Path, trackDestination.Path, resolvedCabinet.BuildOption == CabinetBuildOption.BuildAndMove, mediaSymbol.SourceLineNumbers);
                this.fileTransfers.Add(transfer);
            }

            return(cabinetWorkItem);
        }
예제 #22
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, MediaTuple mediaRow, CompressionLevel compressionLevel, IEnumerable <FileFacade> fileFacades, List <FileTransfer> fileTransfers)
        {
            CabinetWorkItem cabinetWorkItem  = null;
            string          tempCabinetFileX = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet);

            // check for an empty cabinet
            if (!fileFacades.Any())
            {
                string cabinetName = mediaRow.Cabinet;

                // remove the leading '#' from the embedded cabinet name to make the warning easier to understand
                if (cabinetName.StartsWith("#", StringComparison.Ordinal))
                {
                    cabinetName = cabinetName.Substring(1);
                }

                // If building a patch, remind them to run -p for torch.
                if (OutputType.Patch == output.Type)
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true));
                }
                else
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName));
                }
            }

            var cabinetResolver = new CabinetResolver(this.CabCachePath, this.BackendExtensions);

            ResolvedCabinet resolvedCabinet = cabinetResolver.ResolveCabinet(tempCabinetFileX, fileFacades);

            // create a cabinet work item if it's not being skipped
            if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption)
            {
                int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet).

                cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold, compressionLevel /*, this.FileManager*/);
            }
            else // reuse the cabinet from the cabinet cache.
            {
                this.Messaging.Write(VerboseMessages.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, resolvedCabinet.Path));

                try
                {
                    // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The
                    // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that
                    // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from
                    // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output)
                    // causing the project to look like it perpetually needs a rebuild until all of the reused
                    // cabinets get newer timestamps.
                    File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now);
                }
                catch (Exception e)
                {
                    this.Messaging.Write(WarningMessages.CannotUpdateCabCache(mediaRow.SourceLineNumbers, resolvedCabinet.Path, e.Message));
                }
            }

            if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal))
            {
                Table streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]);

                Row streamRow = streamsTable.CreateRow(mediaRow.SourceLineNumbers);
                streamRow[0] = mediaRow.Cabinet.Substring(1);
                streamRow[1] = resolvedCabinet.Path;
            }
            else
            {
                string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet);
                if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out var transfer))
                {
                    transfer.Built = true;
                    fileTransfers.Add(transfer);
                }
            }

            return(cabinetWorkItem);
        }
예제 #23
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"));
        }
예제 #24
0
 protected override void WriteVerbose(string message)
 {
     VerboseMessages.Add(message);
 }
        public void Execute()
        {
            var destinationFiles = new List <string>();

            foreach (var fileTransfer in this.FileTransfers)
            {
                // If the source and destination are identical, then there's nothing to do here
                if (0 == String.Compare(fileTransfer.Source, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase))
                {
                    fileTransfer.Redundant = true;
                    continue;
                }

                var retry = false;
                do
                {
                    try
                    {
                        if (fileTransfer.Move)
                        {
                            this.Messaging.Write(VerboseMessages.MoveFile(fileTransfer.Source, fileTransfer.Destination));
                            this.MoveFile(fileTransfer.Source, fileTransfer.Destination);
                        }
                        else
                        {
                            this.Messaging.Write(VerboseMessages.CopyFile(fileTransfer.Source, fileTransfer.Destination));
                            this.CopyFile(fileTransfer.Source, fileTransfer.Destination);
                        }

                        retry = false;
                        destinationFiles.Add(fileTransfer.Destination);
                    }
                    catch (FileNotFoundException e)
                    {
                        throw new WixException(ErrorMessages.FileNotFound(fileTransfer.SourceLineNumbers, e.FileName));
                    }
                    catch (DirectoryNotFoundException)
                    {
                        // if we already retried, give up
                        if (retry)
                        {
                            throw;
                        }

                        var directory = Path.GetDirectoryName(fileTransfer.Destination);
                        this.Messaging.Write(VerboseMessages.CreateDirectory(directory));
                        Directory.CreateDirectory(directory);
                        retry = true;
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // if we already retried, give up
                        if (retry)
                        {
                            throw;
                        }

                        if (File.Exists(fileTransfer.Destination))
                        {
                            this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination));

                            // try to ensure the file is not read-only
                            var attributes = File.GetAttributes(fileTransfer.Destination);
                            try
                            {
                                File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly);
                            }
                            catch (ArgumentException) // thrown for unauthorized access errors
                            {
                                throw new WixException(ErrorMessages.UnauthorizedAccess(fileTransfer.Destination));
                            }

                            // try to delete the file
                            try
                            {
                                File.Delete(fileTransfer.Destination);
                            }
                            catch (IOException)
                            {
                                throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination));
                            }

                            retry = true;
                        }
                        else // no idea what just happened, bail
                        {
                            throw;
                        }
                    }
                    catch (IOException)
                    {
                        // if we already retried, give up
                        if (retry)
                        {
                            throw;
                        }

                        if (File.Exists(fileTransfer.Destination))
                        {
                            this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination));

                            // ensure the file is not read-only, then delete it
                            var attributes = File.GetAttributes(fileTransfer.Destination);
                            File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly);
                            try
                            {
                                File.Delete(fileTransfer.Destination);
                            }
                            catch (IOException)
                            {
                                throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination));
                            }

                            retry = true;
                        }
                        else // no idea what just happened, bail
                        {
                            throw;
                        }
                    }
                } while (retry);
            }

            // Finally, if directed then reset remove ACLs that may may have been picked up
            // during the file transfer process.
            if (this.ResetAcls && 0 < destinationFiles.Count)
            {
                try
                {
                    FileSystem.ResetAcls(destinationFiles);
                }
                catch (Exception e)
                {
                    this.Messaging.Write(WarningMessages.UnableToResetAcls(e.Message));
                }
            }
        }
예제 #26
0
        public void Execute()
        {
            List <string> destinationFiles = new List <string>();

            foreach (var fileTransfer in this.FileTransfers)
            {
                // If the source and destination are identical, then there's nothing to do here
                if (0 == String.Compare(fileTransfer.Source, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase))
                {
                    fileTransfer.Redundant = true;
                    continue;
                }

                bool retry = false;
                do
                {
                    try
                    {
                        if (fileTransfer.Move)
                        {
                            this.Messaging.Write(VerboseMessages.MoveFile(fileTransfer.Source, fileTransfer.Destination));
                            this.TransferFile(true, fileTransfer.Source, fileTransfer.Destination);
                        }
                        else
                        {
                            this.Messaging.Write(VerboseMessages.CopyFile(fileTransfer.Source, fileTransfer.Destination));
                            this.TransferFile(false, fileTransfer.Source, fileTransfer.Destination);
                        }

                        retry = false;
                        destinationFiles.Add(fileTransfer.Destination);
                    }
                    catch (FileNotFoundException e)
                    {
                        throw new WixFileNotFoundException(fileTransfer.SourceLineNumbers, e.FileName);
                    }
                    catch (DirectoryNotFoundException)
                    {
                        // if we already retried, give up
                        if (retry)
                        {
                            throw;
                        }

                        string directory = Path.GetDirectoryName(fileTransfer.Destination);
                        this.Messaging.Write(VerboseMessages.CreateDirectory(directory));
                        Directory.CreateDirectory(directory);
                        retry = true;
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // if we already retried, give up
                        if (retry)
                        {
                            throw;
                        }

                        if (File.Exists(fileTransfer.Destination))
                        {
                            this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination));

                            // try to ensure the file is not read-only
                            FileAttributes attributes = File.GetAttributes(fileTransfer.Destination);
                            try
                            {
                                File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly);
                            }
                            catch (ArgumentException) // thrown for unauthorized access errors
                            {
                                throw new WixException(ErrorMessages.UnauthorizedAccess(fileTransfer.Destination));
                            }

                            // try to delete the file
                            try
                            {
                                File.Delete(fileTransfer.Destination);
                            }
                            catch (IOException)
                            {
                                throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination));
                            }

                            retry = true;
                        }
                        else // no idea what just happened, bail
                        {
                            throw;
                        }
                    }
                    catch (IOException)
                    {
                        // if we already retried, give up
                        if (retry)
                        {
                            throw;
                        }

                        if (File.Exists(fileTransfer.Destination))
                        {
                            this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination));

                            // ensure the file is not read-only, then delete it
                            FileAttributes attributes = File.GetAttributes(fileTransfer.Destination);
                            File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly);
                            try
                            {
                                File.Delete(fileTransfer.Destination);
                            }
                            catch (IOException)
                            {
                                throw new WixException(ErrorMessages.FileInUse(null, fileTransfer.Destination));
                            }

                            retry = true;
                        }
                        else // no idea what just happened, bail
                        {
                            throw;
                        }
                    }
                } while (retry);
            }

            // Finally, if there were any files remove the ACL that may have been added to
            // during the file transfer process.
            if (0 < destinationFiles.Count && !this.SuppressAclReset)
            {
                var aclReset = new FileSecurity();
                aclReset.SetAccessRuleProtection(false, false);

                try
                {
                    //WixToolset.Core.Native.NativeMethods.ResetAcls(destinationFiles.ToArray(), (uint)destinationFiles.Count);

                    foreach (var file in destinationFiles)
                    {
                        new FileInfo(file).SetAccessControl(aclReset);
                    }
                }
                catch
                {
                    this.Messaging.Write(WarningMessages.UnableToResetAcls());
                }
            }
        }
예제 #27
0
        public void Execute()
        {
            Table wixMergeTable          = this.Output.Tables["WixMerge"];
            Table wixFeatureModulesTable = this.Output.Tables["WixFeatureModules"];

            // check for merge rows to see if there is any work to do
            if (null == wixMergeTable || 0 == wixMergeTable.Rows.Count)
            {
                return;
            }

            IMsmMerge2 merge        = null;
            bool       commit       = true;
            bool       logOpen      = false;
            bool       databaseOpen = false;
            string     logPath      = null;

            try
            {
                merge = MsmInterop.GetMsmMerge();

                logPath = Path.Combine(this.IntermediateFolder, "merge.log");
                merge.OpenLog(logPath);
                logOpen = true;

                merge.OpenDatabase(this.OutputPath);
                databaseOpen = true;

                // process all the merge rows
                foreach (WixMergeRow wixMergeRow in wixMergeTable.Rows)
                {
                    bool moduleOpen = false;

                    try
                    {
                        short mergeLanguage;

                        try
                        {
                            mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture);
                        }
                        catch (FormatException)
                        {
                            this.Messaging.Write(ErrorMessages.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language));
                            continue;
                        }

                        this.Messaging.Write(VerboseMessages.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage));
                        merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
                        moduleOpen = true;

                        // If there is merge configuration data, create a callback object to contain it all.
                        ConfigurationCallback callback = null;
                        if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData))
                        {
                            callback = new ConfigurationCallback(wixMergeRow.ConfigurationData);
                        }

                        // merge the module into the database that's being built
                        this.Messaging.Write(VerboseMessages.MergingMergeModule(wixMergeRow.SourceFile));
                        merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback);

                        // connect any non-primary features
                        if (null != wixFeatureModulesTable)
                        {
                            foreach (Row row in wixFeatureModulesTable.Rows)
                            {
                                if (wixMergeRow.Id == (string)row[1])
                                {
                                    this.Messaging.Write(VerboseMessages.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0]));
                                    merge.Connect((string)row[0]);
                                }
                            }
                        }
                    }
                    catch (COMException)
                    {
                        commit = false;
                    }
                    finally
                    {
                        IMsmErrors mergeErrors = merge.Errors;

                        // display all the errors encountered during the merge operations for this module
                        for (int i = 1; i <= mergeErrors.Count; i++)
                        {
                            IMsmError     mergeError   = mergeErrors[i];
                            StringBuilder databaseKeys = new StringBuilder();
                            StringBuilder moduleKeys   = new StringBuilder();

                            // build a string of the database keys
                            for (int j = 1; j <= mergeError.DatabaseKeys.Count; j++)
                            {
                                if (1 != j)
                                {
                                    databaseKeys.Append(';');
                                }
                                databaseKeys.Append(mergeError.DatabaseKeys[j]);
                            }

                            // build a string of the module keys
                            for (int j = 1; j <= mergeError.ModuleKeys.Count; j++)
                            {
                                if (1 != j)
                                {
                                    moduleKeys.Append(';');
                                }
                                moduleKeys.Append(mergeError.ModuleKeys[j]);
                            }

                            // display the merge error based on the msm error type
                            switch (mergeError.Type)
                            {
                            case MsmErrorType.msmErrorExclusion:
                                this.Messaging.Write(ErrorMessages.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleKeys.ToString()));
                                break;

                            case MsmErrorType.msmErrorFeatureRequired:
                                this.Messaging.Write(ErrorMessages.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id));
                                break;

                            case MsmErrorType.msmErrorLanguageFailed:
                                this.Messaging.Write(ErrorMessages.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
                                break;

                            case MsmErrorType.msmErrorLanguageUnsupported:
                                this.Messaging.Write(ErrorMessages.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
                                break;

                            case MsmErrorType.msmErrorResequenceMerge:
                                this.Messaging.Write(WarningMessages.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
                                break;

                            case MsmErrorType.msmErrorTableMerge:
                                if ("_Validation" != mergeError.DatabaseTable)     // ignore merge errors in the _Validation table
                                {
                                    this.Messaging.Write(WarningMessages.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
                                }
                                break;

                            case MsmErrorType.msmErrorPlatformMismatch:
                                this.Messaging.Write(ErrorMessages.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile));
                                break;

                            default:
                                this.Messaging.Write(ErrorMessages.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorWithType, Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace));
                                break;
                            }
                        }

                        if (0 >= mergeErrors.Count && !commit)
                        {
                            this.Messaging.Write(ErrorMessages.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorInSourceFile, wixMergeRow.SourceFile, logPath), "InvalidOperationException", Environment.StackTrace));
                        }

                        if (moduleOpen)
                        {
                            merge.CloseModule();
                        }
                    }
                }
            }
            finally
            {
                if (databaseOpen)
                {
                    merge.CloseDatabase(commit);
                }

                if (logOpen)
                {
                    merge.CloseLog();
                }
            }

            // stop processing if an error previously occurred
            if (this.Messaging.EncounteredError)
            {
                return;
            }

            using (Database db = new Database(this.OutputPath, OpenDatabase.Direct))
            {
                Table suppressActionTable = this.Output.Tables["WixSuppressAction"];

                // suppress individual actions
                if (null != suppressActionTable)
                {
                    foreach (Row row in suppressActionTable.Rows)
                    {
                        if (db.TableExists((string)row[0]))
                        {
                            string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]);

                            using (View view = db.OpenExecuteView(query))
                            {
                                using (Record record = view.Fetch())
                                {
                                    if (null != record)
                                    {
                                        this.Messaging.Write(WarningMessages.SuppressMergedAction((string)row[1], row[0].ToString()));
                                        view.Modify(ModifyView.Delete, record);
                                    }
                                }
                            }
                        }
                    }
                }

                // query for merge module actions in suppressed sequences and drop them
                foreach (string tableName in this.SuppressedTableNames)
                {
                    if (!db.TableExists(tableName))
                    {
                        continue;
                    }

                    using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName)))
                    {
                        while (true)
                        {
                            using (Record resultRecord = view.Fetch())
                            {
                                if (null == resultRecord)
                                {
                                    break;
                                }

                                this.Messaging.Write(WarningMessages.SuppressMergedAction(resultRecord.GetString(1), tableName));
                            }
                        }
                    }

                    // drop suppressed sequences
                    using (View view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName)))
                    {
                    }

                    // delete the validation rows
                    using (View view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?")))
                    {
                        using (Record record = new Record(1))
                        {
                            record.SetString(1, tableName);
                            view.Execute(record);
                        }
                    }
                }

                // now update the Attributes column for the files from the Merge Modules
                this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles());
                using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?"))
                {
                    foreach (var file in this.FileFacades)
                    {
                        if (!file.FromModule)
                        {
                            continue;
                        }

                        using (Record record = new Record(1))
                        {
                            record.SetString(1, file.File.File);
                            view.Execute(record);
                        }

                        using (Record recordUpdate = view.Fetch())
                        {
                            if (null == recordUpdate)
                            {
                                throw new InvalidOperationException("Failed to fetch a File row from the database that was merged in from a module.");
                            }

                            //recordUpdate.SetInteger(1, file.File.Sequence);
                            throw new NotImplementedException();

                            // Update the file attributes to match the compression specified
                            // on the Merge element or on the Package element.
                            var attributes = 0;

                            // Get the current value if its not null.
                            if (!recordUpdate.IsNull(2))
                            {
                                attributes = recordUpdate.GetInteger(2);
                            }

                            if (!file.File.Compressed.HasValue)
                            {
                                // Clear all compression bits.
                                attributes &= ~MsiInterop.MsidbFileAttributesCompressed;
                                attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
                            }
                            else if (file.File.Compressed.Value)
                            {
                                attributes |= MsiInterop.MsidbFileAttributesCompressed;
                                attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
                            }
                            else if (!file.File.Compressed.Value)
                            {
                                attributes |= MsiInterop.MsidbFileAttributesNoncompressed;
                                attributes &= ~MsiInterop.MsidbFileAttributesCompressed;
                            }

                            recordUpdate.SetInteger(2, attributes);

                            view.Modify(ModifyView.Update, recordUpdate);
                        }
                    }
                }

                db.Commit();
            }
        }
예제 #28
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
                    this.Messaging.Write(VerboseMessages.CabinetsSplitInParallel());
                    mutex.WaitOne(); // Wait on other thread
                }

                string firstCabinetName = firstCabName + ".cab";
                string newCabinetName   = newCabName;
                bool   transferAdded    = false; // Used for Error Handling

                // Create File Transfer for new Cabinet using transfer of Base Cabinet
                foreach (FileTransfer transfer in this.FileTransfers)
                {
                    if (firstCabinetName.Equals(Path.GetFileName(transfer.Source), StringComparison.InvariantCultureIgnoreCase))
                    {
                        string newCabSourcePath = Path.Combine(Path.GetDirectoryName(transfer.Source), newCabinetName);
                        string newCabTargetPath = Path.Combine(Path.GetDirectoryName(transfer.Destination), newCabinetName);

                        FileTransfer newTransfer;
                        if (FileTransfer.TryCreate(newCabSourcePath, newCabTargetPath, transfer.Move, "Cabinet", transfer.SourceLineNumbers, out newTransfer))
                        {
                            newTransfer.Built = true;
                            this.fileTransfers.Add(newTransfer);
                            transferAdded = true;
                            break;
                        }
                    }
                }

                // Check if File Transfer was added
                if (!transferAdded)
                {
                    throw new WixException(ErrorMessages.SplitCabinetCopyRegistrationFailed(newCabinetName, firstCabinetName));
                }

                // Add the new Cabinets to media table using LastSequence of Base Cabinet
                Table mediaTable   = this.Output.Tables["Media"];
                Table wixFileTable = this.Output.Tables["WixFile"];
                int   diskIDForLastSplitCabAdded       = 0;     // The DiskID value for the first cab in this cabinet split chain
                int   lastSequenceForLastSplitCabAdded = 0;     // The LastSequence value for the first cab in this cabinet split chain
                bool  lastSplitCabinetFound            = false; // Used for Error Handling

                string lastCabinetOfThisSequence = String.Empty;
                // Get the Value of Last Cabinet Added in this split Sequence from Dictionary
                if (!this.lastCabinetAddedToMediaTable.TryGetValue(firstCabinetName, out lastCabinetOfThisSequence))
                {
                    // If there is no value for this sequence, then use first Cabinet is the last one of this split sequence
                    lastCabinetOfThisSequence = firstCabinetName;
                }

                foreach (MediaRow mediaRow in mediaTable.Rows)
                {
                    // Get details for the Last Cabinet Added in this Split Sequence
                    if ((lastSequenceForLastSplitCabAdded == 0) && lastCabinetOfThisSequence.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase))
                    {
                        lastSequenceForLastSplitCabAdded = mediaRow.LastSequence;
                        diskIDForLastSplitCabAdded       = mediaRow.DiskId;
                        lastSplitCabinetFound            = true;
                    }

                    // Check for Name Collision for the new Cabinet added
                    if (newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase))
                    {
                        // Name Collision of generated Split Cabinet Name and user Specified Cab name for current row
                        throw new WixException(ErrorMessages.SplitCabinetNameCollision(newCabinetName, firstCabinetName));
                    }
                }

                // Check if the last Split Cabinet was found in the Media Table
                if (!lastSplitCabinetFound)
                {
                    throw new WixException(ErrorMessages.SplitCabinetInsertionFailed(newCabinetName, firstCabinetName, lastCabinetOfThisSequence));
                }

                // The new Row has to be inserted just after the last cab in this cabinet split chain according to DiskID Sort
                // This is because the FDI Extract requires DiskID of Split Cabinets to be continuous. It Fails otherwise with
                // Error 2350 (FDI Server Error) as next DiskID did not have the right split cabinet during extraction
                MediaRow newMediaRow = (MediaRow)mediaTable.CreateRow(null);
                newMediaRow.Cabinet      = newCabinetName;
                newMediaRow.DiskId       = diskIDForLastSplitCabAdded + 1; // When Sorted with DiskID, this new Cabinet Row is an Insertion
                newMediaRow.LastSequence = lastSequenceForLastSplitCabAdded;

                // Now increment the DiskID for all rows that come after the newly inserted row to Ensure that DiskId is unique
                foreach (MediaRow mediaRow in mediaTable.Rows)
                {
                    // Check if this row comes after inserted row and it is not the new cabinet inserted row
                    if (mediaRow.DiskId >= newMediaRow.DiskId && !newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase))
                    {
                        mediaRow.DiskId++; // Increment DiskID
                    }
                }

                // Now Increment DiskID for All files Rows so that they refer to the right Media Row
                foreach (WixFileRow wixFileRow in wixFileTable.Rows)
                {
                    // Check if this row comes after inserted row and if this row is not the file that has to go into the current cabinet
                    // This check will work as we have only one large file in every splitting cabinet
                    // If we want to support splitting cabinet with more large files we need to update this code
                    if (wixFileRow.DiskId >= newMediaRow.DiskId && !wixFileRow.File.Equals(fileToken, StringComparison.InvariantCultureIgnoreCase))
                    {
                        wixFileRow.DiskId++; // Increment DiskID
                    }
                }

                // Update the Last Cabinet Added in the Split Sequence in Dictionary for future callback
                this.lastCabinetAddedToMediaTable[firstCabinetName] = newCabinetName;

                mediaTable.ValidateRows(); // Valdiates DiskDIs, throws Exception as Wix Error if validation fails
            }
            finally
            {
                // Releasing the Mutex here
                mutex.ReleaseMutex();
            }
        }
예제 #29
0
 public void Verbose(LogType logType, string message, params object[] items)
 {
     VerboseMessages.Enqueue(message);
     _logger.Verbose(message, items);
 }
 public void Verbose(string message, params object[] items)
 {
     VerboseMessages.Add(message);
     _logger.Verbose(message, items);
 }