Remove dependency on Dtf.WindowsInstaller from Core
Rob Mensching committed
Mar 25, 2021 at 10:00 UTC
3dc92067f57e3803d4e1bac6d055e2a23f797414
5 files changed
+257
-358
src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs
+6
-15
@@ -8,9 +8,9 @@ namespace WixToolset.Core.Burn.Bind
8
using System.Linq;
9
using System.Text;
10
using System.Xml;
11
+ using WixToolset.Core.Native.Msi;
12
using WixToolset.Data;
13
using WixToolset.Data.Symbols;
13
- using WixToolset.Dtf.WindowsInstaller;
14
15
internal class ProcessBundleSoftwareTagsCommand
16
{
@@ -69,22 +69,13 @@ namespace WixToolset.Core.Burn.Bind
69
{
70
var payload = payloadSymbolsById[msiPackage.PayloadRef];
71
72
- using (var db = new Database(payload.SourceFile.Path))
72
+ using (var db = new Database(payload.SourceFile.Path, OpenDatabase.ReadOnly))
73
{
74
- using (var view = db.OpenView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`"))
74
+ using (var view = db.OpenExecuteView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`"))
75
{
76
- view.Execute();
77
- while (true)
76
+ foreach (var record in view.Records)
77
{
79
- using (var record = view.Fetch())
80
- {
81
- if (null == record)
82
- {
83
- break;
84
- }
85
-
86
- tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) });
87
- }
78
+ tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) });
79
}
80
}
81
}
@@ -98,7 +89,7 @@ namespace WixToolset.Core.Burn.Bind
89
{
90
var versionScheme = Version.TryParse(version, out _) ? "multipartnumeric" : "alphanumeric";
91
101
- using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true}))
92
+ using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true }))
93
{
94
writer.WriteStartDocument();
95
writer.WriteStartElement("SoftwareIdentity", "http://standards.iso.org/iso/19770/-2/2015/schema.xsd");
src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+213
-290
@@ -4,24 +4,23 @@ namespace WixToolset.Core.Burn.Bundles
4
{
5
using System;
6
using System.Collections.Generic;
7
- using System.Diagnostics;
7
using System.Globalization;
8
using System.IO;
9
using System.Linq;
10
using WixToolset.Data;
11
using WixToolset.Extensibility;
13
- using Dtf = WixToolset.Dtf.WindowsInstaller;
12
using WixToolset.Extensibility.Services;
13
using WixToolset.Data.Symbols;
14
using WixToolset.Data.WindowsInstaller;
15
using WixToolset.Extensibility.Data;
16
+ using WixToolset.Core.Native.Msi;
17
18
/// <summary>
19
/// Initializes package state from the MSI contents.
20
/// </summary>
21
internal class ProcessMsiPackageCommand
22
{
24
- private const string PropertySqlFormat = "SELECT `Value` FROM `Property` WHERE `Property` = '{0}'";
23
+ private const string PropertySqlQuery = "SELECT `Value` FROM `Property` WHERE `Property` = ?";
24
25
public ProcessMsiPackageCommand(IServiceProvider serviceProvider, IEnumerable<IBurnBackendBinderExtension> backendExtensions, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> packagePayloads)
26
{
@@ -64,41 +63,60 @@ namespace WixToolset.Core.Burn.Bundles
63
var compressed = false;
64
try
65
{
67
- // Read data out of the msi database...
68
- using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
66
+ using (var db = new Database(sourcePath, OpenDatabase.ReadOnly))
67
{
70
- // 1 is the Word Count summary information stream bit that means
71
- // the MSI uses short file names when set. We care about long file
72
- // names so check when the bit is not set.
73
- longNamesInImage = 0 == (sumInfo.WordCount & 1);
74
-
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
- }
68
+ // Read data out of the msi database...
69
+ using (var sumInfo = new SummaryInformation(db))
70
+ {
71
+ var fileAndElevateFlags = sumInfo.GetNumericProperty(SummaryInformation.Package.FileAndElevatedFlags);
72
+ var platformsAndLanguages = sumInfo.GetProperty(SummaryInformation.Package.PlatformsAndLanguages);
73
89
- using (var db = new Dtf.Database(sourcePath))
90
- {
91
- msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode");
92
- msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode");
93
- msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer");
94
- msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture);
95
- msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion");
74
+ // 1 is the Word Count summary information stream bit that means
75
+ // the MSI uses short file names when set. We care about long file
76
+ // names so check when the bit is not set.
77
+
78
+ longNamesInImage = 0 == (fileAndElevateFlags & 1);
79
+
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
+ }
114
115
if (!this.BackendHelper.IsValidFourPartVersion(msiPackage.ProductVersion))
116
{
117
// not a proper .NET version (e.g., five fields); can we get a valid four-part version number?
118
string version = null;
101
- string[] versionParts = msiPackage.ProductVersion.Split('.');
119
+ var versionParts = msiPackage.ProductVersion.Split('.');
120
var count = versionParts.Length;
121
if (0 < count)
122
{
@@ -127,12 +145,12 @@ namespace WixToolset.Core.Burn.Bundles
145
146
if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName))
147
{
130
- this.Facade.PackageSymbol.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName");
148
+ this.Facade.PackageSymbol.DisplayName = packageName;
149
}
150
151
if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description))
152
{
135
- this.Facade.PackageSymbol.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS");
153
+ this.Facade.PackageSymbol.Description = packageDescription;
154
}
155
156
if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Version))
@@ -144,13 +162,13 @@ namespace WixToolset.Core.Burn.Bundles
162
163
var msiPropertyNames = this.GetMsiPropertyNames(packagePayload.Id.Id);
164
147
- this.SetPerMachineAppropriately(db, msiPackage, sourcePath);
165
+ this.SetPerMachineAppropriately(allusers, msiPackage, sourcePath);
166
167
// Ensure the MSI package is appropriately marked visible or not.
150
- this.SetPackageVisibility(db, msiPackage, msiPropertyNames);
168
+ this.SetPackageVisibility(systemComponent, msiPackage, msiPropertyNames);
169
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))
172
{
173
this.AddMsiProperty(msiPackage, "MSIFASTINSTALL", "7");
174
}
@@ -171,10 +189,10 @@ namespace WixToolset.Core.Burn.Bundles
189
this.Facade.PackageSymbol.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames);
190
191
// Add all dependency providers from the MSI.
174
- this.ImportDependencyProviders(msiPackage, db);
192
+ this.ImportDependencyProviders(db, msiPackage);
193
}
194
}
177
- catch (Dtf.InstallerException e)
195
+ catch (MsiException e)
196
{
197
this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath, e.Message));
198
}
@@ -196,7 +214,7 @@ namespace WixToolset.Core.Burn.Bundles
214
return new HashSet<string>(properties, StringComparer.Ordinal);
215
}
216
199
- private void SetPerMachineAppropriately(Dtf.Database db, WixBundleMsiPackageSymbol msiPackage, string sourcePath)
217
+ private void SetPerMachineAppropriately(string allusers, WixBundleMsiPackageSymbol msiPackage, string sourcePath)
218
{
219
if (msiPackage.ForcePerMachine)
220
{
@@ -211,8 +229,6 @@ namespace WixToolset.Core.Burn.Bundles
229
}
230
else
231
{
214
- var allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS");
215
-
232
if (String.IsNullOrEmpty(allusers))
233
{
234
// Not forced per-machine and no ALLUSERS property, flip back to per-user.
@@ -240,269 +256,219 @@ namespace WixToolset.Core.Burn.Bundles
256
}
257
}
258
243
- private void SetPackageVisibility(Dtf.Database db, WixBundleMsiPackageSymbol msiPackage, ISet<string> msiPropertyNames)
259
+ private void SetPackageVisibility(string systemComponent, WixBundleMsiPackageSymbol msiPackage, ISet<string> msiPropertyNames)
260
{
245
- var alreadyVisible = !ProcessMsiPackageCommand.HasProperty(db, "ARPSYSTEMCOMPONENT");
246
- var visible = (this.Facade.PackageSymbol.Attributes & WixBundlePackageAttributes.Visible) == WixBundlePackageAttributes.Visible;
247
-
248
- // If not already set to the correct visibility.
249
- if (alreadyVisible != visible)
261
+ // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again.
262
+ if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT"))
263
{
251
- // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again.
252
- if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT"))
264
+ var alreadyVisible = String.IsNullOrEmpty(systemComponent);
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)
269
{
270
this.AddMsiProperty(msiPackage, "ARPSYSTEMCOMPONENT", visible ? String.Empty : "1");
271
}
272
}
273
}
274
259
- private void CreateRelatedPackages(Dtf.Database db)
275
+ private void CreateRelatedPackages(Database db)
276
{
277
// Represent the Upgrade table as related packages.
262
- if (db.Tables.Contains("Upgrade"))
278
+ if (db.TableExists("Upgrade"))
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`"))
281
{
266
- view.Execute();
267
- while (true)
282
+ foreach (var record in view.Records)
283
{
269
- using (var record = view.Fetch())
270
- {
271
- if (null == record)
272
- {
273
- break;
274
- }
284
+ var recordAttributes = record.GetInteger(5);
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;
291
278
- var attributes = WixBundleRelatedPackageAttributes.None;
279
- attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect ? WixBundleRelatedPackageAttributes.OnlyDetect : 0;
280
- attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive ? WixBundleRelatedPackageAttributes.MinInclusive : 0;
281
- attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive ? WixBundleRelatedPackageAttributes.MaxInclusive : 0;
282
- attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive ? WixBundleRelatedPackageAttributes.LangInclusive : 0;
283
-
284
- this.Section.AddSymbol(new WixBundleRelatedPackageSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
285
- {
286
- PackageRef = this.Facade.PackageId,
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
- }
292
+ this.Section.AddSymbol(new WixBundleRelatedPackageSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
293
+ {
294
+ PackageRef = this.Facade.PackageId,
295
+ RelatedId = record.GetString(1),
296
+ MinVersion = record.GetString(2),
297
+ MaxVersion = record.GetString(3),
298
+ Languages = record.GetString(4),
299
+ Attributes = attributes,
300
+ });
301
}
302
}
303
}
304
}
305
299
- private void CreateMsiFeatures(Dtf.Database db)
306
+ private void CreateMsiFeatures(Database db)
307
{
301
- if (db.Tables.Contains("Feature"))
308
+ if (db.TableExists("Feature"))
309
{
310
+ using (var allFeaturesView = db.OpenExecuteView("SELECT * FROM `Feature`"))
311
using (var featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"))
312
using (var componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?"))
313
{
306
- using (var featureRecord = new Dtf.Record(1))
307
- using (var componentRecord = new Dtf.Record(1))
314
+ using (var featureRecord = new Record(1))
315
+ using (var componentRecord = new Record(1))
316
{
309
- using (var allFeaturesView = db.OpenView("SELECT * FROM `Feature`"))
317
+ foreach (var allFeaturesResultRecord in allFeaturesView.Records)
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);
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)
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)
334
{
317
- if (null == allFeaturesResultRecord)
318
- {
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
- });
335
+ var fileSize = fileResultRecord.GetString(1);
336
+ size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat);
337
}
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
+ });
353
}
354
}
355
}
356
}
357
}
358
380
- private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadSymbol packagePayload, ISet<string> payloadNames)
359
+ private void ImportExternalCabinetAsPayloads(Database db, WixBundlePayloadSymbol packagePayload, ISet<string> payloadNames)
360
{
382
- if (db.Tables.Contains("Media"))
361
+ if (db.TableExists("Media"))
362
{
384
- foreach (var cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`"))
363
+ using (var view = db.OpenExecuteView("SELECT `Cabinet` FROM `Media`"))
364
{
386
- if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal))
365
+ foreach (var cabinetRecord in view.Records)
366
{
388
- // If we didn't find the Payload as an existing child of the package, we need to
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);
367
+ var cabinet = cabinetRecord.GetString(1);
368
393
- if (!payloadNames.Contains(cabinetName))
369
+ if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal))
370
{
395
- var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet);
396
- var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers);
371
+ // If we didn't find the Payload as an existing child of the package, we need to
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);
375
398
- this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
376
+ if (!payloadNames.Contains(cabinetName))
377
{
400
- ParentType = ComplexReferenceParentType.Package,
401
- ParentId = this.Facade.PackageId,
402
- ChildType = ComplexReferenceChildType.Payload,
403
- ChildId = generatedId
404
- });
378
+ var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet);
379
+ var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers);
380
406
- this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
407
- {
408
- Name = cabinetName,
409
- SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
410
- Compressed = packagePayload.Compressed,
411
- UnresolvedSourceFile = cabinetName,
412
- ContainerRef = packagePayload.ContainerRef,
413
- ContentFile = true,
414
- Packaging = packagePayload.Packaging,
415
- ParentPackagePayloadRef = packagePayload.Id.Id,
416
- });
381
+ this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
382
+ {
383
+ ParentType = ComplexReferenceParentType.Package,
384
+ ParentId = this.Facade.PackageId,
385
+ ChildType = ComplexReferenceChildType.Payload,
386
+ ChildId = generatedId
387
+ });
388
+
389
+ this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
390
+ {
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
+ }
401
}
402
}
403
}
404
}
405
}
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)
408
{
409
long size = 0;
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"))
412
{
413
var directories = new Dictionary<string, IResolvedDirectory>();
414
415
// Load up the directory hash table so we will be able to resolve source paths
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`"))
418
{
435
- view.Execute();
436
- while (true)
419
+ foreach (var record in view.Records)
420
{
438
- using (var record = view.Fetch())
439
- {
440
- if (null == record)
441
- {
442
- break;
443
- }
421
+ var sourceName = this.BackendHelper.GetMsiFileName(record.GetString(3), true, longNamesInImage);
422
445
- var sourceName = this.BackendHelper.GetMsiFileName(record.GetString(3), true, longNamesInImage);
423
+ var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName);
424
447
- var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName);
448
-
449
- directories.Add(record.GetString(1), resolvedDirectory);
450
- }
425
+ directories.Add(record.GetString(1), resolvedDirectory);
426
}
427
}
428
429
// Resolve the source paths to external files and add each file size to the total
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_`"))
432
{
458
- view.Execute();
459
- while (true)
433
+ foreach (var record in view.Records)
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)))
440
{
463
- if (null == record)
464
- {
465
- break;
466
- }
441
+ var fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
442
+ var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath);
443
468
- // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not
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)))
444
+ if (!payloadNames.Contains(name))
445
{
474
- var fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
475
- var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath);
446
+ var generatedId = this.BackendHelper.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2));
447
+ var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers);
448
477
- if (!payloadNames.Contains(name))
449
+ this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
450
{
479
- var generatedId = this.BackendHelper.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2));
480
- var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers);
481
-
482
- this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers)
483
- {
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
- }
451
+ ParentType = ComplexReferenceParentType.Package,
452
+ ParentId = this.Facade.PackageId,
453
+ ChildType = ComplexReferenceChildType.Payload,
454
+ ChildId = generatedId
455
+ });
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
+ }
469
}
470
+
471
+ size += record.GetInteger(5);
472
}
473
}
474
}
@@ -520,36 +486,25 @@ namespace WixToolset.Core.Burn.Bundles
486
});
487
}
488
523
- private void ImportDependencyProviders(WixBundleMsiPackageSymbol msiPackage, Dtf.Database db)
489
+ private void ImportDependencyProviders(Database db, WixBundleMsiPackageSymbol msiPackage)
490
{
525
- if (db.Tables.Contains("WixDependencyProvider"))
491
+ if (db.TableExists("WixDependencyProvider"))
492
{
527
- var query = "SELECT `WixDependencyProvider`, `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`";
528
-
529
- using (var view = db.OpenView(query))
493
+ using (var view = db.OpenExecuteView("SELECT `WixDependencyProvider`, `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`"))
494
{
531
- view.Execute();
532
- while (true)
495
+ foreach (var record in view.Records)
496
{
534
- using (var record = view.Fetch())
535
- {
536
- if (null == record)
537
- {
538
- break;
539
- }
497
+ var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1)));
498
541
- var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", msiPackage.Id.Id, record.GetString(1)));
542
-
543
- // Import the provider key and attributes.
544
- this.Section.AddSymbol(new WixDependencyProviderSymbol(msiPackage.SourceLineNumbers, id)
545
- {
546
- ParentRef = msiPackage.Id.Id,
547
- ProviderKey = record.GetString(2),
548
- Version = record.GetString(3) ?? msiPackage.ProductVersion,
549
- DisplayName = record.GetString(4) ?? this.Facade.PackageSymbol.DisplayName,
550
- Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)record.GetInteger(5),
551
- });
552
- }
499
+ // Import the provider key and attributes.
500
+ this.Section.AddSymbol(new WixDependencyProviderSymbol(msiPackage.SourceLineNumbers, id)
501
+ {
502
+ ParentRef = msiPackage.Id.Id,
503
+ ProviderKey = record.GetString(2),
504
+ Version = record.GetString(3) ?? msiPackage.ProductVersion,
505
+ DisplayName = record.GetString(4) ?? this.Facade.PackageSymbol.DisplayName,
506
+ Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)record.GetInteger(5),
507
+ });
508
}
509
}
510
}
@@ -585,51 +540,19 @@ namespace WixToolset.Core.Burn.Bundles
540
return resolvedPath;
541
}
542
588
- /// <summary>
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)
543
+ private static string GetProperty(View view, string property)
544
{
596
- try
597
- {
598
- return db.ExecuteScalar(PropertyQuery(property)).ToString();
599
- }
600
- catch (Dtf.InstallerException)
545
+ using (var queryRecord = new Record(1))
546
{
602
- }
547
+ queryRecord[1] = property;
548
604
- return null;
605
- }
549
+ view.Execute(queryRecord);
550
607
- /// <summary>
608
- /// Queries a Windows Installer database to determine if one or more rows exist in the Property table.
609
- /// </summary>
610
- /// <param name="db">Database to query.</param>
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
- {
551
+ using (var record = view.Fetch())
552
+ {
553
+ return record?.GetString(1);
554
+ }
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);
556
}
557
}
558
}
src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs
+38
-51
@@ -4,23 +4,27 @@ namespace WixToolset.Core.Burn.Bundles
4
{
5
using System;
6
using System.Collections.Generic;
7
- using System.Diagnostics;
8
- using System.Globalization;
7
using System.IO;
8
using System.Text;
9
using System.Xml;
10
+ using WixToolset.Core.Native.Msi;
11
using WixToolset.Data;
12
using WixToolset.Data.Symbols;
13
using WixToolset.Extensibility.Services;
15
- using Dtf = WixToolset.Dtf.WindowsInstaller;
14
15
/// <summary>
16
/// Initializes package state from the Msp contents.
17
/// </summary>
18
internal class ProcessMspPackageCommand
19
{
22
- private const string PatchMetadataFormat = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = '{0}'";
23
- private static readonly Encoding XmlOutputEncoding = new UTF8Encoding(false);
20
+ private const string PatchMetadataQuery = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = ?";
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
+ };
28
29
public ProcessMspPackageCommand(IMessaging messaging, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> payloadSymbols)
30
{
@@ -52,30 +56,34 @@ namespace WixToolset.Core.Burn.Bundles
56
57
try
58
{
55
- // Read data out of the msp database...
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))
59
+ using (var db = new Database(sourcePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile))
60
{
63
- if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName))
61
+ // Read data out of the msp database...
62
+ using (var sumInfo = new SummaryInformation(db))
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
}
67
68
- if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description))
68
+ using (var view = db.OpenView(PatchMetadataQuery))
69
{
70
- this.Facade.PackageSymbol.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description");
71
- }
70
+ if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName))
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
+ }
79
73
- mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName");
80
+ mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(view, "ManufacturerName");
81
+ }
82
}
83
84
this.ProcessPatchXml(packagePayload, mspPackage, sourcePath);
85
}
78
- catch (Dtf.InstallerException e)
86
+ catch (MsiException e)
87
{
88
this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
89
return;
@@ -91,7 +99,7 @@ namespace WixToolset.Core.Burn.Bundles
99
{
100
var uniqueTargetCodes = new HashSet<string>();
101
94
- var patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath);
102
+ var patchXml = Installer.ExtractPatchXml(sourcePath);
103
104
var doc = new XmlDocument();
105
doc.LoadXml(patchXml);
@@ -146,15 +154,7 @@ namespace WixToolset.Core.Burn.Bundles
154
// Save the XML as compact as possible.
155
using (var writer = new StringWriter())
156
{
149
- var settings = new XmlWriterSettings()
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))
157
+ using (var xmlWriter = XmlWriter.Create(writer, XmlSettings))
158
{
159
doc.WriteTo(xmlWriter);
160
}
@@ -163,32 +163,19 @@ namespace WixToolset.Core.Burn.Bundles
163
}
164
}
165
166
- /// <summary>
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)
166
+ private static string GetPatchMetadataProperty(View view, string property)
167
{
174
- try
175
- {
176
- return db.ExecuteScalar(PatchMetadataPropertyQuery(property)).ToString();
177
- }
178
- catch (Dtf.InstallerException)
168
+ using (var queryRecord = new Record(1))
169
{
180
- }
181
-
182
- return null;
183
- }
170
+ queryRecord[1] = property;
171
185
- private static string PatchMetadataPropertyQuery(string property)
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("'"));
172
+ view.Execute(queryRecord);
173
191
- return String.Format(CultureInfo.InvariantCulture, ProcessMspPackageCommand.PatchMetadataFormat, property);
174
+ using (var record = view.Fetch())
175
+ {
176
+ return record?.GetString(1);
177
+ }
178
+ }
179
}
180
181
private static bool TargetsCode(XmlNode node) => "true" == node?.Attributes["Validate"]?.Value;
src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj
-1
@@ -27,7 +27,6 @@
27
<PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
28
<PackageReference Include="WixToolset.Data" Version="4.0.*" />
29
<PackageReference Include="WixToolset.Dtf.Resources" Version="4.0.*" />
30
- <PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" />
30
<PackageReference Include="WixToolset.Extensibility" Version="4.0.*" />
31
</ItemGroup>
32
src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj
-1
@@ -15,7 +15,6 @@
15
<ItemGroup>
16
<PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
17
<PackageReference Include="WixToolset.Data" Version="4.0.*" />
18
- <PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" />
18
<PackageReference Include="WixToolset.Extensibility" Version="4.0.*" />
19
</ItemGroup>
20