aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-03-25 10:00:35 -0700
committerRob Mensching <rob@firegiant.com>2021-03-25 10:04:58 -0700
commit3dc92067f57e3803d4e1bac6d055e2a23f797414 (patch)
tree2127b1a5e2a1d11674c7d4411cc277dd61a43ea9
parent7c5ccef16a3d6c88c6da2b996fbe7ec5010ea50c (diff)
downloadwix-3dc92067f57e3803d4e1bac6d055e2a23f797414.tar.gz
wix-3dc92067f57e3803d4e1bac6d055e2a23f797414.tar.bz2
wix-3dc92067f57e3803d4e1bac6d055e2a23f797414.zip
Remove dependency on Dtf.WindowsInstaller from Core
-rw-r--r--src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs21
-rw-r--r--src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs503
-rw-r--r--src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs89
-rw-r--r--src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj1
-rw-r--r--src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj1
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
8 using System.Linq; 8 using System.Linq;
9 using System.Text; 9 using System.Text;
10 using System.Xml; 10 using System.Xml;
11 using WixToolset.Core.Native.Msi;
11 using WixToolset.Data; 12 using WixToolset.Data;
12 using WixToolset.Data.Symbols; 13 using WixToolset.Data.Symbols;
13 using WixToolset.Dtf.WindowsInstaller;
14 14
15 internal class ProcessBundleSoftwareTagsCommand 15 internal class ProcessBundleSoftwareTagsCommand
16 { 16 {
@@ -69,22 +69,13 @@ namespace WixToolset.Core.Burn.Bind
69 { 69 {
70 var payload = payloadSymbolsById[msiPackage.PayloadRef]; 70 var payload = payloadSymbolsById[msiPackage.PayloadRef];
71 71
72 using (var db = new Database(payload.SourceFile.Path)) 72 using (var db = new Database(payload.SourceFile.Path, OpenDatabase.ReadOnly))
73 { 73 {
74 using (var view = db.OpenView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`")) 74 using (var view = db.OpenExecuteView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`"))
75 { 75 {
76 view.Execute(); 76 foreach (var record in view.Records)
77 while (true)
78 { 77 {
79 using (var record = view.Fetch()) 78 tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) });
80 {
81 if (null == record)
82 {
83 break;
84 }
85
86 tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) });
87 }
88 } 79 }
89 } 80 }
90 } 81 }
@@ -98,7 +89,7 @@ namespace WixToolset.Core.Burn.Bind
98 { 89 {
99 var versionScheme = Version.TryParse(version, out _) ? "multipartnumeric" : "alphanumeric"; 90 var versionScheme = Version.TryParse(version, out _) ? "multipartnumeric" : "alphanumeric";
100 91
101 using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true})) 92 using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true }))
102 { 93 {
103 writer.WriteStartDocument(); 94 writer.WriteStartDocument();
104 writer.WriteStartElement("SoftwareIdentity", "http://standards.iso.org/iso/19770/-2/2015/schema.xsd"); 95 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
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Globalization; 7 using System.Globalization;
9 using System.IO; 8 using System.IO;
10 using System.Linq; 9 using System.Linq;
11 using WixToolset.Data; 10 using WixToolset.Data;
12 using WixToolset.Extensibility; 11 using WixToolset.Extensibility;
13 using Dtf = WixToolset.Dtf.WindowsInstaller;
14 using WixToolset.Extensibility.Services; 12 using WixToolset.Extensibility.Services;
15 using WixToolset.Data.Symbols; 13 using WixToolset.Data.Symbols;
16 using WixToolset.Data.WindowsInstaller; 14 using WixToolset.Data.WindowsInstaller;
17 using WixToolset.Extensibility.Data; 15 using WixToolset.Extensibility.Data;
16 using WixToolset.Core.Native.Msi;
18 17
19 /// <summary> 18 /// <summary>
20 /// Initializes package state from the MSI contents. 19 /// Initializes package state from the MSI contents.
21 /// </summary> 20 /// </summary>
22 internal class ProcessMsiPackageCommand 21 internal class ProcessMsiPackageCommand
23 { 22 {
24 private const string PropertySqlFormat = "SELECT `Value` FROM `Property` WHERE `Property` = '{0}'"; 23 private const string PropertySqlQuery = "SELECT `Value` FROM `Property` WHERE `Property` = ?";
25 24
26 public ProcessMsiPackageCommand(IServiceProvider serviceProvider, IEnumerable<IBurnBackendBinderExtension> backendExtensions, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> packagePayloads) 25 public ProcessMsiPackageCommand(IServiceProvider serviceProvider, IEnumerable<IBurnBackendBinderExtension> backendExtensions, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> packagePayloads)
27 { 26 {
@@ -64,41 +63,60 @@ namespace WixToolset.Core.Burn.Bundles
64 var compressed = false; 63 var compressed = false;
65 try 64 try
66 { 65 {
67 // Read data out of the msi database... 66 using (var db = new Database(sourcePath, OpenDatabase.ReadOnly))
68 using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
69 { 67 {
70 // 1 is the Word Count summary information stream bit that means 68 // Read data out of the msi database...
71 // the MSI uses short file names when set. We care about long file 69 using (var sumInfo = new SummaryInformation(db))
72 // names so check when the bit is not set. 70 {
73 longNamesInImage = 0 == (sumInfo.WordCount & 1); 71 var fileAndElevateFlags = sumInfo.GetNumericProperty(SummaryInformation.Package.FileAndElevatedFlags);
74 72 var platformsAndLanguages = sumInfo.GetProperty(SummaryInformation.Package.PlatformsAndLanguages);
75 // 2 is the Word Count summary information stream bit that means
76 // files are compressed in the MSI by default when the bit is set.
77 compressed = 2 == (sumInfo.WordCount & 2);
78
79 // 8 is the Word Count summary information stream bit that means
80 // "Elevated privileges are not required to install this package."
81 // in MSI 4.5 and below, if this bit is 0, elevation is required.
82 var perMachine = (0 == (sumInfo.WordCount & 8));
83 var x64 = sumInfo.Template.Contains("x64");
84
85 this.Facade.PackageSymbol.PerMachine = perMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No;
86 this.Facade.PackageSymbol.Win64 = x64;
87 }
88 73
89 using (var db = new Dtf.Database(sourcePath)) 74 // 1 is the Word Count summary information stream bit that means
90 { 75 // the MSI uses short file names when set. We care about long file
91 msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode"); 76 // names so check when the bit is not set.
92 msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode"); 77
93 msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer"); 78 longNamesInImage = 0 == (fileAndElevateFlags & 1);
94 msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture); 79
95 msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion"); 80 // 2 is the Word Count summary information stream bit that means
81 // files are compressed in the MSI by default when the bit is set.
82 compressed = 2 == (fileAndElevateFlags & 2);
83
84 // 8 is the Word Count summary information stream bit that means
85 // "Elevated privileges are not required to install this package."
86 // in MSI 4.5 and below, if this bit is 0, elevation is required.
87 var perMachine = (0 == (fileAndElevateFlags & 8));
88 var x64 = platformsAndLanguages.Contains("x64");
89
90 this.Facade.PackageSymbol.PerMachine = perMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No;
91 this.Facade.PackageSymbol.Win64 = x64;
92 }
93
94 string packageName = null;
95 string packageDescription = null;
96 string allusers = null;
97 string fastInstall = null;
98 string systemComponent = null;
99
100 using (var view = db.OpenView(PropertySqlQuery))
101 {
102 packageName = ProcessMsiPackageCommand.GetProperty(view, "ProductName");
103 packageDescription = ProcessMsiPackageCommand.GetProperty(view, "ARPCOMMENTS");
104 allusers = ProcessMsiPackageCommand.GetProperty(view, "ALLUSERS");
105 fastInstall = ProcessMsiPackageCommand.GetProperty(view, "MSIFASTINSTALL");
106 systemComponent = ProcessMsiPackageCommand.GetProperty(view, "ARPSYSTEMCOMPONENT");
107
108 msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(view, "ProductCode");
109 msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(view, "UpgradeCode");
110 msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(view, "Manufacturer");
111 msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(view, "ProductLanguage"), CultureInfo.InvariantCulture);
112 msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(view, "ProductVersion");
113 }
96 114
97 if (!this.BackendHelper.IsValidFourPartVersion(msiPackage.ProductVersion)) 115 if (!this.BackendHelper.IsValidFourPartVersion(msiPackage.ProductVersion))
98 { 116 {
99 // not a proper .NET version (e.g., five fields); can we get a valid four-part version number? 117 // not a proper .NET version (e.g., five fields); can we get a valid four-part version number?
100 string version = null; 118 string version = null;
101 string[] versionParts = msiPackage.ProductVersion.Split('.'); 119 var versionParts = msiPackage.ProductVersion.Split('.');
102 var count = versionParts.Length; 120 var count = versionParts.Length;
103 if (0 < count) 121 if (0 < count)
104 { 122 {
@@ -127,12 +145,12 @@ namespace WixToolset.Core.Burn.Bundles
127 145
128 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName)) 146 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName))
129 { 147 {
130 this.Facade.PackageSymbol.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName"); 148 this.Facade.PackageSymbol.DisplayName = packageName;
131 } 149 }
132 150
133 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description)) 151 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description))
134 { 152 {
135 this.Facade.PackageSymbol.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS"); 153 this.Facade.PackageSymbol.Description = packageDescription;
136 } 154 }
137 155
138 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Version)) 156 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Version))
@@ -144,13 +162,13 @@ namespace WixToolset.Core.Burn.Bundles
144 162
145 var msiPropertyNames = this.GetMsiPropertyNames(packagePayload.Id.Id); 163 var msiPropertyNames = this.GetMsiPropertyNames(packagePayload.Id.Id);
146 164
147 this.SetPerMachineAppropriately(db, msiPackage, sourcePath); 165 this.SetPerMachineAppropriately(allusers, msiPackage, sourcePath);
148 166
149 // Ensure the MSI package is appropriately marked visible or not. 167 // Ensure the MSI package is appropriately marked visible or not.
150 this.SetPackageVisibility(db, msiPackage, msiPropertyNames); 168 this.SetPackageVisibility(systemComponent, msiPackage, msiPropertyNames);
151 169
152 // Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance. 170 // Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance.
153 if (!msiPropertyNames.Contains("MSIFASTINSTALL") && !ProcessMsiPackageCommand.HasProperty(db, "MSIFASTINSTALL")) 171 if (!String.IsNullOrEmpty(fastInstall))
154 { 172 {
155 this.AddMsiProperty(msiPackage, "MSIFASTINSTALL", "7"); 173 this.AddMsiProperty(msiPackage, "MSIFASTINSTALL", "7");
156 } 174 }
@@ -171,10 +189,10 @@ namespace WixToolset.Core.Burn.Bundles
171 this.Facade.PackageSymbol.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames); 189 this.Facade.PackageSymbol.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames);
172 190
173 // Add all dependency providers from the MSI. 191 // Add all dependency providers from the MSI.
174 this.ImportDependencyProviders(msiPackage, db); 192 this.ImportDependencyProviders(db, msiPackage);
175 } 193 }
176 } 194 }
177 catch (Dtf.InstallerException e) 195 catch (MsiException e)
178 { 196 {
179 this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath, e.Message)); 197 this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath, e.Message));
180 } 198 }
@@ -196,7 +214,7 @@ namespace WixToolset.Core.Burn.Bundles
196 return new HashSet<string>(properties, StringComparer.Ordinal); 214 return new HashSet<string>(properties, StringComparer.Ordinal);
197 } 215 }
198 216
199 private void SetPerMachineAppropriately(Dtf.Database db, WixBundleMsiPackageSymbol msiPackage, string sourcePath) 217 private void SetPerMachineAppropriately(string allusers, WixBundleMsiPackageSymbol msiPackage, string sourcePath)
200 { 218 {
201 if (msiPackage.ForcePerMachine) 219 if (msiPackage.ForcePerMachine)
202 { 220 {
@@ -211,8 +229,6 @@ namespace WixToolset.Core.Burn.Bundles
211 } 229 }
212 else 230 else
213 { 231 {
214 var allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS");
215
216 if (String.IsNullOrEmpty(allusers)) 232 if (String.IsNullOrEmpty(allusers))
217 { 233 {
218 // Not forced per-machine and no ALLUSERS property, flip back to per-user. 234 // Not forced per-machine and no ALLUSERS property, flip back to per-user.
@@ -240,269 +256,219 @@ namespace WixToolset.Core.Burn.Bundles
240 } 256 }
241 } 257 }
242 258
243 private void SetPackageVisibility(Dtf.Database db, WixBundleMsiPackageSymbol msiPackage, ISet<string> msiPropertyNames) 259 private void SetPackageVisibility(string systemComponent, WixBundleMsiPackageSymbol msiPackage, ISet<string> msiPropertyNames)
244 { 260 {
245 var alreadyVisible = !ProcessMsiPackageCommand.HasProperty(db, "ARPSYSTEMCOMPONENT"); 261 // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again.
246 var visible = (this.Facade.PackageSymbol.Attributes & WixBundlePackageAttributes.Visible) == WixBundlePackageAttributes.Visible; 262 if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT"))
247
248 // If not already set to the correct visibility.
249 if (alreadyVisible != visible)
250 { 263 {
251 // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again. 264 var alreadyVisible = String.IsNullOrEmpty(systemComponent);
252 if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT")) 265 var visible = (this.Facade.PackageSymbol.Attributes & WixBundlePackageAttributes.Visible) == WixBundlePackageAttributes.Visible;
266
267 // If not already set to the correct visibility.
268 if (alreadyVisible != visible)
253 { 269 {
254 this.AddMsiProperty(msiPackage, "ARPSYSTEMCOMPONENT", visible ? String.Empty : "1"); 270 this.AddMsiProperty(msiPackage, "ARPSYSTEMCOMPONENT", visible ? String.Empty : "1");
255 } 271 }
256 } 272 }
257 } 273 }
258 274
259 private void CreateRelatedPackages(Dtf.Database db) 275 private void CreateRelatedPackages(Database db)
260 { 276 {
261 // Represent the Upgrade table as related packages. 277 // Represent the Upgrade table as related packages.
262 if (db.Tables.Contains("Upgrade")) 278 if (db.TableExists("Upgrade"))
263 { 279 {
264 using (var view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`")) 280 using (var view = db.OpenExecuteView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`"))
265 { 281 {
266 view.Execute(); 282 foreach (var record in view.Records)
267 while (true)
268 { 283 {
269 using (var record = view.Fetch()) 284 var recordAttributes = record.GetInteger(5);
270 {
271 if (null == record)
272 {
273 break;
274 }
275 285
276 var recordAttributes = record.GetInteger(5); 286 var attributes = WixBundleRelatedPackageAttributes.None;
287 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect ? WixBundleRelatedPackageAttributes.OnlyDetect : 0;
288 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive ? WixBundleRelatedPackageAttributes.MinInclusive : 0;
289 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive ? WixBundleRelatedPackageAttributes.MaxInclusive : 0;
290 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive ? WixBundleRelatedPackageAttributes.LangInclusive : 0;
277 291
278 var attributes = WixBundleRelatedPackageAttributes.None; 292 this.Section.AddSymbol(new WixBundleRelatedPackageSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
279 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect ? WixBundleRelatedPackageAttributes.OnlyDetect : 0; 293 {
280 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive ? WixBundleRelatedPackageAttributes.MinInclusive : 0; 294 PackageRef = this.Facade.PackageId,
281 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive ? WixBundleRelatedPackageAttributes.MaxInclusive : 0; 295 RelatedId = record.GetString(1),
282 attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive ? WixBundleRelatedPackageAttributes.LangInclusive : 0; 296 MinVersion = record.GetString(2),
283 297 MaxVersion = record.GetString(3),
284 this.Section.AddSymbol(new WixBundleRelatedPackageSymbol(this.Facade.PackageSymbol.SourceLineNumbers) 298 Languages = record.GetString(4),
285 { 299 Attributes = attributes,
286 PackageRef = this.Facade.PackageId, 300 });
287 RelatedId = record.GetString(1),
288 MinVersion = record.GetString(2),
289 MaxVersion = record.GetString(3),
290 Languages = record.GetString(4),
291 Attributes = attributes,
292 });
293 }
294 } 301 }
295 } 302 }
296 } 303 }
297 } 304 }
298 305
299 private void CreateMsiFeatures(Dtf.Database db) 306 private void CreateMsiFeatures(Database db)
300 { 307 {
301 if (db.Tables.Contains("Feature")) 308 if (db.TableExists("Feature"))
302 { 309 {
310 using (var allFeaturesView = db.OpenExecuteView("SELECT * FROM `Feature`"))
303 using (var featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?")) 311 using (var featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"))
304 using (var componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?")) 312 using (var componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?"))
305 { 313 {
306 using (var featureRecord = new Dtf.Record(1)) 314 using (var featureRecord = new Record(1))
307 using (var componentRecord = new Dtf.Record(1)) 315 using (var componentRecord = new Record(1))
308 { 316 {
309 using (var allFeaturesView = db.OpenView("SELECT * FROM `Feature`")) 317 foreach (var allFeaturesResultRecord in allFeaturesView.Records)
310 { 318 {
311 allFeaturesView.Execute(); 319 var featureName = allFeaturesResultRecord.GetString(1);
320
321 // Calculate the Feature size.
322 featureRecord.SetString(1, featureName);
323 featureView.Execute(featureRecord);
312 324
313 while (true) 325 // Loop over all the components for the feature to calculate the size of the feature.
326 long size = 0;
327 foreach (var componentResultRecord in featureView.Records)
314 { 328 {
315 using (var allFeaturesResultRecord = allFeaturesView.Fetch()) 329 var component = componentResultRecord.GetString(1);
330 componentRecord.SetString(1, component);
331 componentView.Execute(componentRecord);
332
333 foreach (var fileResultRecord in componentView.Records)
316 { 334 {
317 if (null == allFeaturesResultRecord) 335 var fileSize = fileResultRecord.GetString(1);
318 { 336 size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat);
319 break;
320 }
321
322 var featureName = allFeaturesResultRecord.GetString(1);
323
324 // Calculate the Feature size.
325 featureRecord.SetString(1, featureName);
326 featureView.Execute(featureRecord);
327
328 // Loop over all the components for the feature to calculate the size of the feature.
329 long size = 0;
330 while (true)
331 {
332 using (var componentResultRecord = featureView.Fetch())
333 {
334 if (null == componentResultRecord)
335 {
336 break;
337 }
338
339 var component = componentResultRecord.GetString(1);
340 componentRecord.SetString(1, component);
341 componentView.Execute(componentRecord);
342
343 while (true)
344 {
345 using (var fileResultRecord = componentView.Fetch())
346 {
347 if (null == fileResultRecord)
348 {
349 break;
350 }
351
352 var fileSize = fileResultRecord.GetString(1);
353 size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat);
354 }
355 }
356 }
357 }
358
359 this.Section.AddSymbol(new WixBundleMsiFeatureSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, this.Facade.PackageId, featureName))
360 {
361 PackageRef = this.Facade.PackageId,
362 Name = featureName,
363 Parent = allFeaturesResultRecord.GetString(2),
364 Title = allFeaturesResultRecord.GetString(3),
365 Description = allFeaturesResultRecord.GetString(4),
366 Display = allFeaturesResultRecord.GetInteger(5),
367 Level = allFeaturesResultRecord.GetInteger(6),
368 Directory = allFeaturesResultRecord.GetString(7),
369 Attributes = allFeaturesResultRecord.GetInteger(8),
370 Size = size
371 });
372 } 337 }
373 } 338 }
339
340 this.Section.AddSymbol(new WixBundleMsiFeatureSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, this.Facade.PackageId, featureName))
341 {
342 PackageRef = this.Facade.PackageId,
343 Name = featureName,
344 Parent = allFeaturesResultRecord.GetString(2),
345 Title = allFeaturesResultRecord.GetString(3),
346 Description = allFeaturesResultRecord.GetString(4),
347 Display = allFeaturesResultRecord.GetInteger(5),
348 Level = allFeaturesResultRecord.GetInteger(6),
349 Directory = allFeaturesResultRecord.GetString(7),
350 Attributes = allFeaturesResultRecord.GetInteger(8),
351 Size = size
352 });
374 } 353 }
375 } 354 }
376 } 355 }
377 } 356 }
378 } 357 }
379 358
380 private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadSymbol packagePayload, ISet<string> payloadNames) 359 private void ImportExternalCabinetAsPayloads(Database db, WixBundlePayloadSymbol packagePayload, ISet<string> payloadNames)
381 { 360 {
382 if (db.Tables.Contains("Media")) 361 if (db.TableExists("Media"))
383 { 362 {
384 foreach (var cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`")) 363 using (var view = db.OpenExecuteView("SELECT `Cabinet` FROM `Media`"))
385 { 364 {
386 if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal)) 365 foreach (var cabinetRecord in view.Records)
387 { 366 {
388 // If we didn't find the Payload as an existing child of the package, we need to 367 var cabinet = cabinetRecord.GetString(1);
389 // add it. We expect the file to exist on-disk in the same relative location as
390 // the MSI expects to find it...
391 var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet);
392 368
393 if (!payloadNames.Contains(cabinetName)) 369 if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal))
394 { 370 {
395 var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet); 371 // If we didn't find the Payload as an existing child of the package, we need to
396 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers); 372 // add it. We expect the file to exist on-disk in the same relative location as
373 // the MSI expects to find it...
374 var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet);
397 375
398 this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers) 376 if (!payloadNames.Contains(cabinetName))
399 { 377 {
400 ParentType = ComplexReferenceParentType.Package, 378 var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet);
401 ParentId = this.Facade.PackageId, 379 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers);
402 ChildType = ComplexReferenceChildType.Payload,
403 ChildId = generatedId
404 });
405 380
406 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) 381 this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
407 { 382 {
408 Name = cabinetName, 383 ParentType = ComplexReferenceParentType.Package,
409 SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, 384 ParentId = this.Facade.PackageId,
410 Compressed = packagePayload.Compressed, 385 ChildType = ComplexReferenceChildType.Payload,
411 UnresolvedSourceFile = cabinetName, 386 ChildId = generatedId
412 ContainerRef = packagePayload.ContainerRef, 387 });
413 ContentFile = true, 388
414 Packaging = packagePayload.Packaging, 389 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
415 ParentPackagePayloadRef = packagePayload.Id.Id, 390 {
416 }); 391 Name = cabinetName,
392 SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
393 Compressed = packagePayload.Compressed,
394 UnresolvedSourceFile = cabinetName,
395 ContainerRef = packagePayload.ContainerRef,
396 ContentFile = true,
397 Packaging = packagePayload.Packaging,
398 ParentPackagePayloadRef = packagePayload.Id.Id,
399 });
400 }
417 } 401 }
418 } 402 }
419 } 403 }
420 } 404 }
421 } 405 }
422 406
423 private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadSymbol packagePayload, bool longNamesInImage, bool compressed, ISet<string> payloadNames) 407 private long ImportExternalFileAsPayloadsAndReturnInstallSize(Database db, WixBundlePayloadSymbol packagePayload, bool longNamesInImage, bool compressed, ISet<string> payloadNames)
424 { 408 {
425 long size = 0; 409 long size = 0;
426 410
427 if (db.Tables.Contains("Component") && db.Tables.Contains("Directory") && db.Tables.Contains("File")) 411 if (db.TableExists("Component") && db.TableExists("Directory") && db.TableExists("File"))
428 { 412 {
429 var directories = new Dictionary<string, IResolvedDirectory>(); 413 var directories = new Dictionary<string, IResolvedDirectory>();
430 414
431 // Load up the directory hash table so we will be able to resolve source paths 415 // Load up the directory hash table so we will be able to resolve source paths
432 // for files in the MSI database. 416 // for files in the MSI database.
433 using (var view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) 417 using (var view = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
434 { 418 {
435 view.Execute(); 419 foreach (var record in view.Records)
436 while (true)
437 { 420 {
438 using (var record = view.Fetch()) 421 var sourceName = this.BackendHelper.GetMsiFileName(record.GetString(3), true, longNamesInImage);
439 {
440 if (null == record)
441 {
442 break;
443 }
444 422
445 var sourceName = this.BackendHelper.GetMsiFileName(record.GetString(3), true, longNamesInImage); 423 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName);
446 424
447 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName); 425 directories.Add(record.GetString(1), resolvedDirectory);
448
449 directories.Add(record.GetString(1), resolvedDirectory);
450 }
451 } 426 }
452 } 427 }
453 428
454 // Resolve the source paths to external files and add each file size to the total 429 // Resolve the source paths to external files and add each file size to the total
455 // install size of the package. 430 // install size of the package.
456 using (var view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`")) 431 using (var view = db.OpenExecuteView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`"))
457 { 432 {
458 view.Execute(); 433 foreach (var record in view.Records)
459 while (true)
460 { 434 {
461 using (var record = view.Fetch()) 435 // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not
436 // explicitly marked compressed then this is an external file.
437 var compressionBit = record.GetInteger(4);
438 if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) ||
439 (!compressed && 0 == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesCompressed)))
462 { 440 {
463 if (null == record) 441 var fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
464 { 442 var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath);
465 break;
466 }
467 443
468 // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not 444 if (!payloadNames.Contains(name))
469 // explicitly marked compressed then this is an external file.
470 var compressionBit = record.GetInteger(4);
471 if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) ||
472 (!compressed && 0 == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesCompressed)))
473 { 445 {
474 var fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage); 446 var generatedId = this.BackendHelper.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2));
475 var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath); 447 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers);
476 448
477 if (!payloadNames.Contains(name)) 449 this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
478 { 450 {
479 var generatedId = this.BackendHelper.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2)); 451 ParentType = ComplexReferenceParentType.Package,
480 var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers); 452 ParentId = this.Facade.PackageId,
481 453 ChildType = ComplexReferenceChildType.Payload,
482 this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers) 454 ChildId = generatedId
483 { 455 });
484 ParentType = ComplexReferenceParentType.Package,
485 ParentId = this.Facade.PackageId,
486 ChildType = ComplexReferenceChildType.Payload,
487 ChildId = generatedId
488 });
489
490 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
491 {
492 Name = name,
493 SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
494 Compressed = packagePayload.Compressed,
495 UnresolvedSourceFile = name,
496 ContainerRef = packagePayload.ContainerRef,
497 ContentFile = true,
498 Packaging = packagePayload.Packaging,
499 ParentPackagePayloadRef = packagePayload.Id.Id,
500 });
501 }
502 }
503 456
504 size += record.GetInteger(5); 457 this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
458 {
459 Name = name,
460 SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
461 Compressed = packagePayload.Compressed,
462 UnresolvedSourceFile = name,
463 ContainerRef = packagePayload.ContainerRef,
464 ContentFile = true,
465 Packaging = packagePayload.Packaging,
466 ParentPackagePayloadRef = packagePayload.Id.Id,
467 });
468 }
505 } 469 }
470
471 size += record.GetInteger(5);
506 } 472 }
507 } 473 }
508 } 474 }
@@ -520,36 +486,25 @@ namespace WixToolset.Core.Burn.Bundles
520 }); 486 });
521 } 487 }
522 488
523 private void ImportDependencyProviders(WixBundleMsiPackageSymbol msiPackage, Dtf.Database db) 489 private void ImportDependencyProviders(Database db, WixBundleMsiPackageSymbol msiPackage)
524 { 490 {
525 if (db.Tables.Contains("WixDependencyProvider")) 491 if (db.TableExists("WixDependencyProvider"))
526 { 492 {
527 var query = "SELECT `WixDependencyProvider`, `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`"; 493 using (var view = db.OpenExecuteView("SELECT `WixDependencyProvider`, `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`"))
528
529 using (var view = db.OpenView(query))
530 { 494 {
531 view.Execute(); 495 foreach (var record in view.Records)
532 while (true)
533 { 496 {
534 using (var record = view.Fetch()) 497 var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1)));
535 {
536 if (null == record)
537 {
538 break;
539 }
540 498
541 var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1))); 499 // Import the provider key and attributes.
542 500 this.Section.AddSymbol(new WixDependencyProviderSymbol(msiPackage.SourceLineNumbers, id)
543 // Import the provider key and attributes. 501 {
544 this.Section.AddSymbol(new WixDependencyProviderSymbol(msiPackage.SourceLineNumbers, id) 502 ParentRef = msiPackage.Id.Id,
545 { 503 ProviderKey = record.GetString(2),
546 ParentRef = msiPackage.Id.Id, 504 Version = record.GetString(3) ?? msiPackage.ProductVersion,
547 ProviderKey = record.GetString(2), 505 DisplayName = record.GetString(4) ?? this.Facade.PackageSymbol.DisplayName,
548 Version = record.GetString(3) ?? msiPackage.ProductVersion, 506 Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)record.GetInteger(5),
549 DisplayName = record.GetString(4) ?? this.Facade.PackageSymbol.DisplayName, 507 });
550 Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)record.GetInteger(5),
551 });
552 }
553 } 508 }
554 } 509 }
555 } 510 }
@@ -585,51 +540,19 @@ namespace WixToolset.Core.Burn.Bundles
585 return resolvedPath; 540 return resolvedPath;
586 } 541 }
587 542
588 /// <summary> 543 private static string GetProperty(View view, string property)
589 /// Queries a Windows Installer database for a Property value.
590 /// </summary>
591 /// <param name="db">Database to query.</param>
592 /// <param name="property">Property to examine.</param>
593 /// <returns>String value for result or null if query doesn't match a single result.</returns>
594 private static string GetProperty(Dtf.Database db, string property)
595 { 544 {
596 try 545 using (var queryRecord = new Record(1))
597 {
598 return db.ExecuteScalar(PropertyQuery(property)).ToString();
599 }
600 catch (Dtf.InstallerException)
601 { 546 {
602 } 547 queryRecord[1] = property;
603 548
604 return null; 549 view.Execute(queryRecord);
605 }
606 550
607 /// <summary> 551 using (var record = view.Fetch())
608 /// Queries a Windows Installer database to determine if one or more rows exist in the Property table. 552 {
609 /// </summary> 553 return record?.GetString(1);
610 /// <param name="db">Database to query.</param> 554 }
611 /// <param name="property">Property to examine.</param>
612 /// <returns>True if query matches at least one result.</returns>
613 private static bool HasProperty(Dtf.Database db, string property)
614 {
615 try
616 {
617 return 0 < db.ExecuteQuery(PropertyQuery(property)).Count;
618 }
619 catch (Dtf.InstallerException)
620 {
621 } 555 }
622
623 return false;
624 }
625
626 private static string PropertyQuery(string property)
627 {
628 // quick sanity check that we'll be creating a valid query...
629 // TODO: Are there any other special characters we should be looking for?
630 Debug.Assert(!property.Contains("'"));
631
632 return String.Format(CultureInfo.InvariantCulture, ProcessMsiPackageCommand.PropertySqlFormat, property);
633 } 556 }
634 } 557 }
635} 558}
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
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Globalization;
9 using System.IO; 7 using System.IO;
10 using System.Text; 8 using System.Text;
11 using System.Xml; 9 using System.Xml;
10 using WixToolset.Core.Native.Msi;
12 using WixToolset.Data; 11 using WixToolset.Data;
13 using WixToolset.Data.Symbols; 12 using WixToolset.Data.Symbols;
14 using WixToolset.Extensibility.Services; 13 using WixToolset.Extensibility.Services;
15 using Dtf = WixToolset.Dtf.WindowsInstaller;
16 14
17 /// <summary> 15 /// <summary>
18 /// Initializes package state from the Msp contents. 16 /// Initializes package state from the Msp contents.
19 /// </summary> 17 /// </summary>
20 internal class ProcessMspPackageCommand 18 internal class ProcessMspPackageCommand
21 { 19 {
22 private const string PatchMetadataFormat = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = '{0}'"; 20 private const string PatchMetadataQuery = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = ?";
23 private static readonly Encoding XmlOutputEncoding = new UTF8Encoding(false); 21 private static readonly XmlWriterSettings XmlSettings = new XmlWriterSettings()
22 {
23 Encoding = new UTF8Encoding(false),
24 Indent = false,
25 NewLineChars = String.Empty,
26 NewLineHandling = NewLineHandling.Replace,
27 };
24 28
25 public ProcessMspPackageCommand(IMessaging messaging, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> payloadSymbols) 29 public ProcessMspPackageCommand(IMessaging messaging, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> payloadSymbols)
26 { 30 {
@@ -52,30 +56,34 @@ namespace WixToolset.Core.Burn.Bundles
52 56
53 try 57 try
54 { 58 {
55 // Read data out of the msp database... 59 using (var db = new Database(sourcePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile))
56 using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
57 {
58 mspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38);
59 }
60
61 using (var db = new Dtf.Database(sourcePath))
62 { 60 {
63 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName)) 61 // Read data out of the msp database...
62 using (var sumInfo = new SummaryInformation(db))
64 { 63 {
65 this.Facade.PackageSymbol.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName"); 64 var patchCode = sumInfo.GetProperty(SummaryInformation.Patch.PatchCode);
65 mspPackage.PatchCode = patchCode.Substring(0, 38);
66 } 66 }
67 67
68 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description)) 68 using (var view = db.OpenView(PatchMetadataQuery))
69 { 69 {
70 this.Facade.PackageSymbol.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description"); 70 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName))
71 } 71 {
72 this.Facade.PackageSymbol.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(view, "DisplayName");
73 }
74
75 if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description))
76 {
77 this.Facade.PackageSymbol.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(view, "Description");
78 }
72 79
73 mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName"); 80 mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(view, "ManufacturerName");
81 }
74 } 82 }
75 83
76 this.ProcessPatchXml(packagePayload, mspPackage, sourcePath); 84 this.ProcessPatchXml(packagePayload, mspPackage, sourcePath);
77 } 85 }
78 catch (Dtf.InstallerException e) 86 catch (MsiException e)
79 { 87 {
80 this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message)); 88 this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
81 return; 89 return;
@@ -91,7 +99,7 @@ namespace WixToolset.Core.Burn.Bundles
91 { 99 {
92 var uniqueTargetCodes = new HashSet<string>(); 100 var uniqueTargetCodes = new HashSet<string>();
93 101
94 var patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath); 102 var patchXml = Installer.ExtractPatchXml(sourcePath);
95 103
96 var doc = new XmlDocument(); 104 var doc = new XmlDocument();
97 doc.LoadXml(patchXml); 105 doc.LoadXml(patchXml);
@@ -146,15 +154,7 @@ namespace WixToolset.Core.Burn.Bundles
146 // Save the XML as compact as possible. 154 // Save the XML as compact as possible.
147 using (var writer = new StringWriter()) 155 using (var writer = new StringWriter())
148 { 156 {
149 var settings = new XmlWriterSettings() 157 using (var xmlWriter = XmlWriter.Create(writer, XmlSettings))
150 {
151 Encoding = ProcessMspPackageCommand.XmlOutputEncoding,
152 Indent = false,
153 NewLineChars = String.Empty,
154 NewLineHandling = NewLineHandling.Replace,
155 };
156
157 using (var xmlWriter = XmlWriter.Create(writer, settings))
158 { 158 {
159 doc.WriteTo(xmlWriter); 159 doc.WriteTo(xmlWriter);
160 } 160 }
@@ -163,32 +163,19 @@ namespace WixToolset.Core.Burn.Bundles
163 } 163 }
164 } 164 }
165 165
166 /// <summary> 166 private static string GetPatchMetadataProperty(View view, string property)
167 /// Queries a Windows Installer patch database for a Property value from the MsiPatchMetadata table.
168 /// </summary>
169 /// <param name="db">Database to query.</param>
170 /// <param name="property">Property to examine.</param>
171 /// <returns>String value for result or null if query doesn't match a single result.</returns>
172 private static string GetPatchMetadataProperty(Dtf.Database db, string property)
173 { 167 {
174 try 168 using (var queryRecord = new Record(1))
175 {
176 return db.ExecuteScalar(PatchMetadataPropertyQuery(property)).ToString();
177 }
178 catch (Dtf.InstallerException)
179 { 169 {
180 } 170 queryRecord[1] = property;
181
182 return null;
183 }
184 171
185 private static string PatchMetadataPropertyQuery(string property) 172 view.Execute(queryRecord);
186 {
187 // quick sanity check that we'll be creating a valid query...
188 // TODO: Are there any other special characters we should be looking for?
189 Debug.Assert(!property.Contains("'"));
190 173
191 return String.Format(CultureInfo.InvariantCulture, ProcessMspPackageCommand.PatchMetadataFormat, property); 174 using (var record = view.Fetch())
175 {
176 return record?.GetString(1);
177 }
178 }
192 } 179 }
193 180
194 private static bool TargetsCode(XmlNode node) => "true" == node?.Attributes["Validate"]?.Value; 181 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 @@
27 <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" /> 27 <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
28 <PackageReference Include="WixToolset.Data" Version="4.0.*" /> 28 <PackageReference Include="WixToolset.Data" Version="4.0.*" />
29 <PackageReference Include="WixToolset.Dtf.Resources" Version="4.0.*" /> 29 <PackageReference Include="WixToolset.Dtf.Resources" Version="4.0.*" />
30 <PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" />
31 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" /> 30 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" />
32 </ItemGroup> 31 </ItemGroup>
33 32
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 @@
15 <ItemGroup> 15 <ItemGroup>
16 <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" /> 16 <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
17 <PackageReference Include="WixToolset.Data" Version="4.0.*" /> 17 <PackageReference Include="WixToolset.Data" Version="4.0.*" />
18 <PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" />
19 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" /> 18 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" />
20 </ItemGroup> 19 </ItemGroup>
21 20