From 3dc92067f57e3803d4e1bac6d055e2a23f797414 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 25 Mar 2021 10:00:35 -0700 Subject: Remove dependency on Dtf.WindowsInstaller from Core --- .../Bind/ProcessBundleSoftwareTagsCommand.cs | 21 +- .../Bundles/ProcessMsiPackageCommand.cs | 503 +++++++++------------ .../Bundles/ProcessMspPackageCommand.cs | 89 ++-- .../WixToolset.Core.Burn.csproj | 1 - .../WixToolset.Core.WindowsInstaller.csproj | 1 - 5 files changed, 257 insertions(+), 358 deletions(-) diff --git a/src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs b/src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs index 8584d2a4..f9ff23cb 100644 --- a/src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs +++ b/src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs @@ -8,9 +8,9 @@ namespace WixToolset.Core.Burn.Bind using System.Linq; using System.Text; using System.Xml; + using WixToolset.Core.Native.Msi; using WixToolset.Data; using WixToolset.Data.Symbols; - using WixToolset.Dtf.WindowsInstaller; internal class ProcessBundleSoftwareTagsCommand { @@ -69,22 +69,13 @@ namespace WixToolset.Core.Burn.Bind { var payload = payloadSymbolsById[msiPackage.PayloadRef]; - using (var db = new Database(payload.SourceFile.Path)) + using (var db = new Database(payload.SourceFile.Path, OpenDatabase.ReadOnly)) { - using (var view = db.OpenView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`")) + using (var view = db.OpenExecuteView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`")) { - view.Execute(); - while (true) + foreach (var record in view.Records) { - using (var record = view.Fetch()) - { - if (null == record) - { - break; - } - - tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) }); - } + tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) }); } } } @@ -98,7 +89,7 @@ namespace WixToolset.Core.Burn.Bind { var versionScheme = Version.TryParse(version, out _) ? "multipartnumeric" : "alphanumeric"; - using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true})) + using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true })) { writer.WriteStartDocument(); writer.WriteStartElement("SoftwareIdentity", "http://standards.iso.org/iso/19770/-2/2015/schema.xsd"); diff --git a/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs index 6d6ae427..99e2eda5 100644 --- a/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs @@ -4,24 +4,23 @@ namespace WixToolset.Core.Burn.Bundles { using System; using System.Collections.Generic; - using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using WixToolset.Data; using WixToolset.Extensibility; - using Dtf = WixToolset.Dtf.WindowsInstaller; using WixToolset.Extensibility.Services; using WixToolset.Data.Symbols; using WixToolset.Data.WindowsInstaller; using WixToolset.Extensibility.Data; + using WixToolset.Core.Native.Msi; /// /// Initializes package state from the MSI contents. /// internal class ProcessMsiPackageCommand { - private const string PropertySqlFormat = "SELECT `Value` FROM `Property` WHERE `Property` = '{0}'"; + private const string PropertySqlQuery = "SELECT `Value` FROM `Property` WHERE `Property` = ?"; public ProcessMsiPackageCommand(IServiceProvider serviceProvider, IEnumerable backendExtensions, IntermediateSection section, PackageFacade facade, Dictionary packagePayloads) { @@ -64,41 +63,60 @@ namespace WixToolset.Core.Burn.Bundles var compressed = false; try { - // Read data out of the msi database... - using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false)) + using (var db = new Database(sourcePath, OpenDatabase.ReadOnly)) { - // 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. - var perMachine = (0 == (sumInfo.WordCount & 8)); - var x64 = sumInfo.Template.Contains("x64"); - - this.Facade.PackageSymbol.PerMachine = perMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No; - this.Facade.PackageSymbol.Win64 = x64; - } + // Read data out of the msi database... + using (var sumInfo = new SummaryInformation(db)) + { + var fileAndElevateFlags = sumInfo.GetNumericProperty(SummaryInformation.Package.FileAndElevatedFlags); + var platformsAndLanguages = sumInfo.GetProperty(SummaryInformation.Package.PlatformsAndLanguages); - using (var db = new Dtf.Database(sourcePath)) - { - msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode"); - msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode"); - msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer"); - msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture); - msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion"); + // 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 == (fileAndElevateFlags & 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 == (fileAndElevateFlags & 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. + var perMachine = (0 == (fileAndElevateFlags & 8)); + var x64 = platformsAndLanguages.Contains("x64"); + + this.Facade.PackageSymbol.PerMachine = perMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No; + this.Facade.PackageSymbol.Win64 = x64; + } + + string packageName = null; + string packageDescription = null; + string allusers = null; + string fastInstall = null; + string systemComponent = null; + + using (var view = db.OpenView(PropertySqlQuery)) + { + packageName = ProcessMsiPackageCommand.GetProperty(view, "ProductName"); + packageDescription = ProcessMsiPackageCommand.GetProperty(view, "ARPCOMMENTS"); + allusers = ProcessMsiPackageCommand.GetProperty(view, "ALLUSERS"); + fastInstall = ProcessMsiPackageCommand.GetProperty(view, "MSIFASTINSTALL"); + systemComponent = ProcessMsiPackageCommand.GetProperty(view, "ARPSYSTEMCOMPONENT"); + + msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(view, "ProductCode"); + msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(view, "UpgradeCode"); + msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(view, "Manufacturer"); + msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(view, "ProductLanguage"), CultureInfo.InvariantCulture); + msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(view, "ProductVersion"); + } if (!this.BackendHelper.IsValidFourPartVersion(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 = msiPackage.ProductVersion.Split('.'); + var versionParts = msiPackage.ProductVersion.Split('.'); var count = versionParts.Length; if (0 < count) { @@ -127,12 +145,12 @@ namespace WixToolset.Core.Burn.Bundles if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName)) { - this.Facade.PackageSymbol.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName"); + this.Facade.PackageSymbol.DisplayName = packageName; } if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description)) { - this.Facade.PackageSymbol.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS"); + this.Facade.PackageSymbol.Description = packageDescription; } if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Version)) @@ -144,13 +162,13 @@ namespace WixToolset.Core.Burn.Bundles var msiPropertyNames = this.GetMsiPropertyNames(packagePayload.Id.Id); - this.SetPerMachineAppropriately(db, msiPackage, sourcePath); + this.SetPerMachineAppropriately(allusers, msiPackage, sourcePath); // Ensure the MSI package is appropriately marked visible or not. - this.SetPackageVisibility(db, msiPackage, msiPropertyNames); + this.SetPackageVisibility(systemComponent, msiPackage, msiPropertyNames); // Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance. - if (!msiPropertyNames.Contains("MSIFASTINSTALL") && !ProcessMsiPackageCommand.HasProperty(db, "MSIFASTINSTALL")) + if (!String.IsNullOrEmpty(fastInstall)) { this.AddMsiProperty(msiPackage, "MSIFASTINSTALL", "7"); } @@ -171,10 +189,10 @@ namespace WixToolset.Core.Burn.Bundles this.Facade.PackageSymbol.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames); // Add all dependency providers from the MSI. - this.ImportDependencyProviders(msiPackage, db); + this.ImportDependencyProviders(db, msiPackage); } } - catch (Dtf.InstallerException e) + catch (MsiException e) { this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath, e.Message)); } @@ -196,7 +214,7 @@ namespace WixToolset.Core.Burn.Bundles return new HashSet(properties, StringComparer.Ordinal); } - private void SetPerMachineAppropriately(Dtf.Database db, WixBundleMsiPackageSymbol msiPackage, string sourcePath) + private void SetPerMachineAppropriately(string allusers, WixBundleMsiPackageSymbol msiPackage, string sourcePath) { if (msiPackage.ForcePerMachine) { @@ -211,8 +229,6 @@ namespace WixToolset.Core.Burn.Bundles } else { - var allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS"); - if (String.IsNullOrEmpty(allusers)) { // Not forced per-machine and no ALLUSERS property, flip back to per-user. @@ -240,269 +256,219 @@ namespace WixToolset.Core.Burn.Bundles } } - private void SetPackageVisibility(Dtf.Database db, WixBundleMsiPackageSymbol msiPackage, ISet msiPropertyNames) + private void SetPackageVisibility(string systemComponent, WixBundleMsiPackageSymbol msiPackage, ISet msiPropertyNames) { - var alreadyVisible = !ProcessMsiPackageCommand.HasProperty(db, "ARPSYSTEMCOMPONENT"); - var visible = (this.Facade.PackageSymbol.Attributes & WixBundlePackageAttributes.Visible) == WixBundlePackageAttributes.Visible; - - // If not already set to the correct visibility. - if (alreadyVisible != visible) + // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again. + if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT")) { - // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again. - if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT")) + var alreadyVisible = String.IsNullOrEmpty(systemComponent); + var visible = (this.Facade.PackageSymbol.Attributes & WixBundlePackageAttributes.Visible) == WixBundlePackageAttributes.Visible; + + // If not already set to the correct visibility. + if (alreadyVisible != visible) { this.AddMsiProperty(msiPackage, "ARPSYSTEMCOMPONENT", visible ? String.Empty : "1"); } } } - private void CreateRelatedPackages(Dtf.Database db) + private void CreateRelatedPackages(Database db) { // Represent the Upgrade table as related packages. - if (db.Tables.Contains("Upgrade")) + if (db.TableExists("Upgrade")) { - using (var view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`")) + using (var view = db.OpenExecuteView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`")) { - view.Execute(); - while (true) + foreach (var record in view.Records) { - using (var record = view.Fetch()) - { - if (null == record) - { - break; - } + var recordAttributes = record.GetInteger(5); - var recordAttributes = record.GetInteger(5); + var attributes = WixBundleRelatedPackageAttributes.None; + attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect ? WixBundleRelatedPackageAttributes.OnlyDetect : 0; + attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive ? WixBundleRelatedPackageAttributes.MinInclusive : 0; + attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive ? WixBundleRelatedPackageAttributes.MaxInclusive : 0; + attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive ? WixBundleRelatedPackageAttributes.LangInclusive : 0; - var attributes = WixBundleRelatedPackageAttributes.None; - attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect ? WixBundleRelatedPackageAttributes.OnlyDetect : 0; - attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive ? WixBundleRelatedPackageAttributes.MinInclusive : 0; - attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive ? WixBundleRelatedPackageAttributes.MaxInclusive : 0; - attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive ? WixBundleRelatedPackageAttributes.LangInclusive : 0; - - this.Section.AddSymbol(new WixBundleRelatedPackageSymbol(this.Facade.PackageSymbol.SourceLineNumbers) - { - PackageRef = this.Facade.PackageId, - RelatedId = record.GetString(1), - MinVersion = record.GetString(2), - MaxVersion = record.GetString(3), - Languages = record.GetString(4), - Attributes = attributes, - }); - } + this.Section.AddSymbol(new WixBundleRelatedPackageSymbol(this.Facade.PackageSymbol.SourceLineNumbers) + { + PackageRef = this.Facade.PackageId, + RelatedId = record.GetString(1), + MinVersion = record.GetString(2), + MaxVersion = record.GetString(3), + Languages = record.GetString(4), + Attributes = attributes, + }); } } } } - private void CreateMsiFeatures(Dtf.Database db) + private void CreateMsiFeatures(Database db) { - if (db.Tables.Contains("Feature")) + if (db.TableExists("Feature")) { + using (var allFeaturesView = db.OpenExecuteView("SELECT * FROM `Feature`")) using (var featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?")) using (var componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?")) { - using (var featureRecord = new Dtf.Record(1)) - using (var componentRecord = new Dtf.Record(1)) + using (var featureRecord = new Record(1)) + using (var componentRecord = new Record(1)) { - using (var allFeaturesView = db.OpenView("SELECT * FROM `Feature`")) + foreach (var allFeaturesResultRecord in allFeaturesView.Records) { - allFeaturesView.Execute(); + var featureName = allFeaturesResultRecord.GetString(1); + + // Calculate the Feature size. + featureRecord.SetString(1, featureName); + featureView.Execute(featureRecord); - while (true) + // Loop over all the components for the feature to calculate the size of the feature. + long size = 0; + foreach (var componentResultRecord in featureView.Records) { - using (var allFeaturesResultRecord = allFeaturesView.Fetch()) + var component = componentResultRecord.GetString(1); + componentRecord.SetString(1, component); + componentView.Execute(componentRecord); + + foreach (var fileResultRecord in componentView.Records) { - if (null == allFeaturesResultRecord) - { - break; - } - - var featureName = allFeaturesResultRecord.GetString(1); - - // Calculate the Feature size. - featureRecord.SetString(1, featureName); - featureView.Execute(featureRecord); - - // Loop over all the components for the feature to calculate the size of the feature. - long size = 0; - while (true) - { - using (var componentResultRecord = featureView.Fetch()) - { - if (null == componentResultRecord) - { - break; - } - - var component = componentResultRecord.GetString(1); - componentRecord.SetString(1, component); - componentView.Execute(componentRecord); - - while (true) - { - using (var fileResultRecord = componentView.Fetch()) - { - if (null == fileResultRecord) - { - break; - } - - var fileSize = fileResultRecord.GetString(1); - size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat); - } - } - } - } - - this.Section.AddSymbol(new WixBundleMsiFeatureSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, this.Facade.PackageId, featureName)) - { - PackageRef = this.Facade.PackageId, - Name = featureName, - Parent = allFeaturesResultRecord.GetString(2), - Title = allFeaturesResultRecord.GetString(3), - Description = allFeaturesResultRecord.GetString(4), - Display = allFeaturesResultRecord.GetInteger(5), - Level = allFeaturesResultRecord.GetInteger(6), - Directory = allFeaturesResultRecord.GetString(7), - Attributes = allFeaturesResultRecord.GetInteger(8), - Size = size - }); + var fileSize = fileResultRecord.GetString(1); + size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat); } } + + this.Section.AddSymbol(new WixBundleMsiFeatureSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, this.Facade.PackageId, featureName)) + { + PackageRef = this.Facade.PackageId, + Name = featureName, + Parent = allFeaturesResultRecord.GetString(2), + Title = allFeaturesResultRecord.GetString(3), + Description = allFeaturesResultRecord.GetString(4), + Display = allFeaturesResultRecord.GetInteger(5), + Level = allFeaturesResultRecord.GetInteger(6), + Directory = allFeaturesResultRecord.GetString(7), + Attributes = allFeaturesResultRecord.GetInteger(8), + Size = size + }); } } } } } - private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadSymbol packagePayload, ISet payloadNames) + private void ImportExternalCabinetAsPayloads(Database db, WixBundlePayloadSymbol packagePayload, ISet payloadNames) { - if (db.Tables.Contains("Media")) + if (db.TableExists("Media")) { - foreach (var cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`")) + using (var view = db.OpenExecuteView("SELECT `Cabinet` FROM `Media`")) { - if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal)) + foreach (var cabinetRecord in view.Records) { - // 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... - var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet); + var cabinet = cabinetRecord.GetString(1); - if (!payloadNames.Contains(cabinetName)) + if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal)) { - var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet); - var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers); + // 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... + var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet); - this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers) + if (!payloadNames.Contains(cabinetName)) { - ParentType = ComplexReferenceParentType.Package, - ParentId = this.Facade.PackageId, - ChildType = ComplexReferenceChildType.Payload, - ChildId = generatedId - }); + var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet); + var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers); - this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) - { - Name = cabinetName, - SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, - Compressed = packagePayload.Compressed, - UnresolvedSourceFile = cabinetName, - ContainerRef = packagePayload.ContainerRef, - ContentFile = true, - Packaging = packagePayload.Packaging, - ParentPackagePayloadRef = packagePayload.Id.Id, - }); + this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers) + { + ParentType = ComplexReferenceParentType.Package, + ParentId = this.Facade.PackageId, + ChildType = ComplexReferenceChildType.Payload, + ChildId = generatedId + }); + + this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) + { + Name = cabinetName, + SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, + Compressed = packagePayload.Compressed, + UnresolvedSourceFile = cabinetName, + ContainerRef = packagePayload.ContainerRef, + ContentFile = true, + Packaging = packagePayload.Packaging, + ParentPackagePayloadRef = packagePayload.Id.Id, + }); + } } } } } } - private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadSymbol packagePayload, bool longNamesInImage, bool compressed, ISet payloadNames) + private long ImportExternalFileAsPayloadsAndReturnInstallSize(Database db, WixBundlePayloadSymbol packagePayload, bool longNamesInImage, bool compressed, ISet payloadNames) { long size = 0; - if (db.Tables.Contains("Component") && db.Tables.Contains("Directory") && db.Tables.Contains("File")) + if (db.TableExists("Component") && db.TableExists("Directory") && db.TableExists("File")) { var directories = new Dictionary(); // Load up the directory hash table so we will be able to resolve source paths // for files in the MSI database. - using (var view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) + using (var view = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) { - view.Execute(); - while (true) + foreach (var record in view.Records) { - using (var record = view.Fetch()) - { - if (null == record) - { - break; - } + var sourceName = this.BackendHelper.GetMsiFileName(record.GetString(3), true, longNamesInImage); - var sourceName = this.BackendHelper.GetMsiFileName(record.GetString(3), true, longNamesInImage); + var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName); - var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName); - - directories.Add(record.GetString(1), resolvedDirectory); - } + directories.Add(record.GetString(1), resolvedDirectory); } } // Resolve the source paths to external files and add each file size to the total // install size of the package. - using (var view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`")) + using (var view = db.OpenExecuteView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`")) { - view.Execute(); - while (true) + foreach (var record in view.Records) { - using (var record = view.Fetch()) + // 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. + var compressionBit = record.GetInteger(4); + if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) || + (!compressed && 0 == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesCompressed))) { - if (null == record) - { - break; - } + var fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage); + var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath); - // 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. - var compressionBit = record.GetInteger(4); - if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) || - (!compressed && 0 == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesCompressed))) + if (!payloadNames.Contains(name)) { - var fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage); - var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath); + var generatedId = this.BackendHelper.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2)); + var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers); - if (!payloadNames.Contains(name)) + this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers) { - var generatedId = this.BackendHelper.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2)); - var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers); - - this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers) - { - ParentType = ComplexReferenceParentType.Package, - ParentId = this.Facade.PackageId, - ChildType = ComplexReferenceChildType.Payload, - ChildId = generatedId - }); - - this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) - { - Name = name, - SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, - Compressed = packagePayload.Compressed, - UnresolvedSourceFile = name, - ContainerRef = packagePayload.ContainerRef, - ContentFile = true, - Packaging = packagePayload.Packaging, - ParentPackagePayloadRef = packagePayload.Id.Id, - }); - } - } + ParentType = ComplexReferenceParentType.Package, + ParentId = this.Facade.PackageId, + ChildType = ComplexReferenceChildType.Payload, + ChildId = generatedId + }); - size += record.GetInteger(5); + this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) + { + Name = name, + SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, + Compressed = packagePayload.Compressed, + UnresolvedSourceFile = name, + ContainerRef = packagePayload.ContainerRef, + ContentFile = true, + Packaging = packagePayload.Packaging, + ParentPackagePayloadRef = packagePayload.Id.Id, + }); + } } + + size += record.GetInteger(5); } } } @@ -520,36 +486,25 @@ namespace WixToolset.Core.Burn.Bundles }); } - private void ImportDependencyProviders(WixBundleMsiPackageSymbol msiPackage, Dtf.Database db) + private void ImportDependencyProviders(Database db, WixBundleMsiPackageSymbol msiPackage) { - if (db.Tables.Contains("WixDependencyProvider")) + if (db.TableExists("WixDependencyProvider")) { - var query = "SELECT `WixDependencyProvider`, `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`"; - - using (var view = db.OpenView(query)) + using (var view = db.OpenExecuteView("SELECT `WixDependencyProvider`, `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`")) { - view.Execute(); - while (true) + foreach (var record in view.Records) { - using (var record = view.Fetch()) - { - if (null == record) - { - break; - } + var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1))); - var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1))); - - // Import the provider key and attributes. - this.Section.AddSymbol(new WixDependencyProviderSymbol(msiPackage.SourceLineNumbers, id) - { - ParentRef = msiPackage.Id.Id, - ProviderKey = record.GetString(2), - Version = record.GetString(3) ?? msiPackage.ProductVersion, - DisplayName = record.GetString(4) ?? this.Facade.PackageSymbol.DisplayName, - Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)record.GetInteger(5), - }); - } + // Import the provider key and attributes. + this.Section.AddSymbol(new WixDependencyProviderSymbol(msiPackage.SourceLineNumbers, id) + { + ParentRef = msiPackage.Id.Id, + ProviderKey = record.GetString(2), + Version = record.GetString(3) ?? msiPackage.ProductVersion, + DisplayName = record.GetString(4) ?? this.Facade.PackageSymbol.DisplayName, + Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)record.GetInteger(5), + }); } } } @@ -585,51 +540,19 @@ namespace WixToolset.Core.Burn.Bundles return resolvedPath; } - /// - /// Queries a Windows Installer database for a Property value. - /// - /// Database to query. - /// Property to examine. - /// String value for result or null if query doesn't match a single result. - private static string GetProperty(Dtf.Database db, string property) + private static string GetProperty(View view, string property) { - try - { - return db.ExecuteScalar(PropertyQuery(property)).ToString(); - } - catch (Dtf.InstallerException) + using (var queryRecord = new Record(1)) { - } + queryRecord[1] = property; - return null; - } + view.Execute(queryRecord); - /// - /// Queries a Windows Installer database to determine if one or more rows exist in the Property table. - /// - /// Database to query. - /// Property to examine. - /// True if query matches at least one result. - private static bool HasProperty(Dtf.Database db, string property) - { - try - { - return 0 < db.ExecuteQuery(PropertyQuery(property)).Count; - } - catch (Dtf.InstallerException) - { + using (var record = view.Fetch()) + { + return record?.GetString(1); + } } - - return false; - } - - private static string PropertyQuery(string property) - { - // quick sanity check that we'll be creating a valid query... - // TODO: Are there any other special characters we should be looking for? - Debug.Assert(!property.Contains("'")); - - return String.Format(CultureInfo.InvariantCulture, ProcessMsiPackageCommand.PropertySqlFormat, property); } } } diff --git a/src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs index f528ce20..5f431b38 100644 --- a/src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs @@ -4,23 +4,27 @@ namespace WixToolset.Core.Burn.Bundles { using System; using System.Collections.Generic; - using System.Diagnostics; - using System.Globalization; using System.IO; using System.Text; using System.Xml; + using WixToolset.Core.Native.Msi; using WixToolset.Data; using WixToolset.Data.Symbols; using WixToolset.Extensibility.Services; - using Dtf = WixToolset.Dtf.WindowsInstaller; /// /// Initializes package state from the Msp contents. /// internal class ProcessMspPackageCommand { - private const string PatchMetadataFormat = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = '{0}'"; - private static readonly Encoding XmlOutputEncoding = new UTF8Encoding(false); + private const string PatchMetadataQuery = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = ?"; + private static readonly XmlWriterSettings XmlSettings = new XmlWriterSettings() + { + Encoding = new UTF8Encoding(false), + Indent = false, + NewLineChars = String.Empty, + NewLineHandling = NewLineHandling.Replace, + }; public ProcessMspPackageCommand(IMessaging messaging, IntermediateSection section, PackageFacade facade, Dictionary payloadSymbols) { @@ -52,30 +56,34 @@ namespace WixToolset.Core.Burn.Bundles 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)) + using (var db = new Database(sourcePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) { - if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName)) + // Read data out of the msp database... + using (var sumInfo = new SummaryInformation(db)) { - this.Facade.PackageSymbol.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName"); + var patchCode = sumInfo.GetProperty(SummaryInformation.Patch.PatchCode); + mspPackage.PatchCode = patchCode.Substring(0, 38); } - if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description)) + using (var view = db.OpenView(PatchMetadataQuery)) { - this.Facade.PackageSymbol.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description"); - } + if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName)) + { + this.Facade.PackageSymbol.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(view, "DisplayName"); + } + + if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description)) + { + this.Facade.PackageSymbol.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(view, "Description"); + } - mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName"); + mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(view, "ManufacturerName"); + } } this.ProcessPatchXml(packagePayload, mspPackage, sourcePath); } - catch (Dtf.InstallerException e) + catch (MsiException e) { this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message)); return; @@ -91,7 +99,7 @@ namespace WixToolset.Core.Burn.Bundles { var uniqueTargetCodes = new HashSet(); - var patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath); + var patchXml = Installer.ExtractPatchXml(sourcePath); var doc = new XmlDocument(); doc.LoadXml(patchXml); @@ -146,15 +154,7 @@ namespace WixToolset.Core.Burn.Bundles // Save the XML as compact as possible. using (var writer = new StringWriter()) { - var settings = new XmlWriterSettings() - { - Encoding = ProcessMspPackageCommand.XmlOutputEncoding, - Indent = false, - NewLineChars = String.Empty, - NewLineHandling = NewLineHandling.Replace, - }; - - using (var xmlWriter = XmlWriter.Create(writer, settings)) + using (var xmlWriter = XmlWriter.Create(writer, XmlSettings)) { doc.WriteTo(xmlWriter); } @@ -163,32 +163,19 @@ namespace WixToolset.Core.Burn.Bundles } } - /// - /// Queries a Windows Installer patch database for a Property value from the MsiPatchMetadata table. - /// - /// Database to query. - /// Property to examine. - /// String value for result or null if query doesn't match a single result. - private static string GetPatchMetadataProperty(Dtf.Database db, string property) + private static string GetPatchMetadataProperty(View view, string property) { - try - { - return db.ExecuteScalar(PatchMetadataPropertyQuery(property)).ToString(); - } - catch (Dtf.InstallerException) + using (var queryRecord = new Record(1)) { - } - - return null; - } + queryRecord[1] = property; - private static string PatchMetadataPropertyQuery(string property) - { - // quick sanity check that we'll be creating a valid query... - // TODO: Are there any other special characters we should be looking for? - Debug.Assert(!property.Contains("'")); + view.Execute(queryRecord); - return String.Format(CultureInfo.InvariantCulture, ProcessMspPackageCommand.PatchMetadataFormat, property); + using (var record = view.Fetch()) + { + return record?.GetString(1); + } + } } private static bool TargetsCode(XmlNode node) => "true" == node?.Attributes["Validate"]?.Value; diff --git a/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj b/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj index 4c57f567..2e828eae 100644 --- a/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj +++ b/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj @@ -27,7 +27,6 @@ - diff --git a/src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj b/src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj index cd2c917c..56262373 100644 --- a/src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj +++ b/src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj @@ -15,7 +15,6 @@ - -- cgit v1.2.3-55-g6feb