/// <summary>
        /// Checks whether a transform is valid for this Database, according to its validation data and flags.
        /// </summary>
        /// <param name="transformFile">Path to the transform file</param>
        /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns>
        /// <exception cref="InstallerException">the transform could not be applied</exception>
        /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
        public bool IsTransformValid(string transformFile)
        {
            if (String.IsNullOrEmpty(transformFile))
            {
                throw new ArgumentNullException("transformFile");
            }

            using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false))
            {
                return(this.IsTransformValid(transformSummInfo));
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Closes the database handle.  After closing a handle, further method calls may throw <see cref="InvalidHandleException"/>.
        /// </summary>
        /// <param name="disposing">If true, the method has been called directly or
        /// indirectly by a user's code, so managed and unmanaged resources will be
        /// disposed. If false, only unmanaged resources will be disposed.</param>
        protected override void Dispose(bool disposing)
        {
            if (!this.IsClosed &&
                (this.OpenMode == DatabaseOpenMode.CreateDirect ||
                 this.OpenMode == DatabaseOpenMode.Direct))
            {
                // Always commit a direct-opened database before closing.
                // This avoids unexpected corruption of the database.
                this.Commit();
            }

            base.Dispose(disposing);

            if (disposing)
            {
                if (this.summaryInfo != null)
                {
                    this.summaryInfo.Close();
                    this.summaryInfo = null;
                }

                if (this.deleteOnClose != null)
                {
                    foreach (string path in this.deleteOnClose)
                    {
                        try
                        {
                            if (Directory.Exists(path))
                            {
                                Directory.Delete(path, true);
                            }
                            else
                            {
                                if (File.Exists(path))
                                {
                                    File.Delete(path);
                                }
                            }
                        }
                        catch (IOException)
                        {
                        }
                        catch (UnauthorizedAccessException)
                        {
                        }
                    }
                    this.deleteOnClose = null;
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Finalizes the persistent form of the database. All persistent data is written
        /// to the writeable database, and no temporary columns or rows are written.
        /// </summary>
        /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
        /// <remarks><p>
        /// For a database open in <see cref="DatabaseOpenMode.ReadOnly"/> mode, this method has no effect.
        /// </p><p>
        /// For a database open in <see cref="DatabaseOpenMode.CreateDirect" /> or <see cref="DatabaseOpenMode.Direct" />
        /// mode, it is not necessary to call this method because the database will be automatically committed
        /// when it is closed. However this method may be called at any time to persist the current state of tables
        /// loaded into memory.
        /// </p><p>
        /// For a database open in <see cref="DatabaseOpenMode.Create" /> or <see cref="DatabaseOpenMode.Transact" />
        /// mode, no changes will be persisted until this method is called. If the database object is closed without
        /// calling this method, the database file remains unmodified.
        /// </p><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabasecommit.asp">MsiDatabaseCommit</a>
        /// </p></remarks>
        public void Commit()
        {
            if (this.summaryInfo != null && !this.summaryInfo.IsClosed)
            {
                this.summaryInfo.Persist();
                this.summaryInfo.Close();
                this.summaryInfo = null;
            }
            uint ret = NativeMethods.MsiDatabaseCommit((int)this.Handle);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
        /// <summary>
        /// Apply a transform to the database, suppressing any error conditions
        /// specified by the transform's summary information.
        /// </summary>
        /// <param name="transformFile">Path to the transform file</param>
        /// <exception cref="InstallerException">the transform could not be applied</exception>
        /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabaseapplytransform.asp">MsiDatabaseApplyTransform</a>
        /// </p></remarks>
        public void ApplyTransform(string transformFile)
        {
            if (String.IsNullOrEmpty(transformFile))
            {
                throw new ArgumentNullException("transformFile");
            }

            TransformErrors errorConditionsToSuppress;

            using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false))
            {
                int errorConditions = transformSummInfo.CharacterCount & 0xFFFF;
                errorConditionsToSuppress = (TransformErrors)errorConditions;
            }
            this.ApplyTransform(transformFile, errorConditionsToSuppress);
        }
        /// <summary>
        /// Processes the Msp packages to add properties and payloads from the Msp packages.
        /// </summary>
        public void Execute()
        {
            var packagePayload = this.AuthoredPayloads[this.Facade.PackageSymbol.PayloadRef];

            var mspPackage = (WixBundleMspPackageSymbol)this.Facade.SpecificPackageSymbol;

            var sourcePath = packagePayload.SourceFile.Path;

            try
            {
                // Read data out of the msp database...
                using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
                {
                    mspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38);
                }

                using (var db = new Dtf.Database(sourcePath))
                {
                    if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName))
                    {
                        this.Facade.PackageSymbol.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName");
                    }

                    if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description))
                    {
                        this.Facade.PackageSymbol.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description");
                    }

                    mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName");
                }

                this.ProcessPatchXml(packagePayload, mspPackage, sourcePath);
            }
            catch (Dtf.InstallerException e)
            {
                this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
                return;
            }

            if (String.IsNullOrEmpty(this.Facade.PackageSymbol.CacheId))
            {
                this.Facade.PackageSymbol.CacheId = mspPackage.PatchCode;
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Processes the Msp packages to add properties and payloads from the Msp packages.
        /// </summary>
        public void Execute()
        {
            WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);

            string sourcePath = packagePayload.FullFileName;

            try
            {
                // Read data out of the msp database...
                using (Dtf.SummaryInfo sumInfo = new Dtf.SummaryInfo(sourcePath, false))
                {
                    this.Facade.MspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38);
                }

                using (Dtf.Database db = new Dtf.Database(sourcePath))
                {
                    if (String.IsNullOrEmpty(this.Facade.Package.DisplayName))
                    {
                        this.Facade.Package.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName");
                    }

                    if (String.IsNullOrEmpty(this.Facade.Package.Description))
                    {
                        this.Facade.Package.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description");
                    }

                    this.Facade.MspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName");
                }

                this.ProcessPatchXml(packagePayload, sourcePath);
            }
            catch (Dtf.InstallerException e)
            {
                Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
                return;
            }

            if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
            {
                this.Facade.Package.CacheId = this.Facade.MspPackage.PatchCode;
            }
        }
        /// <summary>
        /// Processes the MSI packages to add properties and payloads from the MSI packages.
        /// </summary>
        public void Execute()
        {
            WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);

            string sourcePath       = packagePayload.FullFileName;
            bool   longNamesInImage = false;
            bool   compressed       = false;
            bool   x64 = false;

            try
            {
                // Read data out of the msi database...
                using (Dtf.SummaryInfo sumInfo = new Dtf.SummaryInfo(sourcePath, false))
                {
                    // 1 is the Word Count summary information stream bit that means
                    // the MSI uses short file names when set. We care about long file
                    // names so check when the bit is not set.
                    longNamesInImage = 0 == (sumInfo.WordCount & 1);

                    // 2 is the Word Count summary information stream bit that means
                    // files are compressed in the MSI by default when the bit is set.
                    compressed = 2 == (sumInfo.WordCount & 2);

                    x64 = (sumInfo.Template.Contains("x64") || sumInfo.Template.Contains("Intel64"));

                    // 8 is the Word Count summary information stream bit that means
                    // "Elevated privileges are not required to install this package."
                    // in MSI 4.5 and below, if this bit is 0, elevation is required.
                    this.Facade.Package.PerMachine = (0 == (sumInfo.WordCount & 8)) ? YesNoDefaultType.Yes : YesNoDefaultType.No;
                    this.Facade.Package.x64        = x64 ? YesNoType.Yes : YesNoType.No;
                }

                using (Dtf.Database db = new Dtf.Database(sourcePath))
                {
                    this.Facade.MsiPackage.ProductCode     = ProcessMsiPackageCommand.GetProperty(db, "ProductCode");
                    this.Facade.MsiPackage.UpgradeCode     = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode");
                    this.Facade.MsiPackage.Manufacturer    = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer");
                    this.Facade.MsiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture);
                    this.Facade.MsiPackage.ProductVersion  = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion");

                    if (!Common.IsValidModuleOrBundleVersion(this.Facade.MsiPackage.ProductVersion))
                    {
                        // not a proper .NET version (e.g., five fields); can we get a valid four-part version number?
                        string   version      = null;
                        string[] versionParts = this.Facade.MsiPackage.ProductVersion.Split('.');
                        int      count        = versionParts.Length;
                        if (0 < count)
                        {
                            version = versionParts[0];
                            for (int i = 1; i < 4 && i < count; ++i)
                            {
                                version = String.Concat(version, ".", versionParts[i]);
                            }
                        }

                        if (!String.IsNullOrEmpty(version) && Common.IsValidModuleOrBundleVersion(version))
                        {
                            Messaging.Instance.OnMessage(WixWarnings.VersionTruncated(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath, version));
                            this.Facade.MsiPackage.ProductVersion = version;
                        }
                        else
                        {
                            Messaging.Instance.OnMessage(WixErrors.InvalidProductVersion(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath));
                        }
                    }

                    if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
                    {
                        this.Facade.Package.CacheId = String.Format("{0}v{1}", this.Facade.MsiPackage.ProductCode, this.Facade.MsiPackage.ProductVersion);
                    }

                    if (String.IsNullOrEmpty(this.Facade.Package.DisplayName))
                    {
                        this.Facade.Package.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName");
                    }

                    if (String.IsNullOrEmpty(this.Facade.Package.Description))
                    {
                        this.Facade.Package.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS");
                    }

                    ISet <string> payloadNames = this.GetPayloadTargetNames();

                    ISet <string> msiPropertyNames = this.GetMsiPropertyNames();

                    this.SetPerMachineAppropriately(db, sourcePath);

                    // Ensure the MSI package is appropriately marked visible or not.
                    this.SetPackageVisibility(db, msiPropertyNames);

                    // Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance.
                    if (!msiPropertyNames.Contains("MSIFASTINSTALL") && !ProcessMsiPackageCommand.HasProperty(db, "MSIFASTINSTALL"))
                    {
                        this.AddMsiProperty("MSIFASTINSTALL", "7");
                    }

                    this.CreateRelatedPackages(db);

                    // If feature selection is enabled, represent the Feature table in the manifest.
                    if (this.Facade.MsiPackage.EnableFeatureSelection)
                    {
                        this.CreateMsiFeatures(db);
                    }

                    // Add all external cabinets as package payloads.
                    this.ImportExternalCabinetAsPayloads(db, packagePayload, payloadNames);

                    // Add all external files as package payloads and calculate the total install size as the rollup of
                    // File table's sizes.
                    this.Facade.Package.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames);

                    // Add all dependency providers from the MSI.
                    this.ImportDependencyProviders(db);
                }
            }
            catch (Dtf.InstallerException e)
            {
                Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(this.Facade.Package.SourceLineNumbers, sourcePath, e.Message));
            }
        }
        /// <summary>
        /// Gets the value of a summary information stream property
        /// </summary>
        /// <param name="msi">The MSI to get the property from</param>
        /// <param name="propertyIndex">The summary information stream property Id of the property to get</param>
        /// <returns>Summary information stream property</returns>
        /// <remarks>
        /// This method reflects on wix.dll to use some of its internal methods for getting Summary Information data
        /// </remarks>
        public static string GetSummaryInformationProperty(string msi, int propertyIndex)
        {
            using (DTF.SummaryInfo summaryInfo = new DTF.SummaryInfo(msi, false))
            {
                switch (propertyIndex)
                {
                case 1:
                    return(summaryInfo.CodePage.ToString());

                case 2:
                    return(summaryInfo.Title);

                case 3:
                    return(summaryInfo.Subject);

                case 4:
                    return(summaryInfo.Author);

                case 5:
                    return(summaryInfo.Keywords);

                case 6:
                    return(summaryInfo.Comments);

                case 7:
                    return(summaryInfo.Template);

                case 8:
                    return(summaryInfo.LastSavedBy);

                case 9:
                    return(summaryInfo.RevisionNumber);

                case 11:
                    return(summaryInfo.LastPrintTime.ToString());

                case 12:
                    return(summaryInfo.CreateTime.ToString());

                case 13:
                    return(summaryInfo.LastSaveTime.ToString());

                case 14:
                    return(summaryInfo.PageCount.ToString());

                case 15:
                    return(summaryInfo.WordCount.ToString());

                case 16:
                    return(summaryInfo.CharacterCount.ToString());

                case 18:
                    return(summaryInfo.CreatingApp);

                case 19:
                    return(summaryInfo.Security.ToString());

                default:
                    throw new NotImplementedException(String.Format("Unknown summary information property: {0}", propertyIndex));
                }
            }
        }
        /// <summary>
        /// Checks whether a transform is valid for this Database, according to its SummaryInfo data.
        /// </summary>
        /// <param name="transformSummaryInfo">SummaryInfo data of a transform file</param>
        /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns>
        /// <exception cref="InstallerException">error processing summary info</exception>
        /// <exception cref="InvalidHandleException">the Database or SummaryInfo handle is invalid</exception>
        public bool IsTransformValid(SummaryInfo transformSummaryInfo)
        {
            if (transformSummaryInfo == null)
            {
                throw new ArgumentNullException("transformSummaryInfo");
            }

            string[] rev = transformSummaryInfo.RevisionNumber.Split(new char[] { ';' }, 3);
            string   targetProductCode    = rev[0].Substring(0, 38);
            string   targetProductVersion = rev[0].Substring(38);
            string   upgradeCode          = rev[2];

            string[] templ = transformSummaryInfo.Template.Split(new char[] { ';' }, 2);
            int      targetProductLanguage = 0;

            if (templ.Length >= 2 && templ[1].Length > 0)
            {
                targetProductLanguage = Int32.Parse(templ[1], CultureInfo.InvariantCulture.NumberFormat);
            }

            int flags         = transformSummaryInfo.CharacterCount;
            int validateFlags = flags >> 16;

            string thisProductCode     = this.ExecutePropertyQuery("ProductCode");
            string thisProductVersion  = this.ExecutePropertyQuery("ProductVersion");
            string thisUpgradeCode     = this.ExecutePropertyQuery("UpgradeCode");
            string thisProductLang     = this.ExecutePropertyQuery("ProductLanguage");
            int    thisProductLanguage = 0;

            if (!String.IsNullOrEmpty(thisProductLang))
            {
                thisProductLanguage = Int32.Parse(thisProductLang, CultureInfo.InvariantCulture.NumberFormat);
            }

            if ((validateFlags & (int)TransformValidations.Product) != 0 &&
                thisProductCode != targetProductCode)
            {
                return(false);
            }

            if ((validateFlags & (int)TransformValidations.UpgradeCode) != 0 &&
                thisUpgradeCode != upgradeCode)
            {
                return(false);
            }

            if ((validateFlags & (int)TransformValidations.Language) != 0 &&
                targetProductLanguage != 0 && thisProductLanguage != targetProductLanguage)
            {
                return(false);
            }

            Version thisProductVer   = new Version(thisProductVersion);
            Version targetProductVer = new Version(targetProductVersion);

            if ((validateFlags & (int)TransformValidations.UpdateVersion) != 0)
            {
                if (thisProductVer.Major != targetProductVer.Major)
                {
                    return(false);
                }
                if (thisProductVer.Minor != targetProductVer.Minor)
                {
                    return(false);
                }
                if (thisProductVer.Build != targetProductVer.Build)
                {
                    return(false);
                }
            }
            else if ((validateFlags & (int)TransformValidations.MinorVersion) != 0)
            {
                if (thisProductVer.Major != targetProductVer.Major)
                {
                    return(false);
                }
                if (thisProductVer.Minor != targetProductVer.Minor)
                {
                    return(false);
                }
            }
            else if ((validateFlags & (int)TransformValidations.MajorVersion) != 0)
            {
                if (thisProductVer.Major != targetProductVer.Major)
                {
                    return(false);
                }
            }

            return(true);
        }
Esempio n. 10
0
 /// <summary>
 /// Gets a SummaryInfo object that can be used to examine, update, and add
 /// properties to the summary information stream of a package or transform.
 /// </summary>
 /// <param name="packagePath">Path to the package (database) or transform</param>
 /// <param name="enableWrite">True to reserve resources for writing summary information properties.</param>
 /// <exception cref="FileNotFoundException">the package does not exist or could not be read</exception>
 /// <exception cref="InstallerException">the package is an invalid format</exception>
 /// <remarks><p>
 /// The SummaryInfo object should be <see cref="InstallerHandle.Close"/>d after use.
 /// It is best that the handle be closed manually as soon as it is no longer
 /// needed, as leaving lots of unused handles open can degrade performance.
 /// </p><p>
 /// Win32 MSI API:
 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msigetsummaryinformation.asp">MsiGetSummaryInformation</a>
 /// </p></remarks>
 public SummaryInfo(string packagePath, bool enableWrite)
     : base((IntPtr)SummaryInfo.OpenSummaryInfo(packagePath, enableWrite), true)
 {
 }