Exemple #1
0
        /// <summary>
        /// Initializes package state from the MSP contents.
        /// </summary>
        private void ResolveMspPackage(Output bundle)
        {
            string sourcePath = this.PackagePayload.FullFileName;

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

                using (Microsoft.Deployment.WindowsInstaller.Database db = new Microsoft.Deployment.WindowsInstaller.Database(sourcePath))
                {
                    if (String.IsNullOrEmpty(this.DisplayName))
                    {
                        this.DisplayName = ChainPackageInfo.GetPatchMetadataProperty(db, "DisplayName");
                    }

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

                    this.Manufacturer = ChainPackageInfo.GetPatchMetadataProperty(db, "ManufacturerName");
                }

                this.ProcessPatchXml(sourcePath, bundle);
            }
            catch (Microsoft.Deployment.WindowsInstaller.InstallerException e)
            {
                this.core.OnMessage(WixErrors.UnableToReadPackageInformation(this.PackagePayload.SourceLineNumbers, sourcePath, e.Message));
                return;
            }

            if (String.IsNullOrEmpty(this.CacheId))
            {
                this.CacheId = this.PatchCode;
            }
        }
Exemple #2
0
        /// <summary>
        /// Initializes package state from the MSI contents.
        /// </summary>
        private void ResolveMsiPackage(BinderFileManager fileManager, Dictionary<string, PayloadInfoRow> allPayloads, Dictionary<string, ContainerInfo> containers, YesNoType suppressLooseFilePayloadGeneration, YesNoType enableFeatureSelection, YesNoType forcePerMachine, Output bundle)
        {
            string sourcePath = this.PackagePayload.FullFileName;
            bool longNamesInImage = false;
            bool compressed = false;
            try
            {
                // Read data out of the msi database...
                using (Microsoft.Deployment.WindowsInstaller.SummaryInfo sumInfo = new Microsoft.Deployment.WindowsInstaller.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);

                    // 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.PerMachine = (0 == (sumInfo.WordCount & 8)) ? YesNoDefaultType.Yes : YesNoDefaultType.No;
                }

                using (Microsoft.Deployment.WindowsInstaller.Database db = new Microsoft.Deployment.WindowsInstaller.Database(sourcePath))
                {
                    this.ProductCode = ChainPackageInfo.GetProperty(db, "ProductCode");
                    this.Language = ChainPackageInfo.GetProperty(db, "ProductLanguage");
                    this.Version = ChainPackageInfo.GetProperty(db, "ProductVersion");

                    if (!Common.IsValidModuleOrBundleVersion(this.Version))
                    {
                        // not a proper .NET version (i.e., five fields); can we get a valid version number up to four fields?
                        string version = null;
                        string[] versionParts = this.Version.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))
                        {
                            this.core.OnMessage(WixWarnings.VersionTruncated(this.PackagePayload.SourceLineNumbers, this.Version, sourcePath, version));
                            this.Version = version;
                        }
                        else
                        {
                            this.core.OnMessage(WixErrors.InvalidProductVersion(this.PackagePayload.SourceLineNumbers, this.Version, sourcePath));
                        }
                    }

                    if (String.IsNullOrEmpty(this.CacheId))
                    {
                        this.CacheId = String.Format("{0}v{1}", this.ProductCode, this.Version);
                    }

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

                    this.Manufacturer = ChainPackageInfo.GetProperty(db, "Manufacturer");

                    this.VerifyMsiProperties();

                    if (YesNoType.Yes == forcePerMachine)
                    {
                        if (YesNoDefaultType.No == this.PerMachine)
                        {
                            this.core.OnMessage(WixWarnings.PerUserButForcingPerMachine(this.PackagePayload.SourceLineNumbers, sourcePath));
                            this.PerMachine = YesNoDefaultType.Yes; // ensure that we think the MSI is per-machine.
                        }

                        this.MsiProperties.Add(new MsiPropertyInfo(this.Id, "ALLUSERS", "1")); // force ALLUSERS=1 via the MSI command-line.
                    }
                    else if (ChainPackageInfo.HasProperty(db, "ALLUSERS"))
                    {
                        string allusers = ChainPackageInfo.GetProperty(db, "ALLUSERS");
                        if (allusers.Equals("1", StringComparison.Ordinal))
                        {
                            if (YesNoDefaultType.No == this.PerMachine)
                            {
                                this.core.OnMessage(WixErrors.PerUserButAllUsersEquals1(this.PackagePayload.SourceLineNumbers, sourcePath));
                            }
                        }
                        else if (allusers.Equals("2", StringComparison.Ordinal))
                        {
                            this.core.OnMessage(WixWarnings.DiscouragedAllUsersValue(this.PackagePayload.SourceLineNumbers, sourcePath, (YesNoDefaultType.Yes == this.PerMachine) ? "machine" : "user"));
                        }
                        else
                        {
                            this.core.OnMessage(WixErrors.UnsupportedAllUsersValue(this.PackagePayload.SourceLineNumbers, sourcePath, allusers));
                        }
                    }
                    else if (YesNoDefaultType.Yes == this.PerMachine) // not forced per-machine and no ALLUSERS property, flip back to per-user
                    {
                        this.core.OnMessage(WixWarnings.ImplicitlyPerUser(this.PackagePayload.SourceLineNumbers, sourcePath));
                        this.PerMachine = YesNoDefaultType.No;
                    }

                    if (String.IsNullOrEmpty(this.Description) && ChainPackageInfo.HasProperty(db, "ARPCOMMENTS"))
                    {
                        this.Description = ChainPackageInfo.GetProperty(db, "ARPCOMMENTS");
                    }

                    // Ensure the MSI package is appropriately marked visible or not.
                    bool alreadyVisible = !ChainPackageInfo.HasProperty(db, "ARPSYSTEMCOMPONENT");
                    if (alreadyVisible != this.Visible) // if not already set to the correct visibility.
                    {
                        // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again.
                        bool sysComponentSet = false;
                        foreach (MsiPropertyInfo propertyInfo in this.MsiProperties)
                        {
                            if ("ARPSYSTEMCOMPONENT".Equals(propertyInfo.Name, StringComparison.Ordinal))
                            {
                                sysComponentSet = true;
                                break;
                            }
                        }

                        if (!sysComponentSet)
                        {
                            this.MsiProperties.Add(new MsiPropertyInfo(this.Id, "ARPSYSTEMCOMPONENT", this.Visible ? "" : "1"));
                        }
                    }

                    // Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance.
                    if (!ChainPackageInfo.HasProperty(db, "MSIFASTINSTALL"))
                    {
                        bool fastInstallSet = false;
                        foreach (MsiPropertyInfo propertyInfo in this.MsiProperties)
                        {
                            if ("MSIFASTINSTALL".Equals(propertyInfo.Name, StringComparison.Ordinal))
                            {
                                fastInstallSet = true;
                                break;
                            }
                        }

                        if (!fastInstallSet)
                        {
                            this.MsiProperties.Add(new MsiPropertyInfo(this.Id, "MSIFASTINSTALL", "7"));
                        }
                    }

                    this.UpgradeCode = ChainPackageInfo.GetProperty(db, "UpgradeCode");

                        // Represent the Upgrade table as related packages.
                    if (db.Tables.Contains("Upgrade") && !String.IsNullOrEmpty(this.UpgradeCode))
                    {
                        using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`"))
                        {
                            view.Execute();
                            while (true)
                            {
                                using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch())
                                {
                                    if (null == record)
                                    {
                                        break;
                                    }

                                    RelatedPackage related = new RelatedPackage();
                                    related.Id = record.GetString(1);
                                    related.MinVersion = record.GetString(2);
                                    related.MaxVersion = record.GetString(3);

                                    string languages = record.GetString(4);
                                    if (!String.IsNullOrEmpty(languages))
                                    {
                                        string[] splitLanguages = languages.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                        related.Languages.AddRange(splitLanguages);
                                    }

                                    int attributes = record.GetInteger(5);
                                    // when an Upgrade row has an upgrade code different than this package's upgrade code, don't count it as a possible downgrade to this package
                                    related.OnlyDetect = ((attributes & MsiInterop.MsidbUpgradeAttributesOnlyDetect) == MsiInterop.MsidbUpgradeAttributesOnlyDetect) && this.UpgradeCode.Equals(related.Id, StringComparison.OrdinalIgnoreCase);
                                    related.MinInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMinInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMinInclusive;
                                    related.MaxInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive;
                                    related.LangInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesLanguagesExclusive) == 0;

                                    this.RelatedPackages.Add(related);
                                }
                            }
                        }
                    }

                    // If feature selection is enabled, represent the Feature table in the manifest.
                    if (YesNoType.Yes == enableFeatureSelection && db.Tables.Contains("Feature"))
                    {
                        using (Microsoft.Deployment.WindowsInstaller.View featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"),
                                    componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?"))
                        {
                            using (Microsoft.Deployment.WindowsInstaller.Record featureRecord = new Microsoft.Deployment.WindowsInstaller.Record(1),
                                          componentRecord = new Microsoft.Deployment.WindowsInstaller.Record(1))
                            {
                                using (Microsoft.Deployment.WindowsInstaller.View allFeaturesView = db.OpenView("SELECT * FROM `Feature`"))
                                {
                                    allFeaturesView.Execute();

                                    while (true)
                                    {
                                        using (Microsoft.Deployment.WindowsInstaller.Record allFeaturesResultRecord = allFeaturesView.Fetch())
                                        {
                                            if (null == allFeaturesResultRecord)
                                            {
                                                break;
                                            }

                                            MsiFeature feature = new MsiFeature();
                                            string featureName = allFeaturesResultRecord.GetString(1);
                                            feature.Name = featureName;
                                            feature.Size = 0;
                                            feature.Parent = allFeaturesResultRecord.GetString(2);
                                            feature.Title = allFeaturesResultRecord.GetString(3);
                                            feature.Description = allFeaturesResultRecord.GetString(4);
                                            feature.Display = allFeaturesResultRecord.GetInteger(5);
                                            feature.Level = allFeaturesResultRecord.GetInteger(6);
                                            feature.Directory = allFeaturesResultRecord.GetString(7);
                                            feature.Attributes = allFeaturesResultRecord.GetInteger(8);
                                            this.MsiFeatures.Add(feature);

                                            // Determine Feature Size
                                            featureRecord.SetString(1, featureName);
                                            featureView.Execute(featureRecord);

                                            // Loop over all the components
                                            while (true)
                                            {
                                                using (Microsoft.Deployment.WindowsInstaller.Record componentResultRecord = featureView.Fetch())
                                                {
                                                    if (null == componentResultRecord)
                                                    {
                                                        break;
                                                    }
                                                    string component = componentResultRecord.GetString(1);
                                                    componentRecord.SetString(1, component);
                                                    componentView.Execute(componentRecord);

                                                    // Loop over all the files

                                                    while (true)
                                                    {
                                                        using (Microsoft.Deployment.WindowsInstaller.Record fileResultRecord = componentView.Fetch())
                                                        {
                                                            if (null == fileResultRecord)
                                                            {
                                                                break;
                                                            }

                                                            string fileSize = fileResultRecord.GetString(1);
                                                            feature.Size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat);
                                                        }
                                                    }

                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // Add all external cabinets as package payloads.
                    if (db.Tables.Contains("Media"))
                    {
                        foreach (string cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`"))
                        {
                            if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal))
                            {
                                // If we didn't find the Payload as an existing child of the package, we need to
                                // add it.  We expect the file to exist on-disk in the same relative location as
                                // the MSI expects to find it...
                                string cabinetName = Path.Combine(Path.GetDirectoryName(this.PackagePayload.Name), cabinet);
                                if (!this.IsExistingPayload(cabinetName))
                                {
                                    string generatedId = Common.GenerateIdentifier("cab", true, this.PackagePayload.Id, cabinet);
                                    string payloadSourceFile = fileManager.ResolveRelatedFile(this.PackagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.PackagePayload.SourceLineNumbers, BindStage.Normal);

                                    PayloadInfoRow payloadNew = PayloadInfoRow.Create(this.SourceLineNumbers, bundle, generatedId, cabinetName, payloadSourceFile, true, this.PackagePayload.SuppressSignatureValidation, null, this.PackagePayload.Container, this.PackagePayload.Packaging);
                                    payloadNew.ParentPackagePayload = this.PackagePayload.Id;
                                    if (!String.IsNullOrEmpty(payloadNew.Container))
                                    {
                                        containers[payloadNew.Container].Payloads.Add(payloadNew);
                                    }

                                    this.Payloads.Add(payloadNew);
                                    allPayloads.Add(payloadNew.Id, payloadNew);

                                    this.Size += payloadNew.FileSize; // add the newly added payload to the package size.
                                }
                            }
                        }
                    }

                    // Add all external files as package payloads and calculate the total install size as the rollup of
                    // File table's sizes.
                    this.InstallSize = 0;
                    if (db.Tables.Contains("Component") && db.Tables.Contains("Directory") && db.Tables.Contains("File"))
                    {
                        Hashtable directories = new Hashtable();

                        // Load up the directory hash table so we will be able to resolve source paths
                        // for files in the MSI database.
                        using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
                        {
                            view.Execute();
                            while (true)
                            {
                                using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch())
                                {
                                    if (null == record)
                                    {
                                        break;
                                    }
                                    string sourceName = Installer.GetName(record.GetString(3), true, longNamesInImage);
                                    directories.Add(record.GetString(1), new ResolvedDirectory(record.GetString(2), sourceName));
                                }
                            }
                        }

                        // Resolve the source paths to external files and add each file size to the total
                        // install size of the package.
                        using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`"))
                        {
                            view.Execute();
                            while (true)
                            {
                                using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch())
                                {
                                    if (null == record)
                                    {
                                        break;
                                    }

                                    // Skip adding the loose files as payloads if it was suppressed.
                                    if (suppressLooseFilePayloadGeneration != YesNoType.Yes)
                                    {
                                        // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not
                                        // explicitly marked compressed then this is an external file.
                                        if (MsiInterop.MsidbFileAttributesNoncompressed == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesNoncompressed) ||
                                            (!compressed && 0 == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesCompressed)))
                                        {
                                            string generatedId = Common.GenerateIdentifier("f", true, this.PackagePayload.Id, record.GetString(2));
                                            string fileSourcePath = Binder.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
                                            string payloadSourceFile = fileManager.ResolveRelatedFile(this.PackagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.PackagePayload.SourceLineNumbers, BindStage.Normal);
                                            string name = Path.Combine(Path.GetDirectoryName(this.PackagePayload.Name), fileSourcePath);

                                            if (!this.IsExistingPayload(name))
                                            {
                                                PayloadInfoRow payloadNew = PayloadInfoRow.Create(this.SourceLineNumbers, bundle, generatedId, name, payloadSourceFile, true, this.PackagePayload.SuppressSignatureValidation, null, this.PackagePayload.Container, this.PackagePayload.Packaging);
                                                payloadNew.ParentPackagePayload = this.PackagePayload.Id;
                                                if (!String.IsNullOrEmpty(payloadNew.Container))
                                                {
                                                    containers[payloadNew.Container].Payloads.Add(payloadNew);
                                                }

                                                this.Payloads.Add(payloadNew);
                                                allPayloads.Add(payloadNew.Id, payloadNew);

                                                this.Size += payloadNew.FileSize; // add the newly added payload to the package size.
                                            }
                                        }
                                    }

                                    this.InstallSize += record.GetInteger(5);
                                }
                            }
                        }
                    }

                    // Import any dependency providers from the MSI.
                    if (db.Tables.Contains("WixDependencyProvider"))
                    {
                        // Use the old schema (v1) if the Version column does not exist.
                        bool hasVersion = db.Tables["WixDependencyProvider"].Columns.Contains("Version");
                        string query = "SELECT `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`";

                        if (!hasVersion)
                        {
                            query = "SELECT `ProviderKey`, `Attributes` FROM `WixDependencyProvider`";
                        }

                        using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView(query))
                        {
                            view.Execute();
                            while (true)
                            {
                                using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch())
                                {
                                    if (null == record)
                                    {
                                        break;
                                    }

                                    // Import the provider key and attributes.
                                    ProvidesDependency dependency = null;
                                    string providerKey = record.GetString(1);

                                    if (hasVersion)
                                    {
                                        string version = record.GetString(2) ?? this.Version;
                                        string displayName = record.GetString(3) ?? this.DisplayName;
                                        int attributes = record.GetInteger(4);

                                        dependency = new ProvidesDependency(providerKey, version, displayName, attributes);
                                    }
                                    else
                                    {
                                        int attributes = record.GetInteger(2);

                                        dependency = new ProvidesDependency(providerKey, this.Version, this.DisplayName, attributes);
                                    }

                                    dependency.Imported = true;
                                    this.Provides.Add(dependency);
                                }
                            }
                        }
                    }
                }
            }
            catch (Microsoft.Deployment.WindowsInstaller.InstallerException e)
            {
                this.core.OnMessage(WixErrors.UnableToReadPackageInformation(this.PackagePayload.SourceLineNumbers, sourcePath, e.Message));
            }
        }
Exemple #3
0
        /// <summary>
        /// Initializes package state from the MSP contents.
        /// </summary>
        /// <param name="core">BinderCore for messages.</param>
        private void ResolveMspPackage(BinderCore core, Output bundle)
        {
            string sourcePath = this.PackagePayload.FullFileName;

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

                using (Microsoft.Deployment.WindowsInstaller.Database db = new Microsoft.Deployment.WindowsInstaller.Database(sourcePath))
                {
                    if (String.IsNullOrEmpty(this.DisplayName))
                    {
                        this.DisplayName = ChainPackageInfo.GetPatchMetadataProperty(db, "DisplayName");
                    }

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

                    this.Manufacturer = ChainPackageInfo.GetPatchMetadataProperty(db, "ManufacturerName");
                }

                this.PatchXml = Microsoft.Deployment.WindowsInstaller.Installer.ExtractPatchXmlData(sourcePath);

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(this.PatchXml);

                XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
                nsmgr.AddNamespace("p", "http://www.microsoft.com/msi/patch_applicability.xsd");

                foreach (XmlNode node in doc.SelectNodes("/p:MsiPatch/p:TargetProduct", nsmgr))
                {
                    // If this patch targes a product code, this is the best case.
                    XmlNode targetCode = node.SelectSingleNode("p:TargetProductCode", nsmgr);
                    WixBundlePatchTargetCodeAttributes attributes = WixBundlePatchTargetCodeAttributes.None;

                    if (null != targetCode)
                    {
                        attributes = WixBundlePatchTargetCodeAttributes.TargetsProductCode;
                    }
                    else // maybe targets and upgrade code?
                    {
                        targetCode = node.SelectSingleNode("p:UpgradeCode", nsmgr);
                        if (null != targetCode)
                        {
                            attributes = WixBundlePatchTargetCodeAttributes.TargetsUpgradeCode;
                        }
                        else // this patch targets a unknown number of products
                        {
                            this.TargetUnspecified = true;
                        }
                    }

                    Table table = bundle.EnsureTable(core.TableDefinitions["WixBundlePatchTargetCode"]);
                    WixBundlePatchTargetCodeRow row = (WixBundlePatchTargetCodeRow)table.CreateRow(this.PackagePayload.SourceLineNumbers, false);
                    row.MspPackageId = this.PackagePayload.Id;
                    row.TargetCode = targetCode.InnerText;
                    row.Attributes = attributes;

                    if (this.TargetCodes.TryAdd(row))
                    {
                        table.Rows.Add(row);
                    }
                }
            }
            catch (Microsoft.Deployment.WindowsInstaller.InstallerException e)
            {
                core.OnMessage(WixErrors.UnableToReadPackageInformation(this.PackagePayload.SourceLineNumbers, sourcePath, e.Message));
                return;
            }

            if (String.IsNullOrEmpty(this.CacheId))
            {
                this.CacheId = this.PatchCode;
            }
        }