aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-03-14 07:38:48 -0700
committerRob Mensching <rob@firegiant.com>2021-03-14 07:47:48 -0700
commit3ccd5e439da4296d6f2b66ce47075ab20d039676 (patch)
treeb5546552613b869367d09f444492a0bbcfadcfe0 /src/WixToolset.Core.WindowsInstaller
parent574785ab1421c9b67336c13ade5c2263e665ca07 (diff)
downloadwix-3ccd5e439da4296d6f2b66ce47075ab20d039676.tar.gz
wix-3ccd5e439da4296d6f2b66ce47075ab20d039676.tar.bz2
wix-3ccd5e439da4296d6f2b66ce47075ab20d039676.zip
Minimize public surface area of Core
Fixes wixtoolset/issues#6374
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs36
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs31
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs15
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs5
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs6
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs630
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs7
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs2
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs83
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs19
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs21
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs21
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs6
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs12
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs11
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs15
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs15
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs12
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs14
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs12
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd73
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd248
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs65
-rw-r--r--src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs33
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs5
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Melter.cs2
-rw-r--r--src/WixToolset.Core.WindowsInstaller/MsiBackend.cs1
-rw-r--r--src/WixToolset.Core.WindowsInstaller/MsmBackend.cs1
-rw-r--r--src/WixToolset.Core.WindowsInstaller/MspBackend.cs6
-rw-r--r--src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs202
-rw-r--r--src/WixToolset.Core.WindowsInstaller/RowDictionary.cs13
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs10
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/UnbindContext.cs1
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Unbinder.cs4
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Validator.cs13
-rw-r--r--src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs14
43 files changed, 412 insertions, 1300 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
index f6c61866..d7faa382 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
@@ -6,9 +6,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Globalization; 7 using System.Globalization;
8 using System.Linq; 8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Data; 9 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 10 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services; 12 using WixToolset.Extensibility.Services;
13 13
14 /// <summary> 14 /// <summary>
@@ -18,7 +18,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18 { 18 {
19 private const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB 19 private const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB
20 20
21 public AssignMediaCommand(IntermediateSection section, IMessaging messaging, IEnumerable<FileFacade> fileFacades, bool compressed) 21 public AssignMediaCommand(IntermediateSection section, IMessaging messaging, IEnumerable<IFileFacade> fileFacades, bool compressed)
22 { 22 {
23 this.CabinetNameTemplate = "Cab{0}.cab"; 23 this.CabinetNameTemplate = "Cab{0}.cab";
24 this.Section = section; 24 this.Section = section;
@@ -31,7 +31,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
31 31
32 private IMessaging Messaging { get; } 32 private IMessaging Messaging { get; }
33 33
34 private IEnumerable<FileFacade> FileFacades { get; } 34 private IEnumerable<IFileFacade> FileFacades { get; }
35 35
36 private bool FilesCompressed { get; } 36 private bool FilesCompressed { get; }
37 37
@@ -40,13 +40,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
40 /// <summary> 40 /// <summary>
41 /// Gets cabinets with their file rows. 41 /// Gets cabinets with their file rows.
42 /// </summary> 42 /// </summary>
43 public Dictionary<MediaSymbol, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; } 43 public Dictionary<MediaSymbol, IEnumerable<IFileFacade>> FileFacadesByCabinetMedia { get; private set; }
44 44
45 /// <summary> 45 /// <summary>
46 /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. 46 /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no.
47 /// This contains all the files when Package element is marked with compression=no 47 /// This contains all the files when Package element is marked with compression=no
48 /// </summary> 48 /// </summary>
49 public IEnumerable<FileFacade> UncompressedFileFacades { get; private set; } 49 public IEnumerable<IFileFacade> UncompressedFileFacades { get; private set; }
50 50
51 public void Execute() 51 public void Execute()
52 { 52 {
@@ -79,34 +79,34 @@ namespace WixToolset.Core.WindowsInstaller.Bind
79 Cabinet = "#MergeModule.CABinet", 79 Cabinet = "#MergeModule.CABinet",
80 }); 80 });
81 81
82 this.FileFacadesByCabinetMedia = new Dictionary<MediaSymbol, IEnumerable<FileFacade>> 82 this.FileFacadesByCabinetMedia = new Dictionary<MediaSymbol, IEnumerable<IFileFacade>>
83 { 83 {
84 { mergeModuleMediaSymbol, this.FileFacades } 84 { mergeModuleMediaSymbol, this.FileFacades }
85 }; 85 };
86 86
87 this.UncompressedFileFacades = Array.Empty<FileFacade>(); 87 this.UncompressedFileFacades = Array.Empty<IFileFacade>();
88 } 88 }
89 else if (mediaTemplateSymbols.Count == 0) 89 else if (mediaTemplateSymbols.Count == 0)
90 { 90 {
91 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<FileFacade>>(); 91 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<IFileFacade>>();
92 92
93 var uncompressedFiles = new List<FileFacade>(); 93 var uncompressedFiles = new List<IFileFacade>();
94 94
95 this.ManuallyAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles); 95 this.ManuallyAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles);
96 96
97 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<FileFacade>)kvp.Value); 97 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<IFileFacade>)kvp.Value);
98 98
99 this.UncompressedFileFacades = uncompressedFiles; 99 this.UncompressedFileFacades = uncompressedFiles;
100 } 100 }
101 else 101 else
102 { 102 {
103 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<FileFacade>>(); 103 var filesByCabinetMedia = new Dictionary<MediaSymbol, List<IFileFacade>>();
104 104
105 var uncompressedFiles = new List<FileFacade>(); 105 var uncompressedFiles = new List<IFileFacade>();
106 106
107 this.AutoAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles); 107 this.AutoAssignFiles(mediaSymbols, filesByCabinetMedia, uncompressedFiles);
108 108
109 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<FileFacade>)kvp.Value); 109 this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<IFileFacade>)kvp.Value);
110 110
111 this.UncompressedFileFacades = uncompressedFiles; 111 this.UncompressedFileFacades = uncompressedFiles;
112 } 112 }
@@ -115,7 +115,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
115 /// <summary> 115 /// <summary>
116 /// Assign files to cabinets based on MediaTemplate authoring. 116 /// Assign files to cabinets based on MediaTemplate authoring.
117 /// </summary> 117 /// </summary>
118 private void AutoAssignFiles(List<MediaSymbol> mediaTable, Dictionary<MediaSymbol, List<FileFacade>> filesByCabinetMedia, List<FileFacade> uncompressedFiles) 118 private void AutoAssignFiles(List<MediaSymbol> mediaTable, Dictionary<MediaSymbol, List<IFileFacade>> filesByCabinetMedia, List<IFileFacade> uncompressedFiles)
119 { 119 {
120 const int MaxCabIndex = 999; 120 const int MaxCabIndex = 999;
121 121
@@ -194,7 +194,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
194 { 194 {
195 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex); 195 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex);
196 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow); 196 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow);
197 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); 197 filesByCabinetMedia.Add(currentMediaRow, new List<IFileFacade>());
198 198
199 // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize 199 // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize
200 currentPreCabSize = (ulong)facade.FileSize; 200 currentPreCabSize = (ulong)facade.FileSize;
@@ -206,7 +206,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
206 // Create new cab and MediaRow 206 // Create new cab and MediaRow
207 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex); 207 currentMediaRow = this.AddMediaSymbol(mediaTemplateRow, ++currentCabIndex);
208 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow); 208 mediaSymbolsByDiskId.Add(currentMediaRow.DiskId, currentMediaRow);
209 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); 209 filesByCabinetMedia.Add(currentMediaRow, new List<IFileFacade>());
210 } 210 }
211 } 211 }
212 } 212 }
@@ -232,7 +232,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
232 /// <summary> 232 /// <summary>
233 /// Assign files to cabinets based on Media authoring. 233 /// Assign files to cabinets based on Media authoring.
234 /// </summary> 234 /// </summary>
235 private void ManuallyAssignFiles(List<MediaSymbol> mediaSymbols, Dictionary<MediaSymbol, List<FileFacade>> filesByCabinetMedia, List<FileFacade> uncompressedFiles) 235 private void ManuallyAssignFiles(List<MediaSymbol> mediaSymbols, Dictionary<MediaSymbol, List<IFileFacade>> filesByCabinetMedia, List<IFileFacade> uncompressedFiles)
236 { 236 {
237 var mediaSymbolsByDiskId = new Dictionary<int, MediaSymbol>(); 237 var mediaSymbolsByDiskId = new Dictionary<int, MediaSymbol>();
238 238
@@ -254,7 +254,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
254 cabinetMediaSymbols.Add(mediaSymbol.Cabinet, mediaSymbol); 254 cabinetMediaSymbols.Add(mediaSymbol.Cabinet, mediaSymbol);
255 } 255 }
256 256
257 filesByCabinetMedia.Add(mediaSymbol, new List<FileFacade>()); 257 filesByCabinetMedia.Add(mediaSymbol, new List<IFileFacade>());
258 } 258 }
259 259
260 mediaSymbolsByDiskId.Add(mediaSymbol.DiskId, mediaSymbol); 260 mediaSymbolsByDiskId.Add(mediaSymbol.DiskId, mediaSymbol);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
index 2249faf8..b2052b90 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
@@ -55,16 +55,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
55 55
56 private readonly TableDefinitionCollection tableDefinitions; 56 private readonly TableDefinitionCollection tableDefinitions;
57 57
58 public AttachPatchTransformsCommand(IMessaging messaging, Intermediate intermediate, IEnumerable<PatchTransform> transforms) 58 public AttachPatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, Intermediate intermediate, IEnumerable<PatchTransform> transforms)
59 { 59 {
60 this.tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); 60 this.tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All);
61 this.Messaging = messaging; 61 this.Messaging = messaging;
62 this.BackendHelper = backendHelper;
62 this.Intermediate = intermediate; 63 this.Intermediate = intermediate;
63 this.Transforms = transforms; 64 this.Transforms = transforms;
64 } 65 }
65 66
66 private IMessaging Messaging { get; } 67 private IMessaging Messaging { get; }
67 68
69 private IBackendHelper BackendHelper { get; }
70
68 private Intermediate Intermediate { get; } 71 private Intermediate Intermediate { get; }
69 72
70 private IEnumerable<PatchTransform> Transforms { get; } 73 private IEnumerable<PatchTransform> Transforms { get; }
@@ -797,7 +800,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
797 if (!deletedComponent.ContainsKey(componentId)) 800 if (!deletedComponent.ContainsKey(componentId))
798 { 801 {
799 var foundRemoveFileEntry = false; 802 var foundRemoveFileEntry = false;
800 var filename = Common.GetName(row.FieldAsString(2), false, true); 803 var filename = this.BackendHelper.GetMsiFileName(row.FieldAsString(2), false, true);
801 804
802 if (transform.TryGetTable("RemoveFile", out var removeFileTable)) 805 if (transform.TryGetTable("RemoveFile", out var removeFileTable))
803 { 806 {
@@ -813,7 +816,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
813 // Check if there is a RemoveFile entry for this file 816 // Check if there is a RemoveFile entry for this file
814 if (null != removeFileRow[2]) 817 if (null != removeFileRow[2])
815 { 818 {
816 var removeFileName = Common.GetName(removeFileRow.FieldAsString(2), false, true); 819 var removeFileName = this.BackendHelper.GetMsiFileName(removeFileRow.FieldAsString(2), false, true);
817 820
818 // Convert the MSI format for a wildcard string to Regex format. 821 // Convert the MSI format for a wildcard string to Regex format.
819 removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\."); 822 removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\.");
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
index 292f1572..b6244a6e 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
@@ -6,7 +6,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.IO; 7 using System.IO;
8 using System.Linq; 8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Data; 9 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 10 using WixToolset.Data.Symbols;
12 using WixToolset.Data.WindowsInstaller; 11 using WixToolset.Data.WindowsInstaller;
@@ -133,7 +132,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
133 Platform platform; 132 Platform platform;
134 string modularizationSuffix; 133 string modularizationSuffix;
135 { 134 {
136 var command = new BindSummaryInfoCommand(section); 135 var branding = this.ServiceProvider.GetService<IWixBranding>();
136
137 var command = new BindSummaryInfoCommand(section, this.WindowsInstallerBackendHelper, branding);
137 command.Execute(); 138 command.Execute();
138 139
139 compressed = command.Compressed; 140 compressed = command.Compressed;
@@ -151,7 +152,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
151 // Set the ProductCode if it is to be generated. 152 // Set the ProductCode if it is to be generated.
152 if ("ProductCode".Equals(propertyRow.Id.Id, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal)) 153 if ("ProductCode".Equals(propertyRow.Id.Id, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal))
153 { 154 {
154 propertyRow.Value = Common.GenerateGuid(); 155 propertyRow.Value = this.WindowsInstallerBackendHelper.CreateGuid();
155 156
156#if TODO_PATCHING // Is this still necessary? 157#if TODO_PATCHING // Is this still necessary?
157 158
@@ -235,24 +236,23 @@ namespace WixToolset.Core.WindowsInstaller.Bind
235 236
236 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). 237 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules).
237 { 238 {
238 var command = new ExtractEmbeddedFilesCommand(this.WindowsInstallerBackendHelper, this.ExpectedEmbeddedFiles); 239 var extractedFiles = this.WindowsInstallerBackendHelper.ExtractEmbeddedFiles(this.ExpectedEmbeddedFiles);
239 command.Execute();
240 240
241 trackedFiles.AddRange(command.TrackedFiles); 241 trackedFiles.AddRange(extractedFiles);
242 } 242 }
243 243
244 // This must occur after all variables and source paths have been resolved. 244 // This must occur after all variables and source paths have been resolved.
245 List<FileFacade> fileFacades; 245 List<IFileFacade> fileFacades;
246 if (SectionType.Patch == section.Type) 246 if (SectionType.Patch == section.Type)
247 { 247 {
248 var command = new GetFileFacadesFromTransforms(this.Messaging, this.FileSystemManager, this.SubStorages); 248 var command = new GetFileFacadesFromTransforms(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, this.SubStorages);
249 command.Execute(); 249 command.Execute();
250 250
251 fileFacades = command.FileFacades; 251 fileFacades = command.FileFacades;
252 } 252 }
253 else 253 else
254 { 254 {
255 var command = new GetFileFacadesCommand(section); 255 var command = new GetFileFacadesCommand(section, this.WindowsInstallerBackendHelper);
256 command.Execute(); 256 command.Execute();
257 257
258 fileFacades = command.FileFacades; 258 fileFacades = command.FileFacades;
@@ -267,7 +267,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
267 { 267 {
268 containsMergeModules = true; 268 containsMergeModules = true;
269 269
270 var command = new ExtractMergeModuleFilesCommand(this.Messaging, wixMergeSymbols, fileFacades, installerVersion, this.IntermediateFolder, this.SuppressLayout); 270 var command = new ExtractMergeModuleFilesCommand(this.Messaging, this.WindowsInstallerBackendHelper, wixMergeSymbols, fileFacades, installerVersion, this.IntermediateFolder, this.SuppressLayout);
271 command.Execute(); 271 command.Execute();
272 272
273 fileFacades.AddRange(command.MergeModulesFileFacades); 273 fileFacades.AddRange(command.MergeModulesFileFacades);
@@ -307,8 +307,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
307 // Now that the variable cache is populated, resolve any delayed fields. 307 // Now that the variable cache is populated, resolve any delayed fields.
308 if (this.DelayedFields.Any()) 308 if (this.DelayedFields.Any())
309 { 309 {
310 var command = new ResolveDelayedFieldsCommand(this.Messaging, this.DelayedFields, variableCache); 310 this.WindowsInstallerBackendHelper.ResolveDelayedFields(this.DelayedFields, variableCache);
311 command.Execute();
312 } 311 }
313 312
314 // Update symbols that reference text files on disk. 313 // Update symbols that reference text files on disk.
@@ -330,7 +329,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
330 329
331 if (dependencyRefs.Any()) 330 if (dependencyRefs.Any())
332 { 331 {
333 var command = new ProcessDependencyReferencesCommand(section, dependencyRefs); 332 var command = new ProcessDependencyReferencesCommand(this.WindowsInstallerBackendHelper, section, dependencyRefs);
334 command.Execute(); 333 command.Execute();
335 } 334 }
336 } 335 }
@@ -379,8 +378,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
379 } 378 }
380 379
381 // Assign files to media and update file sequences. 380 // Assign files to media and update file sequences.
382 Dictionary<MediaSymbol, IEnumerable<FileFacade>> filesByCabinetMedia; 381 Dictionary<MediaSymbol, IEnumerable<IFileFacade>> filesByCabinetMedia;
383 IEnumerable<FileFacade> uncompressedFiles; 382 IEnumerable<IFileFacade> uncompressedFiles;
384 { 383 {
385 var order = new OptimizeFileFacadesOrderCommand(this.WindowsInstallerBackendHelper, this.PathResolver, section, platform, fileFacades); 384 var order = new OptimizeFileFacadesOrderCommand(this.WindowsInstallerBackendHelper, this.PathResolver, section, platform, fileFacades);
386 order.Execute(); 385 order.Execute();
@@ -414,7 +413,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
414 if (data.Type == OutputType.Module) 413 if (data.Type == OutputType.Module)
415 { 414 {
416 // Modularize identifiers. 415 // Modularize identifiers.
417 var modularize = new ModularizeCommand(data, modularizationSuffix, section.Symbols.OfType<WixSuppressModularizationSymbol>()); 416 var modularize = new ModularizeCommand(this.WindowsInstallerBackendHelper, data, modularizationSuffix, section.Symbols.OfType<WixSuppressModularizationSymbol>());
418 modularize.Execute(); 417 modularize.Execute();
419 418
420 // Ensure all sequence tables in place because, mergemod.dll requires them. 419 // Ensure all sequence tables in place because, mergemod.dll requires them.
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
index a496c7ce..babe0c1b 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
@@ -7,19 +7,26 @@ namespace WixToolset.Core.WindowsInstaller.Bind
7 using System.Linq; 7 using System.Linq;
8 using WixToolset.Data; 8 using WixToolset.Data;
9 using WixToolset.Data.Symbols; 9 using WixToolset.Data.Symbols;
10 using WixToolset.Extensibility.Services;
10 11
11 /// <summary> 12 /// <summary>
12 /// Binds the summary information table of a database. 13 /// Binds the summary information table of a database.
13 /// </summary> 14 /// </summary>
14 internal class BindSummaryInfoCommand 15 internal class BindSummaryInfoCommand
15 { 16 {
16 public BindSummaryInfoCommand(IntermediateSection section) 17 public BindSummaryInfoCommand(IntermediateSection section, IBackendHelper backendHelper, IWixBranding branding)
17 { 18 {
18 this.Section = section; 19 this.Section = section;
20 this.BackendHelper = backendHelper;
21 this.Branding = branding;
19 } 22 }
20 23
21 private IntermediateSection Section { get; } 24 private IntermediateSection Section { get; }
22 25
26 private IBackendHelper BackendHelper { get; }
27
28 private IWixBranding Branding { get; }
29
23 /// <summary> 30 /// <summary>
24 /// Returns a flag indicating if files are compressed by default. 31 /// Returns a flag indicating if files are compressed by default.
25 /// </summary> 32 /// </summary>
@@ -66,7 +73,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
66 } 73 }
67 else 74 else
68 { 75 {
69 summaryInformationSymbol.Value = Common.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture); 76 summaryInformationSymbol.Value = this.BackendHelper.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture);
70 } 77 }
71 break; 78 break;
72 case SummaryInformationType.PlatformAndLanguage: 79 case SummaryInformationType.PlatformAndLanguage:
@@ -116,7 +123,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
116 this.Section.AddSymbol(new SummaryInformationSymbol(null) 123 this.Section.AddSymbol(new SummaryInformationSymbol(null)
117 { 124 {
118 PropertyId = SummaryInformationType.PackageCode, 125 PropertyId = SummaryInformationType.PackageCode,
119 Value = Common.GenerateGuid(), 126 Value = this.BackendHelper.CreateGuid(),
120 }); 127 });
121 } 128 }
122 129
@@ -146,7 +153,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
146 this.Section.AddSymbol(new SummaryInformationSymbol(null) 153 this.Section.AddSymbol(new SummaryInformationSymbol(null)
147 { 154 {
148 PropertyId = SummaryInformationType.CreatingApplication, 155 PropertyId = SummaryInformationType.CreatingApplication,
149 Value = String.Format(CultureInfo.InvariantCulture, AppCommon.GetCreatingApplicationString()), 156 Value = this.Branding.GetCreatingApplication(),
150 }); 157 });
151 } 158 }
152 } 159 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
index bc5c6853..28e1d9ee 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
@@ -99,7 +99,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
99 } 99 }
100 else 100 else
101 { 101 {
102 codePage = Common.GetValidCodePage(codePage).ToString(CultureInfo.InvariantCulture); 102 codePage = this.BackendHelper.GetValidCodePage(codePage).ToString(CultureInfo.InvariantCulture);
103 } 103 }
104 104
105 var previousCodePage = row.Fields[1].PreviousData; 105 var previousCodePage = row.Fields[1].PreviousData;
@@ -109,7 +109,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
109 } 109 }
110 else 110 else
111 { 111 {
112 previousCodePage = Common.GetValidCodePage(previousCodePage).ToString(CultureInfo.InvariantCulture); 112 previousCodePage = this.BackendHelper.GetValidCodePage(previousCodePage).ToString(CultureInfo.InvariantCulture);
113 } 113 }
114 114
115 var targetCodePageRow = targetSummaryInfo.CreateRow(null); 115 var targetCodePageRow = targetSummaryInfo.CreateRow(null);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
index 6dbcb1a1..e47e5b64 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
@@ -6,7 +6,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.IO; 7 using System.IO;
8 using System.Linq; 8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Core.Native; 9 using WixToolset.Core.Native;
11 using WixToolset.Data; 10 using WixToolset.Data;
12 using WixToolset.Extensibility; 11 using WixToolset.Extensibility;
@@ -30,7 +29,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
30 29
31 private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; } 30 private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; }
32 31
33 public IResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) 32 public IResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<IFileFacade> fileFacades)
34 { 33 {
35 var filesWithPath = fileFacades.Select(this.CreateBindFileWithPath).ToList(); 34 var filesWithPath = fileFacades.Select(this.CreateBindFileWithPath).ToList();
36 35
@@ -109,7 +108,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
109 return resolved; 108 return resolved;
110 } 109 }
111 110
112 private IBindFileWithPath CreateBindFileWithPath(FileFacade facade) 111 private IBindFileWithPath CreateBindFileWithPath(IFileFacade facade)
113 { 112 {
114 var result = this.ServiceProvider.GetService<IBindFileWithPath>(); 113 var result = this.ServiceProvider.GetService<IBindFileWithPath>();
115 result.Id = facade.Id; 114 result.Id = facade.Id;
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs
index 48f0574e..1990ea78 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs
@@ -3,8 +3,8 @@
3namespace WixToolset.Core.WindowsInstaller.Bind 3namespace WixToolset.Core.WindowsInstaller.Bind
4{ 4{
5 using System.Collections.Generic; 5 using System.Collections.Generic;
6 using WixToolset.Core.Bind;
7 using WixToolset.Data; 6 using WixToolset.Data;
7 using WixToolset.Extensibility.Data;
8 8
9 /// <summary> 9 /// <summary>
10 /// A cabinet builder work item. 10 /// A cabinet builder work item.
@@ -20,7 +20,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
20 /// <param name="compressionLevel">The compression level of the cabinet.</param> 20 /// <param name="compressionLevel">The compression level of the cabinet.</param>
21 /// <param name="modularizationSuffix">Modularization suffix used when building a Merge Module.</param> 21 /// <param name="modularizationSuffix">Modularization suffix used when building a Merge Module.</param>
22 /// <!--<param name="binderFileManager">The binder file manager.</param>--> 22 /// <!--<param name="binderFileManager">The binder file manager.</param>-->
23 public CabinetWorkItem(IEnumerable<FileFacade> fileFacades, string cabinetFile, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix /*, BinderFileManager binderFileManager*/) 23 public CabinetWorkItem(IEnumerable<IFileFacade> fileFacades, string cabinetFile, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix /*, BinderFileManager binderFileManager*/)
24 { 24 {
25 this.CabinetFile = cabinetFile; 25 this.CabinetFile = cabinetFile;
26 this.CompressionLevel = compressionLevel; 26 this.CompressionLevel = compressionLevel;
@@ -51,7 +51,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
51 /// Gets the collection of files in this cabinet. 51 /// Gets the collection of files in this cabinet.
52 /// </summary> 52 /// </summary>
53 /// <value>The collection of files in this cabinet.</value> 53 /// <value>The collection of files in this cabinet.</value>
54 public IEnumerable<FileFacade> FileFacades { get; } 54 public IEnumerable<IFileFacade> FileFacades { get; }
55 55
56 // <summary> 56 // <summary>
57 // Gets the binder file manager. 57 // Gets the binder file manager.
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
index 55cda9ea..5cb297e5 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
@@ -138,8 +138,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
138 if (fileRow.Id.Id == componentSymbol.KeyPath) 138 if (fileRow.Id.Id == componentSymbol.KeyPath)
139 { 139 {
140 // calculate the key file's canonical target path 140 // calculate the key file's canonical target path
141 string directoryPath = this.PathResolver.GetCanonicalDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentSymbol.DirectoryRef, this.Platform); 141 var directoryPath = this.PathResolver.GetCanonicalDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentSymbol.DirectoryRef, this.Platform);
142 string fileName = Common.GetName(fileRow.Name, false, true).ToLowerInvariant(); 142 var fileName = this.BackendHelper.GetMsiFileName(fileRow.Name, false, true).ToLowerInvariant();
143 path = Path.Combine(directoryPath, fileName); 143 path = Path.Combine(directoryPath, fileName);
144 144
145 // find paths that are not canonicalized 145 // find paths that are not canonicalized
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs
deleted file mode 100644
index 8a85a975..00000000
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs
+++ /dev/null
@@ -1,630 +0,0 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#if DELETE
4
5namespace WixToolset.Core.WindowsInstaller.Bind
6{
7 using System;
8 using System.Collections.Generic;
9 using System.Diagnostics;
10 using System.IO;
11 using System.Linq;
12 using WixToolset.Core.Bind;
13 using WixToolset.Data;
14 using WixToolset.Data.Symbols;
15 using WixToolset.Data.WindowsInstaller;
16 using WixToolset.Data.WindowsInstaller.Rows;
17 using WixToolset.Extensibility;
18 using WixToolset.Extensibility.Services;
19
20 internal class CopyTransformDataCommand
21 {
22 public CopyTransformDataCommand(IMessaging messaging, WindowsInstallerData output, TableDefinitionCollection tableDefinitions, bool copyOutFileRows)
23 {
24 this.Messaging = messaging;
25 this.Output = output;
26 this.TableDefinitions = tableDefinitions;
27 this.CopyOutFileRows = copyOutFileRows;
28 }
29
30 private bool CopyOutFileRows { get; }
31
32 public IEnumerable<IFileSystemExtension> Extensions { get; }
33
34 private IMessaging Messaging { get; }
35
36 private WindowsInstallerData Output { get; }
37
38 private TableDefinitionCollection TableDefinitions { get; }
39
40 public IEnumerable<FileFacade> FileFacades { get; private set; }
41
42 public void Execute()
43 {
44 Debug.Assert(OutputType.Patch != this.Output.Type);
45
46 var allFileRows = this.CopyOutFileRows ? new List<FileFacade>() : null;
47
48 var copyToPatch = (allFileRows != null);
49 var copyFromPatch = !copyToPatch;
50
51 var patchMediaRows = new RowDictionary<MediaRow>();
52
53 var patchMediaFileRows = new Dictionary<int, RowDictionary<WixFileRow>>();
54
55 var patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]);
56 var patchFileTable = this.Output.EnsureTable(this.TableDefinitions["WixFile"]);
57
58 if (copyFromPatch)
59 {
60 // index patch files by diskId+fileId
61 foreach (WixFileRow patchFileRow in patchFileTable.Rows)
62 {
63 int diskId = patchFileRow.DiskId;
64 if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows))
65 {
66 mediaFileRows = new RowDictionary<WixFileRow>();
67 patchMediaFileRows.Add(diskId, mediaFileRows);
68 }
69
70 mediaFileRows.Add(patchFileRow);
71 }
72
73 var patchMediaTable = this.Output.EnsureTable(this.TableDefinitions["Media"]);
74 patchMediaRows = new RowDictionary<MediaRow>(patchMediaTable);
75 }
76
77 // Index paired transforms by name without the "#" prefix.
78 var pairedTransforms = this.Output.SubStorages.Where(s => s.Name.StartsWith("#")).ToDictionary(s => s.Name.Substring(1), s => s.Data);
79 //Dictionary<string, Output> pairedTransforms = new Dictionary<string, Output>();
80 //foreach (SubStorage substorage in this.Output.SubStorages)
81 //{
82 // if (substorage.Name.StartsWith("#"))
83 // {
84 // pairedTransforms.Add(substorage.Name.Substring(1), substorage.Data);
85 // }
86 //}
87
88 try
89 {
90 // Copy File bind data into substorages
91 foreach (var substorage in this.Output.SubStorages)
92 {
93 if (substorage.Name.StartsWith("#"))
94 {
95 // no changes necessary for paired transforms
96 continue;
97 }
98
99 var mainTransform = substorage.Data;
100 var mainWixFileTable = mainTransform.Tables["WixFile"];
101 var mainMsiFileHashTable = mainTransform.Tables["MsiFileHash"];
102
103 this.FileManagerCore.ActiveSubStorage = substorage;
104
105 var mainWixFiles = new RowDictionary<WixFileRow>(mainWixFileTable);
106 var mainMsiFileHashIndex = new RowDictionary<Row>();
107
108 var mainFileTable = mainTransform.Tables["File"];
109 var pairedTransform = pairedTransforms[substorage.Name];
110
111 // copy Media.LastSequence and index the MsiFileHash table if it exists.
112 if (copyFromPatch)
113 {
114 var pairedMediaTable = pairedTransform.Tables["Media"];
115 foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
116 {
117 var patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId);
118 pairedMediaRow.Fields[1] = patchMediaRow.Fields[1];
119 }
120
121 if (null != mainMsiFileHashTable)
122 {
123 mainMsiFileHashIndex = new RowDictionary<Row>(mainMsiFileHashTable);
124 }
125
126 // Validate file row changes for keypath-related issues
127 this.ValidateFileRowChanges(mainTransform);
128 }
129
130 // Index File table of pairedTransform
131 var pairedFileTable = pairedTransform.Tables["File"];
132 var pairedFileRows = new RowDictionary<FileRow>(pairedFileTable);
133
134 if (null != mainFileTable)
135 {
136 if (copyFromPatch)
137 {
138 // Remove the MsiFileHash table because it will be updated later with the final file hash for each file
139 mainTransform.Tables.Remove("MsiFileHash");
140 }
141
142 foreach (FileRow mainFileRow in mainFileTable.Rows)
143 {
144 if (RowOperation.Delete == mainFileRow.Operation)
145 {
146 continue;
147 }
148 else if (RowOperation.None == mainFileRow.Operation && !copyToPatch)
149 {
150 continue;
151 }
152
153 var mainWixFileRow = mainWixFiles.Get(mainFileRow.File);
154
155 if (copyToPatch) // when copying to the patch, we need compare the underlying files and include all file changes.
156 {
157 var objectField = (ObjectField)mainWixFileRow.Fields[6];
158 var pairedFileRow = pairedFileRows.Get(mainFileRow.File);
159
160 // If the file is new, we always need to add it to the patch.
161 if (mainFileRow.Operation != RowOperation.Add)
162 {
163 // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare.
164 if (null == objectField.PreviousData)
165 {
166 if (mainFileRow.Operation == RowOperation.None)
167 {
168 continue;
169 }
170 }
171 else
172 {
173 // TODO: should this entire condition be placed in the binder file manager?
174 if ((0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) &&
175 !this.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString()))
176 {
177 // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified.
178 mainFileRow.Operation = RowOperation.Modify;
179 if (null != pairedFileRow)
180 {
181 // Always patch-added, but never non-compressed.
182 pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
183 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
184 pairedFileRow.Fields[6].Modified = true;
185 pairedFileRow.Operation = RowOperation.Modify;
186 }
187 }
188 else
189 {
190 // The File is same. We need mark all the attributes as unchanged.
191 mainFileRow.Operation = RowOperation.None;
192 foreach (var field in mainFileRow.Fields)
193 {
194 field.Modified = false;
195 }
196
197 if (null != pairedFileRow)
198 {
199 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
200 pairedFileRow.Fields[6].Modified = false;
201 pairedFileRow.Operation = RowOperation.None;
202 }
203 continue;
204 }
205 }
206 }
207 else if (null != pairedFileRow) // RowOperation.Add
208 {
209 // Always patch-added, but never non-compressed.
210 pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
211 pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
212 pairedFileRow.Fields[6].Modified = true;
213 pairedFileRow.Operation = RowOperation.Add;
214 }
215 }
216
217 // index patch files by diskId+fileId
218 int diskId = mainWixFileRow.DiskId;
219
220 if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows))
221 {
222 mediaFileRows = new RowDictionary<WixFileRow>();
223 patchMediaFileRows.Add(diskId, mediaFileRows);
224 }
225
226 var fileId = mainFileRow.File;
227 var patchFileRow = mediaFileRows.Get(fileId);
228 if (copyToPatch)
229 {
230 if (null == patchFileRow)
231 {
232 var patchActualFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers);
233 patchActualFileRow.CopyFrom(mainFileRow);
234
235 patchFileRow = (WixFileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers);
236 patchFileRow.CopyFrom(mainWixFileRow);
237
238 mediaFileRows.Add(patchFileRow);
239
240 allFileRows.Add(new FileFacade(patchActualFileRow, patchFileRow, null)); // TODO: should we be passing along delta information? Probably, right?
241 }
242 else
243 {
244 // TODO: confirm the rest of data is identical?
245
246 // make sure Source is same. Otherwise we are silently ignoring a file.
247 if (0 != String.Compare(patchFileRow.Source, mainWixFileRow.Source, StringComparison.OrdinalIgnoreCase))
248 {
249 this.Messaging.Write(ErrorMessages.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, fileId, patchFileRow.Source, mainWixFileRow.Source));
250 }
251
252 // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow.
253 patchFileRow.AppendPreviousDataFrom(mainWixFileRow);
254 }
255 }
256 else
257 {
258 // copy data from the patch back to the transform
259 if (null != patchFileRow)
260 {
261 var pairedFileRow = pairedFileRows.Get(fileId);
262 for (var i = 0; i < patchFileRow.Fields.Length; i++)
263 {
264 var patchValue = patchFileRow[i] == null ? String.Empty : patchFileRow.FieldAsString(i);
265 var mainValue = mainFileRow[i] == null ? String.Empty : mainFileRow.FieldAsString(i);
266
267 if (1 == i)
268 {
269 // File.Component_ changes should not come from the shared file rows
270 // that contain the file information as each individual transform might
271 // have different changes (or no changes at all).
272 }
273 // File.Attributes should not changed for binary deltas
274 else if (6 == i)
275 {
276 if (null != patchFileRow.Patch)
277 {
278 // File.Attribute should not change for binary deltas
279 pairedFileRow.Attributes = mainFileRow.Attributes;
280 mainFileRow.Fields[i].Modified = false;
281 }
282 }
283 // File.Sequence is updated in pairedTransform, not mainTransform
284 else if (7 == i)
285 {
286 // file sequence is updated in Patch table instead of File table for delta patches
287 if (null != patchFileRow.Patch)
288 {
289 pairedFileRow.Fields[i].Modified = false;
290 }
291 else
292 {
293 pairedFileRow[i] = patchFileRow[i];
294 pairedFileRow.Fields[i].Modified = true;
295 }
296 mainFileRow.Fields[i].Modified = false;
297 }
298 else if (patchValue != mainValue)
299 {
300 mainFileRow[i] = patchFileRow[i];
301 mainFileRow.Fields[i].Modified = true;
302 if (mainFileRow.Operation == RowOperation.None)
303 {
304 mainFileRow.Operation = RowOperation.Modify;
305 }
306 }
307 }
308
309 // copy MsiFileHash row for this File
310 if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out var patchHashRow))
311 {
312 patchHashRow = patchFileRow.Hash;
313 }
314
315 if (null != patchHashRow)
316 {
317 var mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]);
318 var mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers);
319 for (var i = 0; i < patchHashRow.Fields.Length; i++)
320 {
321 mainHashRow[i] = patchHashRow[i];
322 if (i > 1)
323 {
324 // assume all hash fields have been modified
325 mainHashRow.Fields[i].Modified = true;
326 }
327 }
328
329 // assume the MsiFileHash operation follows the File one
330 mainHashRow.Operation = mainFileRow.Operation;
331 }
332
333 // copy MsiAssemblyName rows for this File
334 List<Row> patchAssemblyNameRows = patchFileRow.AssemblyNames;
335 if (null != patchAssemblyNameRows)
336 {
337 var mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]);
338 foreach (var patchAssemblyNameRow in patchAssemblyNameRows)
339 {
340 // Copy if there isn't an identical modified/added row already in the transform.
341 var foundMatchingModifiedRow = false;
342 foreach (var mainAssemblyNameRow in mainAssemblyNameTable.Rows)
343 {
344 if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/')))
345 {
346 foundMatchingModifiedRow = true;
347 break;
348 }
349 }
350
351 if (!foundMatchingModifiedRow)
352 {
353 var mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers);
354 for (var i = 0; i < patchAssemblyNameRow.Fields.Length; i++)
355 {
356 mainAssemblyNameRow[i] = patchAssemblyNameRow[i];
357 }
358
359 // assume value field has been modified
360 mainAssemblyNameRow.Fields[2].Modified = true;
361 mainAssemblyNameRow.Operation = mainFileRow.Operation;
362 }
363 }
364 }
365
366 // Add patch header for this file
367 if (null != patchFileRow.Patch)
368 {
369 // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables.
370 this.AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow);
371 this.AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow);
372
373 // Add to Patch table
374 var patchTable = pairedTransform.EnsureTable(this.TableDefinitions["Patch"]);
375 if (0 == patchTable.Rows.Count)
376 {
377 patchTable.Operation = TableOperation.Add;
378 }
379
380 var patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers);
381 patchRow[0] = patchFileRow.File;
382 patchRow[1] = patchFileRow.Sequence;
383
384 var patchFile = new FileInfo(patchFileRow.Source);
385 patchRow[2] = (int)patchFile.Length;
386 patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1;
387
388 var streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1];
389 if (Msi.MsiInterop.MsiMaxStreamNameLength < streamName.Length)
390 {
391 streamName = "_" + Guid.NewGuid().ToString("D").ToUpperInvariant().Replace('-', '_');
392
393 var patchHeadersTable = pairedTransform.EnsureTable(this.TableDefinitions["MsiPatchHeaders"]);
394 if (0 == patchHeadersTable.Rows.Count)
395 {
396 patchHeadersTable.Operation = TableOperation.Add;
397 }
398
399 var patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers);
400 patchHeadersRow[0] = streamName;
401 patchHeadersRow[1] = patchFileRow.Patch;
402 patchRow[5] = streamName;
403 patchHeadersRow.Operation = RowOperation.Add;
404 }
405 else
406 {
407 patchRow[4] = patchFileRow.Patch;
408 }
409 patchRow.Operation = RowOperation.Add;
410 }
411 }
412 else
413 {
414 // TODO: throw because all transform rows should have made it into the patch
415 }
416 }
417 }
418 }
419
420 if (copyFromPatch)
421 {
422 this.Output.Tables.Remove("Media");
423 this.Output.Tables.Remove("File");
424 this.Output.Tables.Remove("MsiFileHash");
425 this.Output.Tables.Remove("MsiAssemblyName");
426 }
427 }
428 }
429 finally
430 {
431 this.FileManagerCore.ActiveSubStorage = null;
432 }
433
434 this.FileFacades = allFileRows;
435 }
436
437 /// <summary>
438 /// Adds the PatchFiles action to the sequence table if it does not already exist.
439 /// </summary>
440 /// <param name="table">The sequence table to check or modify.</param>
441 /// <param name="mainTransform">The primary authoring transform.</param>
442 /// <param name="pairedTransform">The secondary patch transform.</param>
443 /// <param name="mainFileRow">The file row that contains information about the patched file.</param>
444 private void AddPatchFilesActionToSequenceTable(SequenceTable table, WindowsInstallerData mainTransform, WindowsInstallerData pairedTransform, Row mainFileRow)
445 {
446 var tableName = table.ToString();
447
448 // Find/add PatchFiles action (also determine sequence for it).
449 // Search mainTransform first, then pairedTransform (pairedTransform overrides).
450 var hasPatchFilesAction = false;
451 var installFilesSequence = 0;
452 var duplicateFilesSequence = 0;
453
454 TestSequenceTableForPatchFilesAction(
455 mainTransform.Tables[tableName],
456 ref hasPatchFilesAction,
457 ref installFilesSequence,
458 ref duplicateFilesSequence);
459 TestSequenceTableForPatchFilesAction(
460 pairedTransform.Tables[tableName],
461 ref hasPatchFilesAction,
462 ref installFilesSequence,
463 ref duplicateFilesSequence);
464 if (!hasPatchFilesAction)
465 {
466 WindowsInstallerStandard.TryGetStandardAction(tableName, "PatchFiles", out var patchFilesActionSymbol);
467
468 var sequence = patchFilesActionSymbol.Sequence;
469
470 // Test for default sequence value's appropriateness
471 if (installFilesSequence >= sequence || (0 != duplicateFilesSequence && duplicateFilesSequence <= sequence))
472 {
473 if (0 != duplicateFilesSequence)
474 {
475 if (duplicateFilesSequence < installFilesSequence)
476 {
477 throw new WixException(ErrorMessages.InsertInvalidSequenceActionOrder(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionSymbol.Action));
478 }
479 else
480 {
481 sequence = (duplicateFilesSequence + installFilesSequence) / 2;
482 if (installFilesSequence == sequence || duplicateFilesSequence == sequence)
483 {
484 throw new WixException(ErrorMessages.InsertSequenceNoSpace(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionSymbol.Action));
485 }
486 }
487 }
488 else
489 {
490 sequence = installFilesSequence + 1;
491 }
492 }
493
494 var sequenceTable = pairedTransform.EnsureTable(this.TableDefinitions[tableName]);
495 if (0 == sequenceTable.Rows.Count)
496 {
497 sequenceTable.Operation = TableOperation.Add;
498 }
499
500 var patchAction = sequenceTable.CreateRow(null);
501 patchAction[0] = patchFilesActionSymbol.Action;
502 patchAction[1] = patchFilesActionSymbol.Condition;
503 patchAction[2] = sequence;
504 patchAction.Operation = RowOperation.Add;
505 }
506 }
507
508 /// <summary>
509 /// Tests sequence table for PatchFiles and associated actions
510 /// </summary>
511 /// <param name="sequenceTable">The table to test.</param>
512 /// <param name="hasPatchFilesAction">Set to true if PatchFiles action is found. Left unchanged otherwise.</param>
513 /// <param name="installFilesSequence">Set to sequence value of InstallFiles action if found. Left unchanged otherwise.</param>
514 /// <param name="duplicateFilesSequence">Set to sequence value of DuplicateFiles action if found. Left unchanged otherwise.</param>
515 private static void TestSequenceTableForPatchFilesAction(Table sequenceTable, ref bool hasPatchFilesAction, ref int installFilesSequence, ref int duplicateFilesSequence)
516 {
517 if (null != sequenceTable)
518 {
519 foreach (var row in sequenceTable.Rows)
520 {
521 var actionName = row.FieldAsString(0);
522 switch (actionName)
523 {
524 case "PatchFiles":
525 hasPatchFilesAction = true;
526 break;
527
528 case "InstallFiles":
529 installFilesSequence = row.FieldAsInteger(2);
530 break;
531
532 case "DuplicateFiles":
533 duplicateFilesSequence = row.FieldAsInteger(2);
534 break;
535 }
536 }
537 }
538 }
539
540 /// <summary>
541 /// Signal a warning if a non-keypath file was changed in a patch without also changing the keypath file of the component.
542 /// </summary>
543 /// <param name="output">The output to validate.</param>
544 private void ValidateFileRowChanges(WindowsInstallerData transform)
545 {
546 var componentTable = transform.Tables["Component"];
547 var fileTable = transform.Tables["File"];
548
549 // There's no sense validating keypaths if the transform has no component or file table
550 if (componentTable == null || fileTable == null)
551 {
552 return;
553 }
554
555 var componentKeyPath = new Dictionary<string, string>(componentTable.Rows.Count);
556
557 // Index the Component table for non-directory & non-registry key paths.
558 foreach (var row in componentTable.Rows)
559 {
560 var keyPath = row.FieldAsString(5);
561 if (keyPath != null && 0 != (row.FieldAsInteger(3) & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath))
562 {
563 componentKeyPath.Add(row.FieldAsString(0), keyPath);
564 }
565 }
566
567 var componentWithChangedKeyPath = new Dictionary<string, string>();
568 var componentWithNonKeyPathChanged = new Dictionary<string, string>();
569 // Verify changes in the file table, now that file diffing has occurred
570 foreach (FileRow row in fileTable.Rows)
571 {
572 if (RowOperation.Modify != row.Operation)
573 {
574 continue;
575 }
576
577 var fileId = row.FieldAsString(0);
578 var componentId = row.FieldAsString(1);
579
580 // If this file is the keypath of a component
581 if (componentKeyPath.ContainsValue(fileId))
582 {
583 if (!componentWithChangedKeyPath.ContainsKey(componentId))
584 {
585 componentWithChangedKeyPath.Add(componentId, fileId);
586 }
587 }
588 else
589 {
590 if (!componentWithNonKeyPathChanged.ContainsKey(componentId))
591 {
592 componentWithNonKeyPathChanged.Add(componentId, fileId);
593 }
594 }
595 }
596
597 foreach (var componentFile in componentWithNonKeyPathChanged)
598 {
599 // Make sure all changes to non keypath files also had a change in the keypath.
600 if (!componentWithChangedKeyPath.ContainsKey(componentFile.Key) && componentKeyPath.TryGetValue(componentFile.Key, out var keyPath))
601 {
602 this.Messaging.Write(WarningMessages.UpdateOfNonKeyPathFile(componentFile.Value, componentFile.Key, keyPath));
603 }
604 }
605 }
606
607 private bool CompareFiles(string targetFile, string updatedFile)
608 {
609 bool? compared = null;
610 foreach (var extension in this.Extensions)
611 {
612 compared = extension.CompareFiles(targetFile, updatedFile);
613
614 if (compared.HasValue)
615 {
616 break;
617 }
618 }
619
620 if (!compared.HasValue)
621 {
622 throw new InvalidOperationException(); // TODO: something needs to be said here that none of the binder file managers returned a result.
623 }
624
625 return compared.Value;
626 }
627 }
628}
629
630#endif
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
index 9f94b2c7..0a543650 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
@@ -80,7 +80,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
80 80
81 public string ModularizationSuffix { private get; set; } 81 public string ModularizationSuffix { private get; set; }
82 82
83 public Dictionary<MediaSymbol, IEnumerable<FileFacade>> FileFacadesByCabinet { private get; set; } 83 public Dictionary<MediaSymbol, IEnumerable<IFileFacade>> FileFacadesByCabinet { private get; set; }
84 84
85 public Func<MediaSymbol, string, string, string> ResolveMedia { private get; set; } 85 public Func<MediaSymbol, string, string, string> ResolveMedia { private get; set; }
86 86
@@ -177,7 +177,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
177 /// <param name="compressionLevel">Desired compression level.</param> 177 /// <param name="compressionLevel">Desired compression level.</param>
178 /// <param name="fileFacades">Collection of files in this cabinet.</param> 178 /// <param name="fileFacades">Collection of files in this cabinet.</param>
179 /// <returns>created CabinetWorkItem object</returns> 179 /// <returns>created CabinetWorkItem object</returns>
180 private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData data, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable<FileFacade> fileFacades) 180 private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData data, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable<IFileFacade> fileFacades)
181 { 181 {
182 CabinetWorkItem cabinetWorkItem = null; 182 CabinetWorkItem cabinetWorkItem = null;
183 var tempCabinetFileX = Path.Combine(this.IntermediateFolder, mediaSymbol.Cabinet); 183 var tempCabinetFileX = Path.Combine(this.IntermediateFolder, mediaSymbol.Cabinet);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs
index 93ac50ff..640322e6 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs
@@ -9,20 +9,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind
9 using WixToolset.Core.Bind; 9 using WixToolset.Core.Bind;
10 using WixToolset.Data; 10 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 11 using WixToolset.Data.Symbols;
12 using WixToolset.Extensibility.Data;
12 13
13 /// <summary> 14 /// <summary>
14 /// Creates delta patches and updates the appropriate rows to point to the newly generated patches. 15 /// Creates delta patches and updates the appropriate rows to point to the newly generated patches.
15 /// </summary> 16 /// </summary>
16 internal class CreateDeltaPatchesCommand 17 internal class CreateDeltaPatchesCommand
17 { 18 {
18 public CreateDeltaPatchesCommand(List<FileFacade> fileFacades, string intermediateFolder, WixPatchIdSymbol wixPatchId) 19 public CreateDeltaPatchesCommand(List<IFileFacade> fileFacades, string intermediateFolder, WixPatchIdSymbol wixPatchId)
19 { 20 {
20 this.FileFacades = fileFacades; 21 this.FileFacades = fileFacades;
21 this.IntermediateFolder = intermediateFolder; 22 this.IntermediateFolder = intermediateFolder;
22 this.WixPatchId = wixPatchId; 23 this.WixPatchId = wixPatchId;
23 } 24 }
24 25
25 private IEnumerable<FileFacade> FileFacades { get; } 26 private IEnumerable<IFileFacade> FileFacades { get; }
26 27
27 private WixPatchIdSymbol WixPatchId { get; } 28 private WixPatchIdSymbol WixPatchId { get; }
28 29
@@ -31,7 +32,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
31 public void Execute() 32 public void Execute()
32 { 33 {
33 var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false; 34 var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false;
34 var apiPatchingSymbolFlags = (PatchSymbolFlagsType)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0); 35 var apiPatchingSymbolFlags = (PatchSymbolFlags)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0);
35 36
36#if TODO_PATCHING_DELTA 37#if TODO_PATCHING_DELTA
37 foreach (FileFacade facade in this.FileFacades) 38 foreach (FileFacade facade in this.FileFacades)
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs
index 33afca77..9a631754 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs
@@ -110,7 +110,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
110 var productCode = instanceSymbol.ProductCode; 110 var productCode = instanceSymbol.ProductCode;
111 if ("*" == productCode) 111 if ("*" == productCode)
112 { 112 {
113 productCode = Common.GenerateGuid(); 113 productCode = this.BackendHelper.CreateGuid();
114 } 114 }
115 115
116 var productCodeRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers); 116 var productCodeRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
index 76e6dd56..7bc1a8bd 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
@@ -15,15 +15,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
15 15
16 internal class CreatePatchTransformsCommand 16 internal class CreatePatchTransformsCommand
17 { 17 {
18 public CreatePatchTransformsCommand(IMessaging messaging, Intermediate intermediate, string intermediateFolder) 18 public CreatePatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, Intermediate intermediate, string intermediateFolder)
19 { 19 {
20 this.Messaging = messaging; 20 this.Messaging = messaging;
21 this.BackendHelper = backendHelper;
21 this.Intermediate = intermediate; 22 this.Intermediate = intermediate;
22 this.IntermediateFolder = intermediateFolder; 23 this.IntermediateFolder = intermediateFolder;
23 } 24 }
24 25
25 private IMessaging Messaging { get; } 26 private IMessaging Messaging { get; }
26 27
28 private IBackendHelper BackendHelper { get; }
29
27 private Intermediate Intermediate { get; } 30 private Intermediate Intermediate { get; }
28 31
29 private string IntermediateFolder { get; } 32 private string IntermediateFolder { get; }
@@ -52,7 +55,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
52 { 55 {
53 var exportBasePath = Path.Combine(this.IntermediateFolder, "_trans"); // TODO: come up with a better path. 56 var exportBasePath = Path.Combine(this.IntermediateFolder, "_trans"); // TODO: come up with a better path.
54 57
55 var command = new UnbindTransformCommand(this.Messaging, symbol.TransformFile.Path, exportBasePath, this.IntermediateFolder); 58 var command = new UnbindTransformCommand(this.Messaging, this.BackendHelper, symbol.TransformFile.Path, exportBasePath, this.IntermediateFolder);
56 transform = command.Execute(); 59 transform = command.Execute();
57 } 60 }
58 61
@@ -76,7 +79,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
76 79
77 var isAdminImage = false; // TODO: need a better way to set this 80 var isAdminImage = false; // TODO: need a better way to set this
78 81
79 var command = new UnbindDatabaseCommand(this.Messaging, database, path, OutputType.Product, exportBasePath, this.IntermediateFolder, isAdminImage, suppressDemodularization: true, skipSummaryInfo: true); 82 var command = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, database, path, OutputType.Product, exportBasePath, this.IntermediateFolder, isAdminImage, suppressDemodularization: true, skipSummaryInfo: true);
80 return command.Execute(); 83 return command.Execute();
81 } 84 }
82 } 85 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
index 9ec26964..0ce67591 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
@@ -481,18 +481,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
481 481
482 private void AddDirectorySymbol(DirectorySymbol symbol) 482 private void AddDirectorySymbol(DirectorySymbol symbol)
483 { 483 {
484 if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !Common.IsValidShortFilename(symbol.Name, false)) 484 if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !this.BackendHelper.IsValidShortFilename(symbol.Name, false))
485 { 485 {
486 symbol.ShortName = CreateShortName(symbol.Name, false, false, "Directory", symbol.ParentDirectoryRef); 486 symbol.ShortName = this.CreateShortName(symbol.Name, false, "Directory", symbol.ParentDirectoryRef);
487 } 487 }
488 488
489 if (String.IsNullOrEmpty(symbol.SourceShortName) && !String.IsNullOrEmpty(symbol.SourceName) && !Common.IsValidShortFilename(symbol.SourceName, false)) 489 if (String.IsNullOrEmpty(symbol.SourceShortName) && !String.IsNullOrEmpty(symbol.SourceName) && !this.BackendHelper.IsValidShortFilename(symbol.SourceName, false))
490 { 490 {
491 symbol.SourceShortName = CreateShortName(symbol.SourceName, false, false, "Directory", symbol.ParentDirectoryRef); 491 symbol.SourceShortName = this.CreateShortName(symbol.SourceName, false, "Directory", symbol.ParentDirectoryRef);
492 } 492 }
493 493
494 var sourceName = GetMsiFilenameValue(symbol.SourceShortName, symbol.SourceName); 494 var sourceName = CreateMsiFilename(symbol.SourceShortName, symbol.SourceName);
495 var targetName = GetMsiFilenameValue(symbol.ShortName, symbol.Name); 495 var targetName = CreateMsiFilename(symbol.ShortName, symbol.Name);
496 496
497 if (String.IsNullOrEmpty(targetName)) 497 if (String.IsNullOrEmpty(targetName))
498 { 498 {
@@ -542,16 +542,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
542 private void AddDuplicateFileSymbol(DuplicateFileSymbol symbol) 542 private void AddDuplicateFileSymbol(DuplicateFileSymbol symbol)
543 { 543 {
544 var name = symbol.DestinationName; 544 var name = symbol.DestinationName;
545 if (null == symbol.DestinationShortName && null != name && !Common.IsValidShortFilename(name, false)) 545 if (null == symbol.DestinationShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
546 { 546 {
547 symbol.DestinationShortName = CreateShortName(name, true, false, "CopyFile", symbol.ComponentRef, symbol.FileRef); 547 symbol.DestinationShortName = this.CreateShortName(name, true, "CopyFile", symbol.ComponentRef, symbol.FileRef);
548 } 548 }
549 549
550 var row = this.CreateRow(symbol, "DuplicateFile"); 550 var row = this.CreateRow(symbol, "DuplicateFile");
551 row[0] = symbol.Id.Id; 551 row[0] = symbol.Id.Id;
552 row[1] = symbol.ComponentRef; 552 row[1] = symbol.ComponentRef;
553 row[2] = symbol.FileRef; 553 row[2] = symbol.FileRef;
554 row[3] = GetMsiFilenameValue(symbol.DestinationShortName, symbol.DestinationName); 554 row[3] = CreateMsiFilename(symbol.DestinationShortName, symbol.DestinationName);
555 row[4] = symbol.DestinationFolder; 555 row[4] = symbol.DestinationFolder;
556 } 556 }
557 557
@@ -621,9 +621,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
621 private void AddFileSymbol(FileSymbol symbol) 621 private void AddFileSymbol(FileSymbol symbol)
622 { 622 {
623 var name = symbol.Name; 623 var name = symbol.Name;
624 if (null == symbol.ShortName && null != name && !Common.IsValidShortFilename(name, false)) 624 if (null == symbol.ShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
625 { 625 {
626 symbol.ShortName = CreateShortName(name, true, false, "File", symbol.DirectoryRef); 626 symbol.ShortName = this.CreateShortName(name, true, "File", symbol.DirectoryRef);
627 627
628 if (!this.GeneratedShortNames.TryGetValue(symbol.ShortName, out var potentialConflicts)) 628 if (!this.GeneratedShortNames.TryGetValue(symbol.ShortName, out var potentialConflicts))
629 { 629 {
@@ -637,7 +637,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
637 var row = (FileRow)this.CreateRow(symbol, "File"); 637 var row = (FileRow)this.CreateRow(symbol, "File");
638 row.File = symbol.Id.Id; 638 row.File = symbol.Id.Id;
639 row.Component = symbol.ComponentRef; 639 row.Component = symbol.ComponentRef;
640 row.FileName = GetMsiFilenameValue(symbol.ShortName, name); 640 row.FileName = CreateMsiFilename(symbol.ShortName, name);
641 row.FileSize = symbol.FileSize; 641 row.FileSize = symbol.FileSize;
642 row.Version = symbol.Version; 642 row.Version = symbol.Version;
643 row.Language = symbol.Language; 643 row.Language = symbol.Language;
@@ -674,14 +674,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
674 var tableName = (IniFileActionType.AddLine == symbol.Action || IniFileActionType.AddTag == symbol.Action || IniFileActionType.CreateLine == symbol.Action) ? "IniFile" : "RemoveIniFile"; 674 var tableName = (IniFileActionType.AddLine == symbol.Action || IniFileActionType.AddTag == symbol.Action || IniFileActionType.CreateLine == symbol.Action) ? "IniFile" : "RemoveIniFile";
675 675
676 var name = symbol.FileName; 676 var name = symbol.FileName;
677 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false)) 677 if (null == symbol.ShortFileName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
678 { 678 {
679 symbol.ShortFileName = CreateShortName(name, true, false, "IniFile", symbol.ComponentRef); 679 symbol.ShortFileName = this.CreateShortName(name, true, "IniFile", symbol.ComponentRef);
680 } 680 }
681 681
682 var row = this.CreateRow(symbol, tableName); 682 var row = this.CreateRow(symbol, tableName);
683 row[0] = symbol.Id.Id; 683 row[0] = symbol.Id.Id;
684 row[1] = GetMsiFilenameValue(symbol.ShortFileName, name); 684 row[1] = CreateMsiFilename(symbol.ShortFileName, name);
685 row[2] = symbol.DirProperty; 685 row[2] = symbol.DirProperty;
686 row[3] = symbol.Section; 686 row[3] = symbol.Section;
687 row[4] = symbol.Key; 687 row[4] = symbol.Key;
@@ -693,14 +693,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
693 private void AddIniLocatorSymbol(IniLocatorSymbol symbol) 693 private void AddIniLocatorSymbol(IniLocatorSymbol symbol)
694 { 694 {
695 var name = symbol.FileName; 695 var name = symbol.FileName;
696 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false)) 696 if (null == symbol.ShortFileName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
697 { 697 {
698 symbol.ShortFileName = CreateShortName(name, true, false, "IniFileSearch"); 698 symbol.ShortFileName = this.CreateShortName(name, true, "IniFileSearch");
699 } 699 }
700 700
701 var row = this.CreateRow(symbol, "IniLocator"); 701 var row = this.CreateRow(symbol, "IniLocator");
702 row[0] = symbol.Id.Id; 702 row[0] = symbol.Id.Id;
703 row[1] = GetMsiFilenameValue(symbol.ShortFileName, name); 703 row[1] = CreateMsiFilename(symbol.ShortFileName, name);
704 row[2] = symbol.Section; 704 row[2] = symbol.Section;
705 row[3] = symbol.Key; 705 row[3] = symbol.Key;
706 row[4] = symbol.Field; 706 row[4] = symbol.Field;
@@ -786,16 +786,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
786 private void AddMoveFileSymbol(MoveFileSymbol symbol) 786 private void AddMoveFileSymbol(MoveFileSymbol symbol)
787 { 787 {
788 var name = symbol.DestinationName; 788 var name = symbol.DestinationName;
789 if (null == symbol.DestinationShortName && null != name && !Common.IsValidShortFilename(name, false)) 789 if (null == symbol.DestinationShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
790 { 790 {
791 symbol.DestinationShortName = CreateShortName(name, true, false, "MoveFile", symbol.ComponentRef); 791 symbol.DestinationShortName = this.CreateShortName(name, true, "MoveFile", symbol.ComponentRef);
792 } 792 }
793 793
794 var row = this.CreateRow(symbol, "MoveFile"); 794 var row = this.CreateRow(symbol, "MoveFile");
795 row[0] = symbol.Id.Id; 795 row[0] = symbol.Id.Id;
796 row[1] = symbol.ComponentRef; 796 row[1] = symbol.ComponentRef;
797 row[2] = symbol.SourceName; 797 row[2] = symbol.SourceName;
798 row[3] = GetMsiFilenameValue(symbol.DestinationShortName, symbol.DestinationName); 798 row[3] = CreateMsiFilename(symbol.DestinationShortName, symbol.DestinationName);
799 row[4] = symbol.SourceFolder; 799 row[4] = symbol.SourceFolder;
800 row[5] = symbol.DestFolder; 800 row[5] = symbol.DestFolder;
801 row[6] = symbol.Delete ? WindowsInstallerConstants.MsidbMoveFileOptionsMove : 0; 801 row[6] = symbol.Delete ? WindowsInstallerConstants.MsidbMoveFileOptionsMove : 0;
@@ -816,9 +816,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
816 private void AddRemoveFileSymbol(RemoveFileSymbol symbol) 816 private void AddRemoveFileSymbol(RemoveFileSymbol symbol)
817 { 817 {
818 var name = symbol.FileName; 818 var name = symbol.FileName;
819 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false)) 819 if (null == symbol.ShortFileName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
820 { 820 {
821 symbol.ShortFileName = CreateShortName(name, true, false, "RemoveFile", symbol.ComponentRef); 821 symbol.ShortFileName = this.CreateShortName(name, true, "RemoveFile", symbol.ComponentRef);
822 } 822 }
823 823
824 var installMode = symbol.OnInstall == true ? WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall : 0; 824 var installMode = symbol.OnInstall == true ? WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall : 0;
@@ -827,7 +827,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
827 var row = this.CreateRow(symbol, "RemoveFile"); 827 var row = this.CreateRow(symbol, "RemoveFile");
828 row[0] = symbol.Id.Id; 828 row[0] = symbol.Id.Id;
829 row[1] = symbol.ComponentRef; 829 row[1] = symbol.ComponentRef;
830 row[2] = GetMsiFilenameValue(symbol.ShortFileName, symbol.FileName); 830 row[2] = CreateMsiFilename(symbol.ShortFileName, symbol.FileName);
831 row[3] = symbol.DirPropertyRef; 831 row[3] = symbol.DirPropertyRef;
832 row[4] = installMode; 832 row[4] = installMode;
833 } 833 }
@@ -966,15 +966,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind
966 private void AddShortcutSymbol(ShortcutSymbol symbol) 966 private void AddShortcutSymbol(ShortcutSymbol symbol)
967 { 967 {
968 var name = symbol.Name; 968 var name = symbol.Name;
969 if (null == symbol.ShortName && null != name && !Common.IsValidShortFilename(name, false)) 969 if (null == symbol.ShortName && null != name && !this.BackendHelper.IsValidShortFilename(name, false))
970 { 970 {
971 symbol.ShortName = CreateShortName(name, true, false, "Shortcut", symbol.ComponentRef, symbol.DirectoryRef); 971 symbol.ShortName = this.CreateShortName(name, true, "Shortcut", symbol.ComponentRef, symbol.DirectoryRef);
972 } 972 }
973 973
974 var row = this.CreateRow(symbol, "Shortcut"); 974 var row = this.CreateRow(symbol, "Shortcut");
975 row[0] = symbol.Id.Id; 975 row[0] = symbol.Id.Id;
976 row[1] = symbol.DirectoryRef; 976 row[1] = symbol.DirectoryRef;
977 row[2] = GetMsiFilenameValue(symbol.ShortName, name); 977 row[2] = CreateMsiFilename(symbol.ShortName, name);
978 row[3] = symbol.ComponentRef; 978 row[3] = symbol.ComponentRef;
979 row[4] = symbol.Target; 979 row[4] = symbol.Target;
980 row[5] = symbol.Arguments; 980 row[5] = symbol.Arguments;
@@ -1177,7 +1177,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1177 } 1177 }
1178 else if (rowField.Column.Category == ColumnCategory.Identifier) 1178 else if (rowField.Column.Category == ColumnCategory.Identifier)
1179 { 1179 {
1180 if (Common.IsIdentifier(data) || Common.IsValidBinderVariable(data) || ColumnCategory.Formatted == rowField.Column.Category) 1180 if (this.BackendHelper.IsValidIdentifier(data) || this.BackendHelper.IsValidBinderVariable(data) || ColumnCategory.Formatted == rowField.Column.Category)
1181 { 1181 {
1182 rowField.Data = data; 1182 rowField.Data = data;
1183 } 1183 }
@@ -1488,19 +1488,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1488 private Row CreateRow(IntermediateSymbol symbol, TableDefinition tableDefinition) => 1488 private Row CreateRow(IntermediateSymbol symbol, TableDefinition tableDefinition) =>
1489 this.BackendHelper.CreateRow(this.Section, symbol, this.Data, tableDefinition); 1489 this.BackendHelper.CreateRow(this.Section, symbol, this.Data, tableDefinition);
1490 1490
1491 private static string GetMsiFilenameValue(string shortName, string longName)
1492 {
1493 if (String.IsNullOrEmpty(shortName) || String.Equals(shortName, longName, StringComparison.OrdinalIgnoreCase))
1494 {
1495 return longName;
1496 }
1497 else
1498 {
1499 return shortName + "|" + longName;
1500 }
1501 }
1502 1491
1503 private static string CreateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args) 1492 private string CreateShortName(string longName, bool keepExtension, params string[] args)
1504 { 1493 {
1505 longName = longName.ToLowerInvariant(); 1494 longName = longName.ToLowerInvariant();
1506 1495
@@ -1537,7 +1526,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1537 shortName.Append(extension); 1526 shortName.Append(extension);
1538 1527
1539 // check the generated short name to ensure its still legal (the extension may not be legal) 1528 // check the generated short name to ensure its still legal (the extension may not be legal)
1540 if (!Common.IsValidShortFilename(shortName.ToString(), allowWildcards)) 1529 if (!this.BackendHelper.IsValidShortFilename(shortName.ToString(), false))
1541 { 1530 {
1542 // remove the extension (by truncating the generated file name back to the generated characters) 1531 // remove the extension (by truncating the generated file name back to the generated characters)
1543 shortName.Length -= extension.Length; 1532 shortName.Length -= extension.Length;
@@ -1546,5 +1535,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1546 1535
1547 return shortName.ToString().ToLowerInvariant(); 1536 return shortName.ToString().ToLowerInvariant();
1548 } 1537 }
1538
1539 private static string CreateMsiFilename(string shortName, string longName)
1540 {
1541 if (String.IsNullOrEmpty(shortName) || String.Equals(shortName, longName, StringComparison.OrdinalIgnoreCase))
1542 {
1543 return longName;
1544 }
1545 else
1546 {
1547 return shortName + "|" + longName;
1548 }
1549 }
1549 } 1550 }
1550} 1551}
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
index e33b38b1..d4de2dd3 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
@@ -11,19 +11,20 @@ namespace WixToolset.Core.WindowsInstaller.Bind
11 using System.Runtime.InteropServices; 11 using System.Runtime.InteropServices;
12 using WixToolset.Data; 12 using WixToolset.Data;
13 using WixToolset.Core.Native; 13 using WixToolset.Core.Native;
14 using WixToolset.Core.Bind;
15 using WixToolset.Data.Symbols; 14 using WixToolset.Data.Symbols;
16 using WixToolset.Extensibility.Services; 15 using WixToolset.Extensibility.Services;
17 using WixToolset.Core.WindowsInstaller.Msi; 16 using WixToolset.Core.WindowsInstaller.Msi;
17 using WixToolset.Extensibility.Data;
18 18
19 /// <summary> 19 /// <summary>
20 /// Retrieve files information and extract them from merge modules. 20 /// Retrieve files information and extract them from merge modules.
21 /// </summary> 21 /// </summary>
22 internal class ExtractMergeModuleFilesCommand 22 internal class ExtractMergeModuleFilesCommand
23 { 23 {
24 public ExtractMergeModuleFilesCommand(IMessaging messaging, IEnumerable<WixMergeSymbol> wixMergeSymbols, IEnumerable<FileFacade> fileFacades, int installerVersion, string intermediateFolder, bool suppressLayout) 24 public ExtractMergeModuleFilesCommand(IMessaging messaging, IWindowsInstallerBackendHelper backendHelper, IEnumerable<WixMergeSymbol> wixMergeSymbols, IEnumerable<IFileFacade> fileFacades, int installerVersion, string intermediateFolder, bool suppressLayout)
25 { 25 {
26 this.Messaging = messaging; 26 this.Messaging = messaging;
27 this.BackendHelper = backendHelper;
27 this.WixMergeSymbols = wixMergeSymbols; 28 this.WixMergeSymbols = wixMergeSymbols;
28 this.FileFacades = fileFacades; 29 this.FileFacades = fileFacades;
29 this.OutputInstallerVersion = installerVersion; 30 this.OutputInstallerVersion = installerVersion;
@@ -33,9 +34,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
33 34
34 private IMessaging Messaging { get; } 35 private IMessaging Messaging { get; }
35 36
37 private IWindowsInstallerBackendHelper BackendHelper { get; }
38
36 private IEnumerable<WixMergeSymbol> WixMergeSymbols { get; } 39 private IEnumerable<WixMergeSymbol> WixMergeSymbols { get; }
37 40
38 private IEnumerable<FileFacade> FileFacades { get; } 41 private IEnumerable<IFileFacade> FileFacades { get; }
39 42
40 private int OutputInstallerVersion { get; } 43 private int OutputInstallerVersion { get; }
41 44
@@ -43,11 +46,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
43 46
44 private bool SuppressLayout { get; } 47 private bool SuppressLayout { get; }
45 48
46 public IEnumerable<FileFacade> MergeModulesFileFacades { get; private set; } 49 public IEnumerable<IFileFacade> MergeModulesFileFacades { get; private set; }
47 50
48 public void Execute() 51 public void Execute()
49 { 52 {
50 var mergeModulesFileFacades = new List<FileFacade>(); 53 var mergeModulesFileFacades = new List<IFileFacade>();
51 54
52 var interop = new MsmInterop(); 55 var interop = new MsmInterop();
53 var merge = interop.GetMsmMerge(); 56 var merge = interop.GetMsmMerge();
@@ -75,7 +78,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
75 this.MergeModulesFileFacades = mergeModulesFileFacades; 78 this.MergeModulesFileFacades = mergeModulesFileFacades;
76 } 79 }
77 80
78 private bool CreateFacadesForMergeModuleFiles(WixMergeSymbol wixMergeRow, List<FileFacade> mergeModulesFileFacades, Dictionary<string, FileFacade> indexedFileFacades) 81 private bool CreateFacadesForMergeModuleFiles(WixMergeSymbol wixMergeRow, List<IFileFacade> mergeModulesFileFacades, Dictionary<string, IFileFacade> indexedFileFacades)
79 { 82 {
80 var containsFiles = false; 83 var containsFiles = false;
81 84
@@ -86,7 +89,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
86 { 89 {
87 if (db.TableExists("File") && db.TableExists("Component")) 90 if (db.TableExists("File") && db.TableExists("Component"))
88 { 91 {
89 var uniqueModuleFileIdentifiers = new Dictionary<string, FileFacade>(StringComparer.OrdinalIgnoreCase); 92 var uniqueModuleFileIdentifiers = new Dictionary<string, IFileFacade>(StringComparer.OrdinalIgnoreCase);
90 93
91 using (var view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`")) 94 using (var view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`"))
92 { 95 {
@@ -102,7 +105,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
102 fileSymbol.DiskId = wixMergeRow.DiskId; 105 fileSymbol.DiskId = wixMergeRow.DiskId;
103 fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) }; 106 fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) };
104 107
105 var mergeModuleFileFacade = new FileFacade(true, fileSymbol); 108 var mergeModuleFileFacade = this.BackendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
106 109
107 // If case-sensitive collision with another merge module or a user-authored file identifier. 110 // If case-sensitive collision with another merge module or a user-authored file identifier.
108 if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.Id, out var collidingFacade)) 111 if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.Id, out var collidingFacade))
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs
index c918e866..949d5e18 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs
@@ -6,36 +6,45 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Globalization; 7 using System.Globalization;
8 using System.Linq; 8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Data; 9 using WixToolset.Data;
11 using WixToolset.Data.Symbols; 10 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services;
12 13
13 internal class GetFileFacadesCommand 14 internal class GetFileFacadesCommand
14 { 15 {
15 public GetFileFacadesCommand(IntermediateSection section) 16 public GetFileFacadesCommand(IntermediateSection section, IWindowsInstallerBackendHelper backendHelper)
16 { 17 {
17 this.Section = section; 18 this.Section = section;
19 this.BackendHelper = backendHelper;
18 } 20 }
19 21
20 private IntermediateSection Section { get; } 22 private IntermediateSection Section { get; }
21 23
22 public List<FileFacade> FileFacades { get; private set; } 24 private IWindowsInstallerBackendHelper BackendHelper { get; }
25
26 public List<IFileFacade> FileFacades { get; private set; }
23 27
24 public void Execute() 28 public void Execute()
25 { 29 {
26 var facades = new List<FileFacade>(); 30 var facades = new List<IFileFacade>();
27 31
28 var assemblyFile = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id); 32 var assemblyFile = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id);
33#if TODO_PATCHING_DELTA
29 //var deltaPatchFiles = this.Section.Symbols.OfType<WixDeltaPatchFileSymbol>().ToDictionary(t => t.Id.Id); 34 //var deltaPatchFiles = this.Section.Symbols.OfType<WixDeltaPatchFileSymbol>().ToDictionary(t => t.Id.Id);
35#endif
30 36
31 foreach (var file in this.Section.Symbols.OfType<FileSymbol>()) 37 foreach (var file in this.Section.Symbols.OfType<FileSymbol>())
32 { 38 {
33 assemblyFile.TryGetValue(file.Id.Id, out var assembly); 39 assemblyFile.TryGetValue(file.Id.Id, out var assembly);
34 40
41#if TODO_PATCHING_DELTA
35 //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile); 42 //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile);
43 // TODO: should we be passing along delta information to the file facade? Probably, right?
44#endif
45 var fileFacade = this.BackendHelper.CreateFileFacade(file, assembly);
36 46
37 facades.Add(new FileFacade(file, assembly)); 47 facades.Add(fileFacade);
38 //facades.Add(new FileFacade(file, wixFile, deltaPatchFile));
39 } 48 }
40 49
41#if TODO_PATCHING_DELTA 50#if TODO_PATCHING_DELTA
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs
index 585bdac0..ca074631 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs
@@ -5,35 +5,35 @@ namespace WixToolset.Core.WindowsInstaller.Bind
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Linq; 7 using System.Linq;
8 using WixToolset.Core.Bind;
9 using WixToolset.Data; 8 using WixToolset.Data;
10 using WixToolset.Data.WindowsInstaller; 9 using WixToolset.Data.WindowsInstaller;
11 using WixToolset.Data.WindowsInstaller.Rows; 10 using WixToolset.Data.WindowsInstaller.Rows;
12 using WixToolset.Extensibility; 11 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services; 12 using WixToolset.Extensibility.Services;
14 13
15 internal class GetFileFacadesFromTransforms 14 internal class GetFileFacadesFromTransforms
16 { 15 {
17 public GetFileFacadesFromTransforms(IMessaging messaging, FileSystemManager fileSystemManager, IEnumerable<SubStorage> subStorages) 16 public GetFileFacadesFromTransforms(IMessaging messaging, IWindowsInstallerBackendHelper backendHelper, FileSystemManager fileSystemManager, IEnumerable<SubStorage> subStorages)
18 { 17 {
19 this.Messaging = messaging; 18 this.Messaging = messaging;
19 this.BackendHelper = backendHelper;
20 this.FileSystemManager = fileSystemManager; 20 this.FileSystemManager = fileSystemManager;
21 this.SubStorages = subStorages; 21 this.SubStorages = subStorages;
22 } 22 }
23 23
24 private IMessaging Messaging { get; } 24 private IMessaging Messaging { get; }
25 25
26 private IWindowsInstallerBackendHelper BackendHelper { get; }
27
26 private FileSystemManager FileSystemManager { get; } 28 private FileSystemManager FileSystemManager { get; }
27 29
28 private IEnumerable<SubStorage> SubStorages { get; } 30 private IEnumerable<SubStorage> SubStorages { get; }
29 31
30 public List<FileFacade> FileFacades { get; private set; } 32 public List<IFileFacade> FileFacades { get; private set; }
31 33
32 public void Execute() 34 public void Execute()
33 { 35 {
34 var allFileRows = new List<FileFacade>(); 36 var allFileRows = new List<IFileFacade>();
35
36 var patchMediaRows = new RowDictionary<MediaRow>();
37 37
38 var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>(); 38 var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>();
39 39
@@ -143,7 +143,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
143 143
144 mediaFileRows.Add(patchFileRow); 144 mediaFileRows.Add(patchFileRow);
145 145
146 allFileRows.Add(new FileFacade(patchFileRow)); // TODO: should we be passing along delta information? Probably, right? 146#if TODO_PATCHING_DELTA
147 // TODO: should we be passing along delta information to the file facade? Probably, right?
148#endif
149 var fileFacade = this.BackendHelper.CreateFileFacade(patchFileRow);
150
151 allFileRows.Add(fileFacade);
147 } 152 }
148 else 153 else
149 { 154 {
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
index 80684e7c..f8a1efd6 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
@@ -9,12 +9,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
9 using System.Linq; 9 using System.Linq;
10 using System.Runtime.InteropServices; 10 using System.Runtime.InteropServices;
11 using System.Text; 11 using System.Text;
12 using WixToolset.Core.Bind;
13 using WixToolset.Core.Native; 12 using WixToolset.Core.Native;
14 using WixToolset.Core.WindowsInstaller.Msi; 13 using WixToolset.Core.WindowsInstaller.Msi;
15 using WixToolset.Data; 14 using WixToolset.Data;
16 using WixToolset.Data.Symbols; 15 using WixToolset.Data.Symbols;
17 using WixToolset.Data.WindowsInstaller; 16 using WixToolset.Data.WindowsInstaller;
17 using WixToolset.Extensibility.Data;
18 using WixToolset.Extensibility.Services; 18 using WixToolset.Extensibility.Services;
19 19
20 /// <summary> 20 /// <summary>
@@ -22,7 +22,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
22 /// </summary> 22 /// </summary>
23 internal class MergeModulesCommand 23 internal class MergeModulesCommand
24 { 24 {
25 public MergeModulesCommand(IMessaging messaging, IEnumerable<FileFacade> fileFacades, IntermediateSection section, IEnumerable<string> suppressedTableNames, string outputPath, string intermediateFolder) 25 public MergeModulesCommand(IMessaging messaging, IEnumerable<IFileFacade> fileFacades, IntermediateSection section, IEnumerable<string> suppressedTableNames, string outputPath, string intermediateFolder)
26 { 26 {
27 this.Messaging = messaging; 27 this.Messaging = messaging;
28 this.FileFacades = fileFacades; 28 this.FileFacades = fileFacades;
@@ -34,7 +34,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
34 34
35 private IMessaging Messaging { get; } 35 private IMessaging Messaging { get; }
36 36
37 private IEnumerable<FileFacade> FileFacades { get; } 37 private IEnumerable<IFileFacade> FileFacades { get; }
38 38
39 private IntermediateSection Section { get; } 39 private IntermediateSection Section { get; }
40 40
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs
index 49ef1adf..04f1b771 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ModularizeCommand.cs
@@ -12,11 +12,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
12 using WixToolset.Data; 12 using WixToolset.Data;
13 using WixToolset.Data.Symbols; 13 using WixToolset.Data.Symbols;
14 using WixToolset.Data.WindowsInstaller; 14 using WixToolset.Data.WindowsInstaller;
15 using WixToolset.Extensibility.Services;
15 16
16 internal class ModularizeCommand 17 internal class ModularizeCommand
17 { 18 {
18 public ModularizeCommand(WindowsInstallerData output, string modularizationSuffix, IEnumerable<WixSuppressModularizationSymbol> suppressSymbols) 19 public ModularizeCommand(IBackendHelper backendHelper, WindowsInstallerData output, string modularizationSuffix, IEnumerable<WixSuppressModularizationSymbol> suppressSymbols)
19 { 20 {
21 this.BackendHelper = backendHelper;
20 this.Output = output; 22 this.Output = output;
21 this.ModularizationSuffix = modularizationSuffix; 23 this.ModularizationSuffix = modularizationSuffix;
22 24
@@ -24,6 +26,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
24 this.SuppressModularizationIdentifiers = new HashSet<string>(suppressSymbols.Select(s => s.SuppressIdentifier)); 26 this.SuppressModularizationIdentifiers = new HashSet<string>(suppressSymbols.Select(s => s.SuppressIdentifier));
25 } 27 }
26 28
29 private IBackendHelper BackendHelper { get; }
30
27 private WindowsInstallerData Output { get; } 31 private WindowsInstallerData Output { get; }
28 32
29 private string ModularizationSuffix { get; } 33 private string ModularizationSuffix { get; }
@@ -90,7 +94,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
90 case "SetTargetPath": 94 case "SetTargetPath":
91 case "SpawnDialog": 95 case "SpawnDialog":
92 case "SpawnWaitDialog": 96 case "SpawnWaitDialog":
93 if (Common.IsIdentifier(fieldData)) 97 if (this.BackendHelper.IsValidIdentifier(fieldData))
94 { 98 {
95 modularizeType = ColumnModularizeType.Column; 99 modularizeType = ColumnModularizeType.Column;
96 } 100 }
@@ -107,7 +111,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
107 else if (ColumnModularizeType.ControlText == field.Column.ModularizeType) 111 else if (ColumnModularizeType.ControlText == field.Column.ModularizeType)
108 { 112 {
109 // icons are stored in the Binary table, so they get column-type modularization 113 // icons are stored in the Binary table, so they get column-type modularization
110 if (("Bitmap" == row[2].ToString() || "Icon" == row[2].ToString()) && Common.IsIdentifier(fieldData)) 114 if (("Bitmap" == row[2].ToString() || "Icon" == row[2].ToString()) && this.BackendHelper.IsValidIdentifier(fieldData))
111 { 115 {
112 modularizeType = ColumnModularizeType.Column; 116 modularizeType = ColumnModularizeType.Column;
113 } 117 }
@@ -121,7 +125,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
121 { 125 {
122 case ColumnModularizeType.Column: 126 case ColumnModularizeType.Column:
123 // ensure the value is an identifier (otherwise it shouldn't be modularized this way) 127 // ensure the value is an identifier (otherwise it shouldn't be modularized this way)
124 if (!Common.IsIdentifier(fieldData)) 128 if (!this.BackendHelper.IsValidIdentifier(fieldData))
125 { 129 {
126 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixDataStrings.EXP_CannotModularizeIllegalID, fieldData)); 130 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixDataStrings.EXP_CannotModularizeIllegalID, fieldData));
127 } 131 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs
index 67515154..5dd4d3ea 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs
@@ -5,7 +5,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Linq; 7 using System.Linq;
8 using WixToolset.Core.Bind;
9 using WixToolset.Data; 8 using WixToolset.Data;
10 using WixToolset.Data.Symbols; 9 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility.Data; 10 using WixToolset.Extensibility.Data;
@@ -13,7 +12,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
13 12
14 internal class OptimizeFileFacadesOrderCommand 13 internal class OptimizeFileFacadesOrderCommand
15 { 14 {
16 public OptimizeFileFacadesOrderCommand(IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section, Platform platform, List<FileFacade> fileFacades) 15 public OptimizeFileFacadesOrderCommand(IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section, Platform platform, List<IFileFacade> fileFacades)
17 { 16 {
18 this.BackendHelper = helper; 17 this.BackendHelper = helper;
19 this.PathResolver = pathResolver; 18 this.PathResolver = pathResolver;
@@ -22,7 +21,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
22 this.FileFacades = fileFacades; 21 this.FileFacades = fileFacades;
23 } 22 }
24 23
25 public List<FileFacade> FileFacades { get; private set; } 24 public List<IFileFacade> FileFacades { get; private set; }
26 25
27 private IBackendHelper BackendHelper { get; } 26 private IBackendHelper BackendHelper { get; }
28 27
@@ -32,7 +31,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
32 31
33 private Platform Platform { get; } 32 private Platform Platform { get; }
34 33
35 public List<FileFacade> Execute() 34 public List<IFileFacade> Execute()
36 { 35 {
37 var canonicalComponentTargetPaths = this.ComponentTargetPaths(); 36 var canonicalComponentTargetPaths = this.ComponentTargetPaths();
38 37
@@ -69,7 +68,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
69 return targetPathsByDirectoryId; 68 return targetPathsByDirectoryId;
70 } 69 }
71 70
72 private class FileFacadeOptimizer : IComparer<FileFacade> 71 private class FileFacadeOptimizer : IComparer<IFileFacade>
73 { 72 {
74 public FileFacadeOptimizer(Dictionary<string, string> componentTargetPaths, bool optimizingMergeModule) 73 public FileFacadeOptimizer(Dictionary<string, string> componentTargetPaths, bool optimizingMergeModule)
75 { 74 {
@@ -81,7 +80,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
81 80
82 private bool OptimizingMergeModule { get; } 81 private bool OptimizingMergeModule { get; }
83 82
84 public int Compare(FileFacade x, FileFacade y) 83 public int Compare(IFileFacade x, IFileFacade y)
85 { 84 {
86 // First group files by DiskId but ignore if processing a Merge Module 85 // First group files by DiskId but ignore if processing a Merge Module
87 // because Merge Modules don't have separate disks. 86 // because Merge Modules don't have separate disks.
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs
index 7a7c2649..5ec93f49 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessDependencyReferencesCommand.cs
@@ -17,12 +17,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind
17 private const string DependencyRegistryRoot = @"Software\Classes\Installer\Dependencies\"; 17 private const string DependencyRegistryRoot = @"Software\Classes\Installer\Dependencies\";
18 private const string RegistryDependents = "Dependents"; 18 private const string RegistryDependents = "Dependents";
19 19
20 public ProcessDependencyReferencesCommand(IntermediateSection section, IEnumerable<WixDependencyRefSymbol> dependencyRefSymbols) 20 public ProcessDependencyReferencesCommand(IBackendHelper backendHelper, IntermediateSection section, IEnumerable<WixDependencyRefSymbol> dependencyRefSymbols)
21 { 21 {
22 this.BackendHelper = backendHelper;
22 this.Section = section; 23 this.Section = section;
23 this.DependencyRefSymbols = dependencyRefSymbols; 24 this.DependencyRefSymbols = dependencyRefSymbols;
24 } 25 }
25 26
27 private IBackendHelper BackendHelper { get; }
28
26 private IntermediateSection Section { get; } 29 private IntermediateSection Section { get; }
27 30
28 private IEnumerable<WixDependencyRefSymbol> DependencyRefSymbols { get; } 31 private IEnumerable<WixDependencyRefSymbol> DependencyRefSymbols { get; }
@@ -57,7 +60,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
57 // Get the component ID from the provider. 60 // Get the component ID from the provider.
58 var componentId = wixDependencyProviderRow.ComponentRef; 61 var componentId = wixDependencyProviderRow.ComponentRef;
59 62
60 var id = Common.GenerateIdentifier("reg", providesId, requiresId, "(Default)"); 63 var id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "(Default)");
61 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 64 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
62 { 65 {
63 ComponentRef = componentId, 66 ComponentRef = componentId,
@@ -68,7 +71,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
68 71
69 if (!String.IsNullOrEmpty(wixDependencyRow.MinVersion)) 72 if (!String.IsNullOrEmpty(wixDependencyRow.MinVersion))
70 { 73 {
71 id = Common.GenerateIdentifier("reg", providesId, requiresId, "MinVersion"); 74 id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "MinVersion");
72 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 75 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
73 { 76 {
74 ComponentRef = componentId, 77 ComponentRef = componentId,
@@ -79,10 +82,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
79 }); 82 });
80 } 83 }
81 84
82 string maxVersion = (string)wixDependencyRow[3]; 85 var maxVersion = (string)wixDependencyRow[3];
83 if (!String.IsNullOrEmpty(wixDependencyRow.MaxVersion)) 86 if (!String.IsNullOrEmpty(wixDependencyRow.MaxVersion))
84 { 87 {
85 id = Common.GenerateIdentifier("reg", providesId, requiresId, "MaxVersion"); 88 id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "MaxVersion");
86 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 89 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
87 { 90 {
88 ComponentRef = componentId, 91 ComponentRef = componentId,
@@ -95,7 +98,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
95 98
96 if (wixDependencyRow.Attributes != WixDependencySymbolAttributes.None) 99 if (wixDependencyRow.Attributes != WixDependencySymbolAttributes.None)
97 { 100 {
98 id = Common.GenerateIdentifier("reg", providesId, requiresId, "Attributes"); 101 id = this.BackendHelper.GenerateIdentifier("reg", providesId, requiresId, "Attributes");
99 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id)) 102 this.Section.AddSymbol(new RegistrySymbol(wixDependencyRefRow.SourceLineNumbers, new Identifier(AccessModifier.Section, id))
100 { 103 {
101 ComponentRef = componentId, 104 ComponentRef = componentId,
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
index ab5ebd4b..8c66a9e1 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
@@ -6,7 +6,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.IO; 7 using System.IO;
8 using System.Linq; 8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Core.WindowsInstaller.Msi; 9 using WixToolset.Core.WindowsInstaller.Msi;
11 using WixToolset.Data; 10 using WixToolset.Data;
12 using WixToolset.Data.Symbols; 11 using WixToolset.Data.Symbols;
@@ -33,7 +32,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
33 32
34 public string DatabasePath { private get; set; } 33 public string DatabasePath { private get; set; }
35 34
36 public IEnumerable<FileFacade> FileFacades { private get; set; } 35 public IEnumerable<IFileFacade> FileFacades { private get; set; }
37 36
38 public string LayoutDirectory { private get; set; } 37 public string LayoutDirectory { private get; set; }
39 38
@@ -63,7 +62,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
63 { 62 {
64 foreach (var directoryRecord in directoryView.Records) 63 foreach (var directoryRecord in directoryView.Records)
65 { 64 {
66 var sourceName = Common.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage); 65 var sourceName = this.BackendHelper.GetMsiFileName(directoryRecord.GetString(3), true, this.LongNamesInImage);
67 66
68 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName); 67 var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName);
69 68
@@ -71,16 +70,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
71 } 70 }
72 } 71 }
73 72
74 using (View fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?")) 73 using (var fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?"))
75 { 74 {
76 using (Record fileQueryRecord = new Record(1)) 75 using (var fileQueryRecord = new Record(1))
77 { 76 {
78 // for each file in the array of uncompressed files 77 // for each file in the array of uncompressed files
79 foreach (FileFacade facade in this.FileFacades) 78 foreach (var facade in this.FileFacades)
80 { 79 {
81 var mediaSymbol = mediaRows[facade.DiskId]; 80 var mediaSymbol = mediaRows[facade.DiskId];
82 string relativeFileLayoutPath = null; 81 string relativeFileLayoutPath = null;
83 string mediaLayoutFolder = mediaSymbol.Layout; 82 var mediaLayoutFolder = mediaSymbol.Layout;
84 83
85 var mediaLayoutDirectory = this.ResolveMedia(mediaSymbol, mediaLayoutFolder, this.LayoutDirectory); 84 var mediaLayoutDirectory = this.ResolveMedia(mediaSymbol, mediaLayoutFolder, this.LayoutDirectory);
86 85
@@ -89,7 +88,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
89 fileQueryRecord[1] = facade.Id; 88 fileQueryRecord[1] = facade.Id;
90 fileView.Execute(fileQueryRecord); 89 fileView.Execute(fileQueryRecord);
91 90
92 using (Record fileRecord = fileView.Fetch()) 91 using (var fileRecord = fileView.Fetch())
93 { 92 {
94 if (null == fileRecord) 93 if (null == fileRecord)
95 { 94 {
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
index f8819a0e..9cd14cfa 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
@@ -8,10 +8,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
8 using System.Globalization; 8 using System.Globalization;
9 using System.IO; 9 using System.IO;
10 using System.Linq; 10 using System.Linq;
11 using WixToolset.Core.Bind;
12 using WixToolset.Core.WindowsInstaller.Msi; 11 using WixToolset.Core.WindowsInstaller.Msi;
13 using WixToolset.Data; 12 using WixToolset.Data;
14 using WixToolset.Data.Symbols; 13 using WixToolset.Data.Symbols;
14 using WixToolset.Extensibility.Data;
15 using WixToolset.Extensibility.Services; 15 using WixToolset.Extensibility.Services;
16 16
17 /// <summary> 17 /// <summary>
@@ -19,7 +19,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
19 /// </summary> 19 /// </summary>
20 internal class UpdateFileFacadesCommand 20 internal class UpdateFileFacadesCommand
21 { 21 {
22 public UpdateFileFacadesCommand(IMessaging messaging, IntermediateSection section, IEnumerable<FileFacade> fileFacades, IEnumerable<FileFacade> updateFileFacades, IDictionary<string, string> variableCache, bool overwriteHash) 22 public UpdateFileFacadesCommand(IMessaging messaging, IntermediateSection section, IEnumerable<IFileFacade> fileFacades, IEnumerable<IFileFacade> updateFileFacades, IDictionary<string, string> variableCache, bool overwriteHash)
23 { 23 {
24 this.Messaging = messaging; 24 this.Messaging = messaging;
25 this.Section = section; 25 this.Section = section;
@@ -33,9 +33,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
33 33
34 private IntermediateSection Section { get; } 34 private IntermediateSection Section { get; }
35 35
36 private IEnumerable<FileFacade> FileFacades { get; } 36 private IEnumerable<IFileFacade> FileFacades { get; }
37 37
38 private IEnumerable<FileFacade> UpdateFileFacades { get; } 38 private IEnumerable<IFileFacade> UpdateFileFacades { get; }
39 39
40 private bool OverwriteHash { get; } 40 private bool OverwriteHash { get; }
41 41
@@ -51,7 +51,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
51 } 51 }
52 } 52 }
53 53
54 private void UpdateFileFacade(FileFacade facade, Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols) 54 private void UpdateFileFacade(IFileFacade facade, Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols)
55 { 55 {
56 FileInfo fileInfo = null; 56 FileInfo fileInfo = null;
57 try 57 try
@@ -314,7 +314,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
314 /// <param name="facade">FileFacade containing the assembly read for the MsiAssemblyName row.</param> 314 /// <param name="facade">FileFacade containing the assembly read for the MsiAssemblyName row.</param>
315 /// <param name="name">MsiAssemblyName name.</param> 315 /// <param name="name">MsiAssemblyName name.</param>
316 /// <param name="value">MsiAssemblyName value.</param> 316 /// <param name="value">MsiAssemblyName value.</param>
317 private void SetMsiAssemblyName(Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols, FileFacade facade, string name, string value) 317 private void SetMsiAssemblyName(Dictionary<string, MsiAssemblyNameSymbol> assemblyNameSymbols, IFileFacade facade, string name, string value)
318 { 318 {
319 // check for null value (this can occur when grabbing the file version from an assembly without one) 319 // check for null value (this can occur when grabbing the file version from an assembly without one)
320 if (String.IsNullOrEmpty(value)) 320 if (String.IsNullOrEmpty(value))
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs
index d3f2b9ea..affec09f 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs
@@ -4,13 +4,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
4{ 4{
5 using System.Collections.Generic; 5 using System.Collections.Generic;
6 using System.Linq; 6 using System.Linq;
7 using WixToolset.Core.Bind;
8 using WixToolset.Data; 7 using WixToolset.Data;
9 using WixToolset.Data.Symbols; 8 using WixToolset.Data.Symbols;
9 using WixToolset.Extensibility.Data;
10 10
11 internal class UpdateMediaSequencesCommand 11 internal class UpdateMediaSequencesCommand
12 { 12 {
13 public UpdateMediaSequencesCommand(IntermediateSection section, List<FileFacade> fileFacades) 13 public UpdateMediaSequencesCommand(IntermediateSection section, IEnumerable<IFileFacade> fileFacades)
14 { 14 {
15 this.Section = section; 15 this.Section = section;
16 this.FileFacades = fileFacades; 16 this.FileFacades = fileFacades;
@@ -18,7 +18,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18 18
19 private IntermediateSection Section { get; } 19 private IntermediateSection Section { get; }
20 20
21 private List<FileFacade> FileFacades { get; } 21 private IEnumerable<IFileFacade> FileFacades { get; }
22 22
23 public void Execute() 23 public void Execute()
24 { 24 {
@@ -38,9 +38,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
38 { 38 {
39 var lastSequence = 0; 39 var lastSequence = 0;
40 MediaSymbol mediaSymbol = null; 40 MediaSymbol mediaSymbol = null;
41 var patchGroups = new Dictionary<int, List<FileFacade>>(); 41 var patchGroups = new Dictionary<int, List<IFileFacade>>();
42 42
43 // sequence the non-patch-added files 43 // Sequence the non-patch-added files.
44 foreach (var facade in this.FileFacades) 44 foreach (var facade in this.FileFacades)
45 { 45 {
46 if (null == mediaSymbol) 46 if (null == mediaSymbol)
@@ -62,7 +62,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
62 { 62 {
63 if (patchGroups.TryGetValue(facade.PatchGroup.Value, out var patchGroup)) 63 if (patchGroups.TryGetValue(facade.PatchGroup.Value, out var patchGroup))
64 { 64 {
65 patchGroup = new List<FileFacade>(); 65 patchGroup = new List<IFileFacade>();
66 patchGroups.Add(facade.PatchGroup.Value, patchGroup); 66 patchGroups.Add(facade.PatchGroup.Value, patchGroup);
67 } 67 }
68 68
@@ -80,7 +80,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
80 mediaSymbol = null; 80 mediaSymbol = null;
81 } 81 }
82 82
83 // sequence the patch-added files 83 // Sequence the patch-added files.
84 foreach (var patchGroup in patchGroups.Values) 84 foreach (var patchGroup in patchGroups.Values)
85 { 85 {
86 foreach (var facade in patchGroup) 86 foreach (var facade in patchGroup)
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs
index 4e716a47..981fa0a4 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs
@@ -5,16 +5,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Linq; 7 using System.Linq;
8 using WixToolset.Core.Bind;
9 using WixToolset.Data; 8 using WixToolset.Data;
10 using WixToolset.Data.Symbols; 9 using WixToolset.Data.Symbols;
11 using WixToolset.Data.WindowsInstaller; 10 using WixToolset.Data.WindowsInstaller;
12 using WixToolset.Data.WindowsInstaller.Rows; 11 using WixToolset.Data.WindowsInstaller.Rows;
12 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services; 13 using WixToolset.Extensibility.Services;
14 14
15 internal class UpdateTransformsWithFileFacades 15 internal class UpdateTransformsWithFileFacades
16 { 16 {
17 public UpdateTransformsWithFileFacades(IMessaging messaging, WindowsInstallerData output, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable<FileFacade> fileFacades) 17 public UpdateTransformsWithFileFacades(IMessaging messaging, WindowsInstallerData output, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable<IFileFacade> fileFacades)
18 { 18 {
19 this.Messaging = messaging; 19 this.Messaging = messaging;
20 this.Output = output; 20 this.Output = output;
@@ -31,18 +31,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
31 31
32 private TableDefinitionCollection TableDefinitions { get; } 32 private TableDefinitionCollection TableDefinitions { get; }
33 33
34 private IEnumerable<FileFacade> FileFacades { get; } 34 private IEnumerable<IFileFacade> FileFacades { get; }
35 35
36 public void Execute() 36 public void Execute()
37 { 37 {
38 var fileFacadesByDiskId = new Dictionary<int, Dictionary<string, FileFacade>>(); 38 var fileFacadesByDiskId = new Dictionary<int, Dictionary<string, IFileFacade>>();
39 39
40 // Index patch file facades by diskId+fileId. 40 // Index patch file facades by diskId+fileId.
41 foreach (var facade in this.FileFacades) 41 foreach (var facade in this.FileFacades)
42 { 42 {
43 if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades)) 43 if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades))
44 { 44 {
45 mediaFacades = new Dictionary<string, FileFacade>(); 45 mediaFacades = new Dictionary<string, IFileFacade>();
46 fileFacadesByDiskId.Add(facade.DiskId, mediaFacades); 46 fileFacadesByDiskId.Add(facade.DiskId, mediaFacades);
47 } 47 }
48 48
@@ -97,7 +97,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
97 // Index patch files by diskId+fileId 97 // Index patch files by diskId+fileId
98 if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades)) 98 if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades))
99 { 99 {
100 mediaFacades = new Dictionary<string, FileFacade>(); 100 mediaFacades = new Dictionary<string, IFileFacade>();
101 fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades); 101 fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades);
102 } 102 }
103 103
diff --git a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd b/src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd
deleted file mode 100644
index bf0ccb95..00000000
--- a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/actions.xsd
+++ /dev/null
@@ -1,73 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
6 targetNamespace="http://wixtoolset.org/schemas/v4/wi/actions"
7 xmlns="http://wixtoolset.org/schemas/v4/wi/actions">
8 <xs:annotation>
9 <xs:documentation>
10 Schema for describing standard actions in the Windows Installer.
11 </xs:documentation>
12 </xs:annotation>
13
14 <xs:element name="actions">
15 <xs:complexType>
16 <xs:sequence maxOccurs="unbounded">
17 <xs:element ref="action" />
18 </xs:sequence>
19 </xs:complexType>
20 </xs:element>
21
22 <xs:element name="action">
23 <xs:complexType>
24 <xs:attribute name="name" type="xs:string" use="required">
25 <xs:annotation>
26 <xs:documentation>Name of action</xs:documentation>
27 </xs:annotation>
28 </xs:attribute>
29 <xs:attribute name="condition" type="xs:string">
30 <xs:annotation>
31 <xs:documentation>Default condition for action</xs:documentation>
32 </xs:annotation>
33 </xs:attribute>
34 <xs:attribute name="sequence" type="xs:integer" use="required">
35 <xs:annotation>
36 <xs:documentation>Sequence of action</xs:documentation>
37 </xs:annotation>
38 </xs:attribute>
39 <xs:attribute name="AdminExecuteSequence" type="ActionsYesNoType">
40 <xs:annotation>
41 <xs:documentation>Specifies if action is allowed in AdminExecuteSequence</xs:documentation>
42 </xs:annotation>
43 </xs:attribute>
44 <xs:attribute name="AdminUISequence" type="ActionsYesNoType">
45 <xs:annotation>
46 <xs:documentation>Specifies if action is allowed in AdminUISequence</xs:documentation>
47 </xs:annotation>
48 </xs:attribute>
49 <xs:attribute name="AdvtExecuteSequence" type="ActionsYesNoType">
50 <xs:annotation>
51 <xs:documentation>Specifies if action is allowed in AdvtExecuteSequence</xs:documentation>
52 </xs:annotation>
53 </xs:attribute>
54 <xs:attribute name="InstallExecuteSequence" type="ActionsYesNoType">
55 <xs:annotation>
56 <xs:documentation>Specifies if action is allowed in InstallExecuteSequence</xs:documentation>
57 </xs:annotation>
58 </xs:attribute>
59 <xs:attribute name="InstallUISequence" type="ActionsYesNoType">
60 <xs:annotation>
61 <xs:documentation>Specifies if action is allowed in InstallUISequence</xs:documentation>
62 </xs:annotation>
63 </xs:attribute>
64 </xs:complexType>
65 </xs:element>
66
67 <xs:simpleType name="ActionsYesNoType">
68 <xs:restriction base="xs:NMTOKEN">
69 <xs:enumeration value="no" />
70 <xs:enumeration value="yes" />
71 </xs:restriction>
72 </xs:simpleType>
73</xs:schema>
diff --git a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd b/src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd
deleted file mode 100644
index f87471bb..00000000
--- a/src/WixToolset.Core.WindowsInstaller/Data/Xsd/tables.xsd
+++ /dev/null
@@ -1,248 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
6 targetNamespace="http://wixtoolset.org/schemas/v4/wi/tables"
7 xmlns="http://wixtoolset.org/schemas/v4/wi/tables">
8 <xs:annotation>
9 <xs:documentation>
10 Schema for describing table definitions in Windows Installer.
11 </xs:documentation>
12 </xs:annotation>
13
14 <xs:element name="tableDefinitions">
15 <xs:complexType>
16 <xs:sequence maxOccurs="unbounded">
17 <xs:element ref="tableDefinition" />
18 </xs:sequence>
19 </xs:complexType>
20 </xs:element>
21
22 <xs:element name="tableDefinition">
23 <xs:complexType>
24 <xs:sequence maxOccurs="unbounded">
25 <xs:element ref="columnDefinition" />
26 </xs:sequence>
27 <xs:attribute name="createSymbols" type="TablesYesNoType">
28 <xs:annotation>
29 <xs:documentation>Boolean whether rows in this table create symbols</xs:documentation>
30 </xs:annotation>
31 </xs:attribute>
32 <xs:attribute name="name" type="NameType" use="required">
33 <xs:annotation>
34 <xs:documentation>Name of table in Windows Installer database</xs:documentation>
35 </xs:annotation>
36 </xs:attribute>
37 <xs:attribute name="unreal" type="TablesYesNoType">
38 <xs:annotation>
39 <xs:documentation>Specifies if table is virtual or not</xs:documentation>
40 </xs:annotation>
41 </xs:attribute>
42 <xs:attribute name="bootstrapperApplicationData" type="TablesYesNoType">
43 <xs:annotation>
44 <xs:documentation>Specifies if the table is a part of the Bootstrapper Application Data manifest</xs:documentation>
45 </xs:annotation>
46 </xs:attribute>
47 </xs:complexType>
48 </xs:element>
49
50 <xs:element name="columnDefinition">
51 <xs:complexType>
52 <xs:attribute name="name" type="NameType" use="required">
53 <xs:annotation>
54 <xs:documentation>Name of column in Windows Installer table</xs:documentation>
55 </xs:annotation>
56 </xs:attribute>
57
58 <xs:attribute name="added" type="TablesYesNoType">
59 <xs:annotation>
60 <xs:documentation>Whether this column was added by a transform.</xs:documentation>
61 </xs:annotation>
62 </xs:attribute>
63
64 <xs:attribute name="type" type="ColumnDefinitionType" use="required">
65 <xs:annotation>
66 <xs:documentation>Type of column in Windows Installer table</xs:documentation>
67 </xs:annotation>
68 </xs:attribute>
69
70 <xs:attribute name="length" use="required">
71 <xs:annotation>
72 <xs:documentation>Type of column in Windows Installer table</xs:documentation>
73 </xs:annotation>
74 <xs:simpleType>
75 <xs:restriction base="xs:integer">
76 <xs:minInclusive value="0" />
77 <xs:maxInclusive value="255" />
78 </xs:restriction>
79 </xs:simpleType>
80 </xs:attribute>
81
82 <xs:attribute name="primaryKey" type="TablesYesNoType">
83 <xs:annotation>
84 <xs:documentation>Boolean whether column is primary key of Windows Installer table</xs:documentation>
85 </xs:annotation>
86 </xs:attribute>
87
88 <xs:attribute name="nullable" type="TablesYesNoType">
89 <xs:annotation>
90 <xs:documentation>Boolean whether column is nullable in Windows Installer table</xs:documentation>
91 </xs:annotation>
92 </xs:attribute>
93
94 <xs:attribute name="unreal" type="TablesYesNoType">
95 <xs:annotation>
96 <xs:documentation>Boolean whether column is virtual in Windows Installer table</xs:documentation>
97 </xs:annotation>
98 </xs:attribute>
99
100 <xs:attribute name="modularize" type="TablesModularizeType">
101 <xs:annotation>
102 <xs:documentation>Enumeration specifying how column should have the ModuleId appended</xs:documentation>
103 </xs:annotation>
104 </xs:attribute>
105
106 <xs:attribute name="localizable" type="TablesYesNoType">
107 <xs:annotation>
108 <xs:documentation>Set to "yes" in order to allow substitution for localized variables.</xs:documentation>
109 </xs:annotation>
110 </xs:attribute>
111
112 <xs:attribute name="minValue" type="xs:long">
113 <xs:annotation>
114 <xs:documentation>Minimum value for column in Windows Installer table</xs:documentation>
115 </xs:annotation>
116 </xs:attribute>
117
118 <xs:attribute name="maxValue" type="xs:long">
119 <xs:annotation>
120 <xs:documentation>Maximum value for column in Windows Installer table</xs:documentation>
121 </xs:annotation>
122 </xs:attribute>
123
124 <xs:attribute name="keyTable" type="NameType">
125 <xs:annotation>
126 <xs:documentation>Foreign key table for column in Windows Installer table</xs:documentation>
127 </xs:annotation>
128 </xs:attribute>
129
130 <xs:attribute name="keyColumn">
131 <xs:annotation>
132 <xs:documentation>Maximum value for column in Windows Installer table</xs:documentation>
133 </xs:annotation>
134 <xs:simpleType>
135 <xs:restriction base="xs:integer">
136 <xs:minInclusive value="1" />
137 <xs:maxInclusive value="32" />
138 </xs:restriction>
139 </xs:simpleType>
140 </xs:attribute>
141
142 <xs:attribute name="category" type="TablesCategoryType">
143 <xs:annotation>
144 <xs:documentation>Specific column data types for column</xs:documentation>
145 </xs:annotation>
146 </xs:attribute>
147
148 <xs:attribute name="set" type="TablesSetType">
149 <xs:annotation>
150 <xs:documentation>List of permissible values for the column</xs:documentation>
151 </xs:annotation>
152 </xs:attribute>
153
154 <xs:attribute name="description" type="xs:string">
155 <xs:annotation>
156 <xs:documentation>Description of column</xs:documentation>
157 </xs:annotation>
158 </xs:attribute>
159
160 <xs:attribute name="escapeIdtCharacters" type="TablesYesNoType">
161 <xs:annotation>
162 <xs:documentation>Set to "yes" in order to make the idt exporter escape whitespace characters \r, \n, and \t.</xs:documentation>
163 </xs:annotation>
164 </xs:attribute>
165
166 <xs:attribute name="useCData" type="TablesYesNoType">
167 <xs:annotation>
168 <xs:documentation>Set to "yes" in order to make the Intermediate and Output objects wrap their data in a CDATA element to preserve whitespace.</xs:documentation>
169 </xs:annotation>
170 </xs:attribute>
171 </xs:complexType>
172 </xs:element>
173
174 <xs:simpleType name="NameType">
175 <xs:restriction base="xs:string">
176 <xs:minLength value="1" />
177 <xs:maxLength value="64" />
178 </xs:restriction>
179 </xs:simpleType>
180
181 <xs:simpleType name="ColumnDefinitionType">
182 <xs:restriction base="xs:NMTOKEN">
183 <xs:enumeration value="string" />
184 <xs:enumeration value="localized" />
185 <xs:enumeration value="number" />
186 <xs:enumeration value="object" />
187 <xs:enumeration value="preserved" />
188 </xs:restriction>
189 </xs:simpleType>
190
191 <xs:simpleType name="TablesYesNoType">
192 <xs:restriction base="xs:NMTOKEN">
193 <xs:enumeration value="yes" />
194 <xs:enumeration value="no" />
195 </xs:restriction>
196 </xs:simpleType>
197
198 <xs:simpleType name="TablesModularizeType">
199 <xs:restriction base="xs:NMTOKEN">
200 <xs:enumeration value="column" />
201 <xs:enumeration value="companionFile" />
202 <xs:enumeration value="condition" />
203 <xs:enumeration value="controlEventArgument" />
204 <xs:enumeration value="controlText" />
205 <xs:enumeration value="icon" />
206 <xs:enumeration value="none" />
207 <xs:enumeration value="property" />
208 <xs:enumeration value="semicolonDelimited" />
209 </xs:restriction>
210 </xs:simpleType>
211
212 <xs:simpleType name="TablesCategoryType">
213 <xs:restriction base="xs:NMTOKEN">
214 <xs:enumeration value="text" />
215 <xs:enumeration value="upperCase" />
216 <xs:enumeration value="lowerCase" />
217 <xs:enumeration value="integer" />
218 <xs:enumeration value="doubleInteger" />
219 <xs:enumeration value="timeDate" />
220 <xs:enumeration value="identifier" />
221 <xs:enumeration value="property" />
222 <xs:enumeration value="filename" />
223 <xs:enumeration value="wildCardFilename" />
224 <xs:enumeration value="path" />
225 <xs:enumeration value="paths" />
226 <xs:enumeration value="anyPath" />
227 <xs:enumeration value="defaultDir" />
228 <xs:enumeration value="regPath" />
229 <xs:enumeration value="formatted" />
230 <xs:enumeration value="formattedSddl" />
231 <xs:enumeration value="template" />
232 <xs:enumeration value="condition" />
233 <xs:enumeration value="guid" />
234 <xs:enumeration value="version" />
235 <xs:enumeration value="language" />
236 <xs:enumeration value="binary" />
237 <xs:enumeration value="customSource" />
238 <xs:enumeration value="cabinet" />
239 <xs:enumeration value="shortcut" />
240 </xs:restriction>
241 </xs:simpleType>
242
243 <xs:simpleType name="TablesSetType">
244 <xs:restriction base="xs:string">
245 <xs:pattern value="\w+(;\w+)*" />
246 </xs:restriction>
247 </xs:simpleType>
248</xs:schema>
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
index 45b669b9..849cb361 100644
--- a/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
@@ -1,6 +1,6 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. 1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 2
3namespace WixToolset.Core.WindowsInstaller.Unbind 3namespace WixToolset.Core.WindowsInstaller.Decompile
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
@@ -8,6 +8,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
8 using System.IO; 8 using System.IO;
9 using System.Linq; 9 using System.Linq;
10 using WixToolset.Core.WindowsInstaller.Msi; 10 using WixToolset.Core.WindowsInstaller.Msi;
11 using WixToolset.Core.WindowsInstaller.Unbind;
11 using WixToolset.Data; 12 using WixToolset.Data;
12 using WixToolset.Data.WindowsInstaller; 13 using WixToolset.Data.WindowsInstaller;
13 using WixToolset.Extensibility; 14 using WixToolset.Extensibility;
@@ -43,11 +44,13 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
43 Directory.Delete(this.Context.ExtractFolder, true); 44 Directory.Delete(this.Context.ExtractFolder, true);
44 } 45 }
45 46
46 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, database, this.Context.DecompilePath, this.Context.DecompileType, this.Context.ExtractFolder, this.Context.IntermediateFolder, this.Context.IsAdminImage, suppressDemodularization: false, skipSummaryInfo: false); 47 var backendHelper = this.Context.ServiceProvider.GetService<IBackendHelper>();
48
49 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, backendHelper, database, this.Context.DecompilePath, this.Context.DecompileType, this.Context.ExtractFolder, this.Context.IntermediateFolder, this.Context.IsAdminImage, suppressDemodularization: false, skipSummaryInfo: false);
47 var output = unbindCommand.Execute(); 50 var output = unbindCommand.Execute();
48 var extractedFilePaths = new List<string>(unbindCommand.ExportedFiles); 51 var extractedFilePaths = new List<string>(unbindCommand.ExportedFiles);
49 52
50 var decompiler = new Decompiler(this.Messaging, this.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressUI, this.Context.TreatProductAsModule); 53 var decompiler = new Decompiler(this.Messaging, backendHelper, this.Extensions, this.Context.BaseSourcePath, this.Context.SuppressCustomTables, this.Context.SuppressDroppingEmptyTables, this.Context.SuppressUI, this.Context.TreatProductAsModule);
51 result.Document = decompiler.Decompile(output); 54 result.Document = decompiler.Decompile(output);
52 55
53 result.Platform = GetPlatformFromOutput(output); 56 result.Platform = GetPlatformFromOutput(output);
diff --git a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
index 2cc61666..8e477dd1 100644
--- a/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
@@ -1,6 +1,6 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. 1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 2
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller.Decompile
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
@@ -10,8 +10,6 @@ namespace WixToolset.Core.WindowsInstaller
10 using System.Text; 10 using System.Text;
11 using System.Text.RegularExpressions; 11 using System.Text.RegularExpressions;
12 using System.Xml.Linq; 12 using System.Xml.Linq;
13 using WixToolset.Core;
14 using WixToolset.Core.WindowsInstaller.Decompile;
15 using WixToolset.Data; 13 using WixToolset.Data;
16 using WixToolset.Data.Symbols; 14 using WixToolset.Data.Symbols;
17 using WixToolset.Data.WindowsInstaller; 15 using WixToolset.Data.WindowsInstaller;
@@ -45,9 +43,10 @@ namespace WixToolset.Core.WindowsInstaller
45 /// <summary> 43 /// <summary>
46 /// Creates a new decompiler object with a default set of table definitions. 44 /// Creates a new decompiler object with a default set of table definitions.
47 /// </summary> 45 /// </summary>
48 public Decompiler(IMessaging messaging, IEnumerable<IWindowsInstallerBackendDecompilerExtension> extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressUI, bool treatProductAsModule) 46 public Decompiler(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IWindowsInstallerBackendDecompilerExtension> extensions, string baseSourcePath, bool suppressCustomTables, bool suppressDroppingEmptyTables, bool suppressUI, bool treatProductAsModule)
49 { 47 {
50 this.Messaging = messaging; 48 this.Messaging = messaging;
49 this.BackendHelper = backendHelper;
51 this.Extensions = extensions; 50 this.Extensions = extensions;
52 this.BaseSourcePath = baseSourcePath ?? "SourceDir"; 51 this.BaseSourcePath = baseSourcePath ?? "SourceDir";
53 this.SuppressCustomTables = suppressCustomTables; 52 this.SuppressCustomTables = suppressCustomTables;
@@ -63,6 +62,8 @@ namespace WixToolset.Core.WindowsInstaller
63 62
64 private IMessaging Messaging { get; } 63 private IMessaging Messaging { get; }
65 64
65 private IBackendHelper BackendHelper { get; }
66
66 private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; } 67 private IEnumerable<IWindowsInstallerBackendDecompilerExtension> Extensions { get; }
67 68
68 private Dictionary<string, IWindowsInstallerBackendDecompilerExtension> ExtensionsByTableName { get; } 69 private Dictionary<string, IWindowsInstallerBackendDecompilerExtension> ExtensionsByTableName { get; }
@@ -2196,11 +2197,11 @@ namespace WixToolset.Core.WindowsInstaller
2196 { 2197 {
2197 foreach (var launchRow in launchConditionTable.Rows) 2198 foreach (var launchRow in launchConditionTable.Rows)
2198 { 2199 {
2199 if (Common.DowngradePreventedCondition == Convert.ToString(launchRow[0])) 2200 if (WixUpgradeConstants.DowngradePreventedCondition == Convert.ToString(launchRow[0]))
2200 { 2201 {
2201 downgradeErrorMessage = Convert.ToString(launchRow[1]); 2202 downgradeErrorMessage = Convert.ToString(launchRow[1]);
2202 } 2203 }
2203 else if (Common.UpgradePreventedCondition == Convert.ToString(launchRow[0])) 2204 else if (WixUpgradeConstants.UpgradePreventedCondition == Convert.ToString(launchRow[0]))
2204 { 2205 {
2205 disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]); 2206 disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]);
2206 } 2207 }
@@ -2213,7 +2214,7 @@ namespace WixToolset.Core.WindowsInstaller
2213 2214
2214 foreach (UpgradeRow upgradeRow in upgradeTable.Rows) 2215 foreach (UpgradeRow upgradeRow in upgradeTable.Rows)
2215 { 2216 {
2216 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty) 2217 if (WixUpgradeConstants.UpgradeDetectedProperty == upgradeRow.ActionProperty)
2217 { 2218 {
2218 var attr = upgradeRow.Attributes; 2219 var attr = upgradeRow.Attributes;
2219 var removeFeatures = upgradeRow.Remove; 2220 var removeFeatures = upgradeRow.Remove;
@@ -2239,7 +2240,7 @@ namespace WixToolset.Core.WindowsInstaller
2239 xMajorUpgrade.SetAttributeValue("RemoveFeatures", removeFeatures); 2240 xMajorUpgrade.SetAttributeValue("RemoveFeatures", removeFeatures);
2240 } 2241 }
2241 } 2242 }
2242 else if (Common.DowngradeDetectedProperty == upgradeRow.ActionProperty) 2243 else if (WixUpgradeConstants.DowngradeDetectedProperty == upgradeRow.ActionProperty)
2243 { 2244 {
2244 xMajorUpgrade = xMajorUpgrade ?? new XElement(Names.MajorUpgradeElement); 2245 xMajorUpgrade = xMajorUpgrade ?? new XElement(Names.MajorUpgradeElement);
2245 xMajorUpgrade.SetAttributeValue("DowngradeErrorMessage", downgradeErrorMessage); 2246 xMajorUpgrade.SetAttributeValue("DowngradeErrorMessage", downgradeErrorMessage);
@@ -4291,7 +4292,7 @@ namespace WixToolset.Core.WindowsInstaller
4291 var xDirectory = new XElement(Names.DirectoryElement, 4292 var xDirectory = new XElement(Names.DirectoryElement,
4292 new XAttribute("Id", id)); 4293 new XAttribute("Id", id));
4293 4294
4294 var names = Common.GetNames(row.FieldAsString(2)); 4295 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(2));
4295 4296
4296 if (String.Equals(id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal)) 4297 if (String.Equals(id, "TARGETDIR", StringComparison.Ordinal) && !String.Equals(names[0], "SourceDir", StringComparison.Ordinal))
4297 { 4298 {
@@ -4396,7 +4397,7 @@ namespace WixToolset.Core.WindowsInstaller
4396 4397
4397 if (!row.IsColumnNull(3)) 4398 if (!row.IsColumnNull(3))
4398 { 4399 {
4399 var names = Common.GetNames(row.FieldAsString(3)); 4400 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(3));
4400 if (null != names[0] && null != names[1]) 4401 if (null != names[0] && null != names[1])
4401 { 4402 {
4402 xCopyFile.SetAttributeValue("DestinationShortName", names[0]); 4403 xCopyFile.SetAttributeValue("DestinationShortName", names[0]);
@@ -4782,7 +4783,7 @@ namespace WixToolset.Core.WindowsInstaller
4782 WindowsInstallerConstants.MsidbFileAttributesVital != (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesVital) ? new XAttribute("Vital", "no") : null, 4783 WindowsInstallerConstants.MsidbFileAttributesVital != (fileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesVital) ? new XAttribute("Vital", "no") : null,
4783 null != fileRow.Version && 0 < fileRow.Version.Length && !Char.IsDigit(fileRow.Version[0]) ? new XAttribute("CompanionFile", fileRow.Version) : null); 4784 null != fileRow.Version && 0 < fileRow.Version.Length && !Char.IsDigit(fileRow.Version[0]) ? new XAttribute("CompanionFile", fileRow.Version) : null);
4784 4785
4785 var names = Common.GetNames(fileRow.FileName); 4786 var names = this.BackendHelper.SplitMsiFileName(fileRow.FileName);
4786 if (null != names[0] && null != names[1]) 4787 if (null != names[0] && null != names[1])
4787 { 4788 {
4788 xFile.SetAttributeValue("ShortName", names[0]); 4789 xFile.SetAttributeValue("ShortName", names[0]);
@@ -4904,7 +4905,7 @@ namespace WixToolset.Core.WindowsInstaller
4904 new XAttribute("Value", row.FieldAsString(5)), 4905 new XAttribute("Value", row.FieldAsString(5)),
4905 row.IsColumnNull(2) ? null : new XAttribute("Directory", row.FieldAsString(2))); 4906 row.IsColumnNull(2) ? null : new XAttribute("Directory", row.FieldAsString(2)));
4906 4907
4907 var names = Common.GetNames(row.FieldAsString(1)); 4908 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
4908 4909
4909 if (null != names[0]) 4910 if (null != names[0])
4910 { 4911 {
@@ -4957,7 +4958,7 @@ namespace WixToolset.Core.WindowsInstaller
4957 new XAttribute("Key", row.FieldAsString(3)), 4958 new XAttribute("Key", row.FieldAsString(3)),
4958 row.IsColumnNull(4) || row.FieldAsInteger(4) == 0 ? null : new XAttribute("Field", row.FieldAsInteger(4))); 4959 row.IsColumnNull(4) || row.FieldAsInteger(4) == 0 ? null : new XAttribute("Field", row.FieldAsInteger(4)));
4959 4960
4960 var names = Common.GetNames(row.FieldAsString(1)); 4961 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
4961 if (null != names[0] && null != names[1]) 4962 if (null != names[0] && null != names[1])
4962 { 4963 {
4963 xIniFileSearch.SetAttributeValue("ShortName", names[0]); 4964 xIniFileSearch.SetAttributeValue("ShortName", names[0]);
@@ -5014,7 +5015,7 @@ namespace WixToolset.Core.WindowsInstaller
5014 { 5015 {
5015 foreach (var row in table.Rows) 5016 foreach (var row in table.Rows)
5016 { 5017 {
5017 if (Common.DowngradePreventedCondition == row.FieldAsString(0) || Common.UpgradePreventedCondition == row.FieldAsString(0)) 5018 if (WixUpgradeConstants.DowngradePreventedCondition == row.FieldAsString(0) || WixUpgradeConstants.UpgradePreventedCondition == row.FieldAsString(0))
5018 { 5019 {
5019 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable 5020 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
5020 } 5021 }
@@ -5101,13 +5102,13 @@ namespace WixToolset.Core.WindowsInstaller
5101 switch (row.FieldAsString(1)) 5102 switch (row.FieldAsString(1))
5102 { 5103 {
5103 case "CreateFolder": 5104 case "CreateFolder":
5104 specialPermissions = Common.FolderPermissions; 5105 specialPermissions = LockPermissionConstants.FolderPermissions;
5105 break; 5106 break;
5106 case "File": 5107 case "File":
5107 specialPermissions = Common.FilePermissions; 5108 specialPermissions = LockPermissionConstants.FilePermissions;
5108 break; 5109 break;
5109 case "Registry": 5110 case "Registry":
5110 specialPermissions = Common.RegistryPermissions; 5111 specialPermissions = LockPermissionConstants.RegistryPermissions;
5111 break; 5112 break;
5112 default: 5113 default:
5113 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); 5114 this.Messaging.Write(WarningMessages.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
@@ -5129,13 +5130,13 @@ namespace WixToolset.Core.WindowsInstaller
5129 { 5130 {
5130 name = "SpecificRightsAll"; 5131 name = "SpecificRightsAll";
5131 } 5132 }
5132 else if (28 > i && Common.StandardPermissions.Length > (i - 16)) 5133 else if (28 > i && LockPermissionConstants.StandardPermissions.Length > (i - 16))
5133 { 5134 {
5134 name = Common.StandardPermissions[i - 16]; 5135 name = LockPermissionConstants.StandardPermissions[i - 16];
5135 } 5136 }
5136 else if (0 <= (i - 28) && Common.GenericPermissions.Length > (i - 28)) 5137 else if (0 <= (i - 28) && LockPermissionConstants.GenericPermissions.Length > (i - 28))
5137 { 5138 {
5138 name = Common.GenericPermissions[i - 28]; 5139 name = LockPermissionConstants.GenericPermissions[i - 28];
5139 } 5140 }
5140 5141
5141 if (null == name) 5142 if (null == name)
@@ -5412,7 +5413,7 @@ namespace WixToolset.Core.WindowsInstaller
5412 5413
5413 if (!row.IsColumnNull(3)) 5414 if (!row.IsColumnNull(3))
5414 { 5415 {
5415 var names = Common.GetNames(row.FieldAsString(3)); 5416 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(3));
5416 if (null != names[0] && null != names[1]) 5417 if (null != names[0] && null != names[1])
5417 { 5418 {
5418 xCopyFile.SetAttributeValue("DestinationShortName", names[0]); 5419 xCopyFile.SetAttributeValue("DestinationShortName", names[0]);
@@ -5922,17 +5923,17 @@ namespace WixToolset.Core.WindowsInstaller
5922 case "OptimizeCA": 5923 case "OptimizeCA":
5923 var xOptimizeCustomActions = new XElement(Names.OptimizeCustomActionsElement); 5924 var xOptimizeCustomActions = new XElement(Names.OptimizeCustomActionsElement);
5924 var optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture); 5925 var optimizeCA = Int32.Parse(value, CultureInfo.InvariantCulture);
5925 if (0 != (Convert.ToInt32(OptimizeCA.SkipAssignment) & optimizeCA)) 5926 if (0 != (Convert.ToInt32(OptimizeCAFlags.SkipAssignment) & optimizeCA))
5926 { 5927 {
5927 xOptimizeCustomActions.SetAttributeValue("SkipAssignment", "yes"); 5928 xOptimizeCustomActions.SetAttributeValue("SkipAssignment", "yes");
5928 } 5929 }
5929 5930
5930 if (0 != (Convert.ToInt32(OptimizeCA.SkipImmediate) & optimizeCA)) 5931 if (0 != (Convert.ToInt32(OptimizeCAFlags.SkipImmediate) & optimizeCA))
5931 { 5932 {
5932 xOptimizeCustomActions.SetAttributeValue("SkipImmediate", "yes"); 5933 xOptimizeCustomActions.SetAttributeValue("SkipImmediate", "yes");
5933 } 5934 }
5934 5935
5935 if (0 != (Convert.ToInt32(OptimizeCA.SkipDeferred) & optimizeCA)) 5936 if (0 != (Convert.ToInt32(OptimizeCAFlags.SkipDeferred) & optimizeCA))
5936 { 5937 {
5937 xOptimizeCustomActions.SetAttributeValue("SkipDeferred", "yes"); 5938 xOptimizeCustomActions.SetAttributeValue("SkipDeferred", "yes");
5938 } 5939 }
@@ -6165,7 +6166,7 @@ namespace WixToolset.Core.WindowsInstaller
6165 { 6166 {
6166 foreach (var propertyId in value.Split(';')) 6167 foreach (var propertyId in value.Split(';'))
6167 { 6168 {
6168 if (Common.DowngradeDetectedProperty == propertyId || Common.UpgradeDetectedProperty == propertyId) 6169 if (WixUpgradeConstants.DowngradeDetectedProperty == propertyId || WixUpgradeConstants.UpgradeDetectedProperty == propertyId)
6169 { 6170 {
6170 continue; 6171 continue;
6171 } 6172 }
@@ -6547,7 +6548,7 @@ namespace WixToolset.Core.WindowsInstaller
6547 var xRemoveFile = new XElement(Names.RemoveFileElement, 6548 var xRemoveFile = new XElement(Names.RemoveFileElement,
6548 new XAttribute("Id", row.FieldAsString(0))); 6549 new XAttribute("Id", row.FieldAsString(0)));
6549 6550
6550 var names = Common.GetNames(row.FieldAsString(2)); 6551 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(2));
6551 if (null != names[0] && null != names[1]) 6552 if (null != names[0] && null != names[1])
6552 { 6553 {
6553 xRemoveFile.SetAttributeValue("ShortName", names[0]); 6554 xRemoveFile.SetAttributeValue("ShortName", names[0]);
@@ -6597,7 +6598,7 @@ namespace WixToolset.Core.WindowsInstaller
6597 new XAttribute("Key", row.FieldAsString(4)), 6598 new XAttribute("Key", row.FieldAsString(4)),
6598 XAttributeIfNotNull("Value", row, 5)); 6599 XAttributeIfNotNull("Value", row, 5));
6599 6600
6600 var names = Common.GetNames(row.FieldAsString(1)); 6601 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
6601 if (null != names[0] && null != names[1]) 6602 if (null != names[0] && null != names[1])
6602 { 6603 {
6603 xIniFile.SetAttributeValue("ShortName", names[0]); 6604 xIniFile.SetAttributeValue("ShortName", names[0]);
@@ -6941,7 +6942,7 @@ namespace WixToolset.Core.WindowsInstaller
6941 XAttributeIfNotNull("IconIndex", row, 9), 6942 XAttributeIfNotNull("IconIndex", row, 9),
6942 XAttributeIfNotNull("WorkingDirectory", row, 11)); 6943 XAttributeIfNotNull("WorkingDirectory", row, 11));
6943 6944
6944 var names = Common.GetNames(row.FieldAsString(2)); 6945 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(2));
6945 if (null != names[0] && null != names[1]) 6946 if (null != names[0] && null != names[1])
6946 { 6947 {
6947 xShortcut.SetAttributeValue("ShortName", names[0]); 6948 xShortcut.SetAttributeValue("ShortName", names[0]);
@@ -7016,11 +7017,11 @@ namespace WixToolset.Core.WindowsInstaller
7016 XAttributeIfNotNull("MaxSize", row, 5), 7017 XAttributeIfNotNull("MaxSize", row, 5),
7017 XAttributeIfNotNull("Languages", row, 8)); 7018 XAttributeIfNotNull("Languages", row, 8));
7018 7019
7019 var names = Common.GetNames(row.FieldAsString(1)); 7020 var names = this.BackendHelper.SplitMsiFileName(row.FieldAsString(1));
7020 if (null != names[0]) 7021 if (null != names[0])
7021 { 7022 {
7022 // it is permissable to just have a long name 7023 // it is permissable to just have a long name
7023 if (!Common.IsValidShortFilename(names[0], false) && null == names[1]) 7024 if (!this.BackendHelper.IsValidShortFilename(names[0], false) && null == names[1])
7024 { 7025 {
7025 fileSearch.SetAttributeValue("Name", names[0]); 7026 fileSearch.SetAttributeValue("Name", names[0]);
7026 } 7027 }
@@ -7248,7 +7249,7 @@ namespace WixToolset.Core.WindowsInstaller
7248 7249
7249 foreach (UpgradeRow upgradeRow in table.Rows) 7250 foreach (UpgradeRow upgradeRow in table.Rows)
7250 { 7251 {
7251 if (Common.UpgradeDetectedProperty == upgradeRow.ActionProperty || Common.DowngradeDetectedProperty == upgradeRow.ActionProperty) 7252 if (WixUpgradeConstants.UpgradeDetectedProperty == upgradeRow.ActionProperty || WixUpgradeConstants.DowngradeDetectedProperty == upgradeRow.ActionProperty)
7252 { 7253 {
7253 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable 7254 continue; // MajorUpgrade rows processed in FinalizeUpgradeTable
7254 } 7255 }
diff --git a/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs b/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
index 09194d4e..18060ca7 100644
--- a/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
+++ b/src/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
@@ -3,9 +3,12 @@
3namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices 3namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic;
6 using System.Linq; 7 using System.Linq;
7 using WixToolset.Data; 8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
8 using WixToolset.Data.WindowsInstaller; 10 using WixToolset.Data.WindowsInstaller;
11 using WixToolset.Data.WindowsInstaller.Rows;
9 using WixToolset.Extensibility.Data; 12 using WixToolset.Extensibility.Data;
10 using WixToolset.Extensibility.Services; 13 using WixToolset.Extensibility.Services;
11 14
@@ -20,14 +23,44 @@ namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices
20 23
21 #region IBackendHelper interfaces 24 #region IBackendHelper interfaces
22 25
26 public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) => this.backendHelper.CreateFileFacade(file, assembly);
27
28 public IFileFacade CreateFileFacade(FileRow fileRow) => this.backendHelper.CreateFileFacade(fileRow);
29
30 public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) => this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol);
31
23 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); 32 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
24 33
34 public string CreateGuid() => this.backendHelper.CreateGuid();
35
25 public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value); 36 public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value);
26 37
27 public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name); 38 public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name);
28 39
40 public IEnumerable<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) => this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
41
42 public string GenerateIdentifier(string prefix, params string[] args) => this.backendHelper.GenerateIdentifier(prefix, args);
43
29 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); 44 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
30 45
46 public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
47
48 public string GetMsiFileName(string value, bool source, bool longName) => this.backendHelper.GetMsiFileName(value, source, longName);
49
50 public bool IsValidBinderVariable(string variable) => this.backendHelper.IsValidBinderVariable(variable);
51
52 public bool IsValidFourPartVersion(string version) => this.backendHelper.IsValidFourPartVersion(version);
53
54 public bool IsValidIdentifier(string id) => this.backendHelper.IsValidIdentifier(id);
55
56 public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) => this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
57
58 public bool IsValidShortFilename(string filename, bool allowWildcards) => this.backendHelper.IsValidShortFilename(filename, allowWildcards);
59
60 public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) => this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
61
62 public string[] SplitMsiFileName(string value) => this.backendHelper.SplitMsiFileName(value);
63
31 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers); 64 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers);
32 65
33 #endregion 66 #endregion
diff --git a/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
index 256d3476..19869cfa 100644
--- a/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
@@ -21,6 +21,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
21 { 21 {
22 this.Context = context; 22 this.Context = context;
23 this.Messaging = context.ServiceProvider.GetService<IMessaging>(); 23 this.Messaging = context.ServiceProvider.GetService<IMessaging>();
24 this.WindowsInstallerBackendHelper = context.ServiceProvider.GetService<IWindowsInstallerBackendHelper>();
24 this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); 25 this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All);
25 } 26 }
26 27
@@ -28,6 +29,8 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
28 29
29 private IMessaging Messaging { get; } 30 private IMessaging Messaging { get; }
30 31
32 private IWindowsInstallerBackendHelper WindowsInstallerBackendHelper { get; }
33
31 private TableDefinitionCollection TableDefinitions { get; } 34 private TableDefinitionCollection TableDefinitions { get; }
32 35
33 public bool Execute() 36 public bool Execute()
@@ -197,7 +200,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
197 if (!certificates.ContainsKey(cert2.Thumbprint)) 200 if (!certificates.ContainsKey(cert2.Thumbprint))
198 { 201 {
199 // generate a stable identifier 202 // generate a stable identifier
200 var certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint); 203 var certificateGeneratedId = this.WindowsInstallerBackendHelper.GenerateIdentifier("cer", cert2.Thumbprint);
201 204
202 // Add it to our "add to MsiDigitalCertificate" table dictionary 205 // Add it to our "add to MsiDigitalCertificate" table dictionary
203 var digitalCertificateRow = digitalCertificateTable.CreateRow(null); 206 var digitalCertificateRow = digitalCertificateTable.CreateRow(null);
diff --git a/src/WixToolset.Core.WindowsInstaller/Melter.cs b/src/WixToolset.Core.WindowsInstaller/Melter.cs
index 4e4d9e4e..29e19e49 100644
--- a/src/WixToolset.Core.WindowsInstaller/Melter.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Melter.cs
@@ -18,7 +18,7 @@ namespace WixToolset
18 /// </summary> 18 /// </summary>
19 public sealed class Melter 19 public sealed class Melter
20 { 20 {
21#if TODO 21#if TODO_MELT
22 private MelterCore core; 22 private MelterCore core;
23 private Decompiler decompiler; 23 private Decompiler decompiler;
24 24
diff --git a/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
index cbd58381..a6cf4f60 100644
--- a/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
+++ b/src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
@@ -3,6 +3,7 @@
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller
4{ 4{
5 using WixToolset.Core.WindowsInstaller.Bind; 5 using WixToolset.Core.WindowsInstaller.Bind;
6 using WixToolset.Core.WindowsInstaller.Decompile;
6 using WixToolset.Core.WindowsInstaller.Inscribe; 7 using WixToolset.Core.WindowsInstaller.Inscribe;
7 using WixToolset.Core.WindowsInstaller.Unbind; 8 using WixToolset.Core.WindowsInstaller.Unbind;
8 using WixToolset.Data; 9 using WixToolset.Data;
diff --git a/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
index 4860bf81..96197d44 100644
--- a/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
+++ b/src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
@@ -3,6 +3,7 @@
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller
4{ 4{
5 using WixToolset.Core.WindowsInstaller.Bind; 5 using WixToolset.Core.WindowsInstaller.Bind;
6 using WixToolset.Core.WindowsInstaller.Decompile;
6 using WixToolset.Core.WindowsInstaller.Unbind; 7 using WixToolset.Core.WindowsInstaller.Unbind;
7 using WixToolset.Data; 8 using WixToolset.Data;
8 using WixToolset.Extensibility; 9 using WixToolset.Extensibility;
diff --git a/src/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs
index 46ff7aa3..1caa9e29 100644
--- a/src/WixToolset.Core.WindowsInstaller/MspBackend.cs
+++ b/src/WixToolset.Core.WindowsInstaller/MspBackend.cs
@@ -22,6 +22,8 @@ namespace WixToolset.Core.WindowsInstaller
22 { 22 {
23 var messaging = context.ServiceProvider.GetService<IMessaging>(); 23 var messaging = context.ServiceProvider.GetService<IMessaging>();
24 24
25 var backendHelper = context.ServiceProvider.GetService<IBackendHelper>();
26
25 var extensionManager = context.ServiceProvider.GetService<IExtensionManager>(); 27 var extensionManager = context.ServiceProvider.GetService<IExtensionManager>();
26 28
27 var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendBinderExtension>(); 29 var backendExtensions = extensionManager.GetServices<IWindowsInstallerBackendBinderExtension>();
@@ -34,14 +36,14 @@ namespace WixToolset.Core.WindowsInstaller
34 // Create transforms named in patch transforms. 36 // Create transforms named in patch transforms.
35 IEnumerable<PatchTransform> patchTransforms; 37 IEnumerable<PatchTransform> patchTransforms;
36 { 38 {
37 var command = new CreatePatchTransformsCommand(messaging, context.IntermediateRepresentation, context.IntermediateFolder); 39 var command = new CreatePatchTransformsCommand(messaging, backendHelper, context.IntermediateRepresentation, context.IntermediateFolder);
38 patchTransforms = command.Execute(); 40 patchTransforms = command.Execute();
39 } 41 }
40 42
41 // Enhance the intermediate by attaching the created patch transforms. 43 // Enhance the intermediate by attaching the created patch transforms.
42 IEnumerable<SubStorage> subStorages; 44 IEnumerable<SubStorage> subStorages;
43 { 45 {
44 var command = new AttachPatchTransformsCommand(messaging, context.IntermediateRepresentation, patchTransforms); 46 var command = new AttachPatchTransformsCommand(messaging, backendHelper, context.IntermediateRepresentation, patchTransforms);
45 subStorages = command.Execute(); 47 subStorages = command.Execute();
46 } 48 }
47 49
diff --git a/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs
index fcd749d2..3874d8e7 100644
--- a/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs
+++ b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs
@@ -7,7 +7,7 @@ namespace WixToolset.PatchAPI
7 using System.Diagnostics.CodeAnalysis; 7 using System.Diagnostics.CodeAnalysis;
8 using System.Globalization; 8 using System.Globalization;
9 using System.Runtime.InteropServices; 9 using System.Runtime.InteropServices;
10 using WixToolset.Core; 10 using WixToolset.Data.Symbols;
11 11
12 /// <summary> 12 /// <summary>
13 /// Interop class for the mspatchc.dll. 13 /// Interop class for the mspatchc.dll.
@@ -25,7 +25,7 @@ namespace WixToolset.PatchAPI
25 static internal UInt32 ParseHexOrDecimal(string source) 25 static internal UInt32 ParseHexOrDecimal(string source)
26 { 26 {
27 string value = source.Trim(); 27 string value = source.Trim();
28 if (String.Equals(value.Substring(0,2), "0x", StringComparison.OrdinalIgnoreCase)) 28 if (String.Equals(value.Substring(0, 2), "0x", StringComparison.OrdinalIgnoreCase))
29 { 29 {
30 return UInt32.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat); 30 return UInt32.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat);
31 } 31 }
@@ -63,13 +63,13 @@ namespace WixToolset.PatchAPI
63 string[] basisIgnoreOffsets, 63 string[] basisIgnoreOffsets,
64 string[] basisRetainLengths, 64 string[] basisRetainLengths,
65 string[] basisRetainOffsets, 65 string[] basisRetainOffsets,
66 PatchSymbolFlagsType apiPatchingSymbolFlags, 66 PatchSymbolFlags apiPatchingSymbolFlags,
67 bool optimizePatchSizeForLargeFiles, 67 bool optimizePatchSizeForLargeFiles,
68 out bool retainRangesIgnored 68 out bool retainRangesIgnored
69 ) 69 )
70 { 70 {
71 retainRangesIgnored = false; 71 retainRangesIgnored = false;
72 if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP | PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES | PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO))) 72 if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlags.PatchSymbolNoImagehlp | PatchSymbolFlags.PatchSymbolNoFailures | PatchSymbolFlags.PatchSymbolUndecoratedToo)))
73 { 73 {
74 throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags"); 74 throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags");
75 } 75 }
@@ -88,13 +88,13 @@ namespace WixToolset.PatchAPI
88 { 88 {
89 return false; 89 return false;
90 } 90 }
91 uint countOldFiles = (uint) basisFiles.Length; 91 uint countOldFiles = (uint)basisFiles.Length;
92 92
93 if (null != basisSymbolPaths) 93 if (null != basisSymbolPaths)
94 { 94 {
95 if (0 != basisSymbolPaths.Length) 95 if (0 != basisSymbolPaths.Length)
96 { 96 {
97 if ((uint) basisSymbolPaths.Length != countOldFiles) 97 if ((uint)basisSymbolPaths.Length != countOldFiles)
98 { 98 {
99 throw new ArgumentOutOfRangeException("basisSymbolPaths"); 99 throw new ArgumentOutOfRangeException("basisSymbolPaths");
100 } 100 }
@@ -106,7 +106,7 @@ namespace WixToolset.PatchAPI
106 { 106 {
107 if (0 != basisIgnoreLengths.Length) 107 if (0 != basisIgnoreLengths.Length)
108 { 108 {
109 if ((uint) basisIgnoreLengths.Length != countOldFiles) 109 if ((uint)basisIgnoreLengths.Length != countOldFiles)
110 { 110 {
111 throw new ArgumentOutOfRangeException("basisIgnoreLengths"); 111 throw new ArgumentOutOfRangeException("basisIgnoreLengths");
112 } 112 }
@@ -121,7 +121,7 @@ namespace WixToolset.PatchAPI
121 { 121 {
122 if (0 != basisIgnoreOffsets.Length) 122 if (0 != basisIgnoreOffsets.Length)
123 { 123 {
124 if ((uint) basisIgnoreOffsets.Length != countOldFiles) 124 if ((uint)basisIgnoreOffsets.Length != countOldFiles)
125 { 125 {
126 throw new ArgumentOutOfRangeException("basisIgnoreOffsets"); 126 throw new ArgumentOutOfRangeException("basisIgnoreOffsets");
127 } 127 }
@@ -136,7 +136,7 @@ namespace WixToolset.PatchAPI
136 { 136 {
137 if (0 != basisRetainLengths.Length) 137 if (0 != basisRetainLengths.Length)
138 { 138 {
139 if ((uint) basisRetainLengths.Length != countOldFiles) 139 if ((uint)basisRetainLengths.Length != countOldFiles)
140 { 140 {
141 throw new ArgumentOutOfRangeException("basisRetainLengths"); 141 throw new ArgumentOutOfRangeException("basisRetainLengths");
142 } 142 }
@@ -151,7 +151,7 @@ namespace WixToolset.PatchAPI
151 { 151 {
152 if (0 != basisRetainOffsets.Length) 152 if (0 != basisRetainOffsets.Length)
153 { 153 {
154 if ((uint) basisRetainOffsets.Length != countOldFiles) 154 if ((uint)basisRetainOffsets.Length != countOldFiles)
155 { 155 {
156 throw new ArgumentOutOfRangeException("basisRetainOffsets"); 156 throw new ArgumentOutOfRangeException("basisRetainOffsets");
157 } 157 }
@@ -253,15 +253,15 @@ namespace WixToolset.PatchAPI
253 253
254 // determine if this is an error or a need to use whole file. 254 // determine if this is an error or a need to use whole file.
255 int err = Marshal.GetLastWin32Error(); 255 int err = Marshal.GetLastWin32Error();
256 switch(err) 256 switch (err)
257 { 257 {
258 case unchecked((int) ERROR_PATCH_BIGGER_THAN_COMPRESSED): 258 case unchecked((int)ERROR_PATCH_BIGGER_THAN_COMPRESSED):
259 break; 259 break;
260 260
261 // too late to exclude this file -- should have been caught before 261 // too late to exclude this file -- should have been caught before
262 case unchecked((int) ERROR_PATCH_SAME_FILE): 262 case unchecked((int)ERROR_PATCH_SAME_FILE):
263 default: 263 default:
264 throw new System.ComponentModel.Win32Exception(err); 264 throw new System.ComponentModel.Win32Exception(err);
265 } 265 }
266 return false; 266 return false;
267 } 267 }
@@ -302,44 +302,44 @@ namespace WixToolset.PatchAPI
302 // The following contants can be combined and used as the OptionFlags 302 // The following contants can be combined and used as the OptionFlags
303 // parameter in the patch creation apis. 303 // parameter in the patch creation apis.
304 304
305 internal const uint PATCH_OPTION_USE_BEST = 0x00000000; // auto choose best (slower) 305 internal const uint PATCH_OPTION_USE_BEST = 0x00000000; // auto choose best (slower)
306 306
307 internal const uint PATCH_OPTION_USE_LZX_BEST = 0x00000003; // auto choose best of LXZ A/B (but not large) 307 internal const uint PATCH_OPTION_USE_LZX_BEST = 0x00000003; // auto choose best of LXZ A/B (but not large)
308 internal const uint PATCH_OPTION_USE_LZX_A = 0x00000001; // normal 308 internal const uint PATCH_OPTION_USE_LZX_A = 0x00000001; // normal
309 internal const uint PATCH_OPTION_USE_LXZ_B = 0x00000002; // better on some x86 binaries 309 internal const uint PATCH_OPTION_USE_LXZ_B = 0x00000002; // better on some x86 binaries
310 internal const uint PATCH_OPTION_USE_LZX_LARGE = 0x00000004; // better support for large files (requires 5.1 or higher applyer) 310 internal const uint PATCH_OPTION_USE_LZX_LARGE = 0x00000004; // better support for large files (requires 5.1 or higher applyer)
311 311
312 internal const uint PATCH_OPTION_NO_BINDFIX = 0x00010000; // PE bound imports 312 internal const uint PATCH_OPTION_NO_BINDFIX = 0x00010000; // PE bound imports
313 internal const uint PATCH_OPTION_NO_LOCKFIX = 0x00020000; // PE smashed locks 313 internal const uint PATCH_OPTION_NO_LOCKFIX = 0x00020000; // PE smashed locks
314 internal const uint PATCH_OPTION_NO_REBASE = 0x00040000; // PE rebased image 314 internal const uint PATCH_OPTION_NO_REBASE = 0x00040000; // PE rebased image
315 internal const uint PATCH_OPTION_FAIL_IF_SAME_FILE = 0x00080000; // don't create if same 315 internal const uint PATCH_OPTION_FAIL_IF_SAME_FILE = 0x00080000; // don't create if same
316 internal const uint PATCH_OPTION_FAIL_IF_BIGGER = 0x00100000; // fail if patch is larger than simply compressing new file (slower) 316 internal const uint PATCH_OPTION_FAIL_IF_BIGGER = 0x00100000; // fail if patch is larger than simply compressing new file (slower)
317 internal const uint PATCH_OPTION_NO_CHECKSUM = 0x00200000; // PE checksum zero 317 internal const uint PATCH_OPTION_NO_CHECKSUM = 0x00200000; // PE checksum zero
318 internal const uint PATCH_OPTION_NO_RESTIMEFIX = 0x00400000; // PE resource timestamps 318 internal const uint PATCH_OPTION_NO_RESTIMEFIX = 0x00400000; // PE resource timestamps
319 internal const uint PATCH_OPTION_NO_TIMESTAMP = 0x00800000; // don't store new file timestamp in patch 319 internal const uint PATCH_OPTION_NO_TIMESTAMP = 0x00800000; // don't store new file timestamp in patch
320 internal const uint PATCH_OPTION_SIGNATURE_MD5 = 0x01000000; // use MD5 instead of CRC (reserved for future support) 320 internal const uint PATCH_OPTION_SIGNATURE_MD5 = 0x01000000; // use MD5 instead of CRC (reserved for future support)
321 internal const uint PATCH_OPTION_INTERLEAVE_FILES = 0x40000000; // better support for large files (requires 5.2 or higher applyer) 321 internal const uint PATCH_OPTION_INTERLEAVE_FILES = 0x40000000; // better support for large files (requires 5.2 or higher applyer)
322 internal const uint PATCH_OPTION_RESERVED1 = 0x80000000; // (used internally) 322 internal const uint PATCH_OPTION_RESERVED1 = 0x80000000; // (used internally)
323 323
324 internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007; 324 internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007;
325 325
326 // 326 //
327 // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags: 327 // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags:
328 // 328 //
329 329
330 internal const uint PATCH_TRANSFORM_PE_RESOURCE_2 = 0x00000100; // better handling of PE resources (requires 5.2 or higher applyer) 330 internal const uint PATCH_TRANSFORM_PE_RESOURCE_2 = 0x00000100; // better handling of PE resources (requires 5.2 or higher applyer)
331 internal const uint PATCH_TRANSFORM_PE_IRELOC_2 = 0x00000200; // better handling of PE stripped relocs (requires 5.2 or higher applyer) 331 internal const uint PATCH_TRANSFORM_PE_IRELOC_2 = 0x00000200; // better handling of PE stripped relocs (requires 5.2 or higher applyer)
332 332
333 // 333 //
334 // In addition to the standard Win32 error codes, the following error codes may 334 // In addition to the standard Win32 error codes, the following error codes may
335 // be returned via GetLastError() when one of the patch APIs fails. 335 // be returned via GetLastError() when one of the patch APIs fails.
336 336
337 internal const uint ERROR_PATCH_ENCODE_FAILURE = 0xC00E3101; // create 337 internal const uint ERROR_PATCH_ENCODE_FAILURE = 0xC00E3101; // create
338 internal const uint ERROR_PATCH_INVALID_OPTIONS = 0xC00E3102; // create 338 internal const uint ERROR_PATCH_INVALID_OPTIONS = 0xC00E3102; // create
339 internal const uint ERROR_PATCH_SAME_FILE = 0xC00E3103; // create 339 internal const uint ERROR_PATCH_SAME_FILE = 0xC00E3103; // create
340 internal const uint ERROR_PATCH_RETAIN_RANGES_DIFFER = 0xC00E3104; // create 340 internal const uint ERROR_PATCH_RETAIN_RANGES_DIFFER = 0xC00E3104; // create
341 internal const uint ERROR_PATCH_BIGGER_THAN_COMPRESSED = 0xC00E3105; // create 341 internal const uint ERROR_PATCH_BIGGER_THAN_COMPRESSED = 0xC00E3105; // create
342 internal const uint ERROR_PATCH_IMAGEHLP_FALURE = 0xC00E3106; // create 342 internal const uint ERROR_PATCH_IMAGEHLP_FALURE = 0xC00E3106; // create
343 343
344 /// <summary> 344 /// <summary>
345 /// Delegate type that the PatchAPI calls for progress notification. 345 /// Delegate type that the PatchAPI calls for progress notification.
@@ -441,14 +441,14 @@ namespace WixToolset.PatchAPI
441 [BestFitMapping(false, ThrowOnUnmappableChar = true)] 441 [BestFitMapping(false, ThrowOnUnmappableChar = true)]
442 internal class PatchOptionData 442 internal class PatchOptionData
443 { 443 {
444 public PatchSymbolFlagsType symbolOptionFlags; // PATCH_SYMBOL_xxx flags 444 public PatchSymbolFlags symbolOptionFlags; // PATCH_SYMBOL_xxx flags
445 [MarshalAs(UnmanagedType.LPStr)] public string newFileSymbolPath; // always ANSI, never Unicode 445 [MarshalAs(UnmanagedType.LPStr)] public string newFileSymbolPath; // always ANSI, never Unicode
446 [MarshalAs(UnmanagedType.LPStr)] public string[] oldFileSymbolPathArray; // array[ OldFileCount ] 446 [MarshalAs(UnmanagedType.LPStr)] public string[] oldFileSymbolPathArray; // array[ OldFileCount ]
447 public uint extendedOptionFlags; 447 public uint extendedOptionFlags;
448 public PatchSymloadCallback symLoadCallback = null; 448 public PatchSymloadCallback symLoadCallback = null;
449 public IntPtr symLoadContext = IntPtr.Zero; 449 public IntPtr symLoadContext = IntPtr.Zero;
450 public PatchInterleaveMap[] interleaveMapArray = null; // array[ OldFileCount ] (requires 5.2 or higher applyer) 450 public PatchInterleaveMap[] interleaveMapArray = null; // array[ OldFileCount ] (requires 5.2 or higher applyer)
451 public uint maxLzxWindowSize = 0; // limit memory requirements (requires 5.2 or higher applyer) 451 public uint maxLzxWindowSize = 0; // limit memory requirements (requires 5.2 or higher applyer)
452 } 452 }
453 453
454 // 454 //
@@ -534,7 +534,7 @@ namespace WixToolset.PatchAPI
534 534
535 private PatchAPIMarshaler(string cookie) 535 private PatchAPIMarshaler(string cookie)
536 { 536 {
537 this.marshalType = (PatchAPIMarshaler.MarshalType) Enum.Parse(typeof(PatchAPIMarshaler.MarshalType), cookie); 537 this.marshalType = (PatchAPIMarshaler.MarshalType)Enum.Parse(typeof(PatchAPIMarshaler.MarshalType), cookie);
538 } 538 }
539 539
540 // 540 //
@@ -575,12 +575,12 @@ namespace WixToolset.PatchAPI
575 575
576 switch (this.marshalType) 576 switch (this.marshalType)
577 { 577 {
578 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: 578 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
579 this.CleanUpPOD(pNativeData); 579 this.CleanUpPOD(pNativeData);
580 break; 580 break;
581 default: 581 default:
582 this.CleanUpPOFI_A(pNativeData); 582 this.CleanUpPOFI_A(pNativeData);
583 break; 583 break;
584 } 584 }
585 } 585 }
586 586
@@ -601,14 +601,14 @@ namespace WixToolset.PatchAPI
601 return IntPtr.Zero; 601 return IntPtr.Zero;
602 } 602 }
603 603
604 switch(this.marshalType) 604 switch (this.marshalType)
605 { 605 {
606 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: 606 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
607 return this.MarshalPOD(ManagedObj as PatchOptionData); 607 return this.MarshalPOD(ManagedObj as PatchOptionData);
608 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: 608 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W:
609 return this.MarshalPOFIW_A(ManagedObj as PatchOldFileInfoW[]); 609 return this.MarshalPOFIW_A(ManagedObj as PatchOldFileInfoW[]);
610 default: 610 default:
611 throw new InvalidOperationException(); 611 throw new InvalidOperationException();
612 } 612 }
613 } 613 }
614 614
@@ -631,23 +631,23 @@ namespace WixToolset.PatchAPI
631 // Implementation ************************************************* 631 // Implementation *************************************************
632 632
633 // PATCH_OPTION_DATA offsets 633 // PATCH_OPTION_DATA offsets
634 private static readonly int symbolOptionFlagsOffset = Marshal.SizeOf(typeof(Int32)); 634 private static readonly int symbolOptionFlagsOffset = Marshal.SizeOf(typeof(Int32));
635 private static readonly int newFileSymbolPathOffset = 2*Marshal.SizeOf(typeof(Int32)); 635 private static readonly int newFileSymbolPathOffset = 2 * Marshal.SizeOf(typeof(Int32));
636 private static readonly int oldFileSymbolPathArrayOffset = 2*Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); 636 private static readonly int oldFileSymbolPathArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
637 private static readonly int extendedOptionFlagsOffset = 2*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 637 private static readonly int extendedOptionFlagsOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
638 private static readonly int symLoadCallbackOffset = 3*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 638 private static readonly int symLoadCallbackOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
639 private static readonly int symLoadContextOffset = 3*Marshal.SizeOf(typeof(Int32)) + 3*Marshal.SizeOf(typeof(IntPtr)); 639 private static readonly int symLoadContextOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr));
640 private static readonly int interleaveMapArrayOffset = 3*Marshal.SizeOf(typeof(Int32)) + 4*Marshal.SizeOf(typeof(IntPtr)); 640 private static readonly int interleaveMapArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 4 * Marshal.SizeOf(typeof(IntPtr));
641 private static readonly int maxLzxWindowSizeOffset = 3*Marshal.SizeOf(typeof(Int32)) + 5*Marshal.SizeOf(typeof(IntPtr)); 641 private static readonly int maxLzxWindowSizeOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr));
642 private static readonly int patchOptionDataSize = 4*Marshal.SizeOf(typeof(Int32)) + 5*Marshal.SizeOf(typeof(IntPtr)); 642 private static readonly int patchOptionDataSize = 4 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr));
643 643
644 // PATCH_OLD_FILE_INFO offsets 644 // PATCH_OLD_FILE_INFO offsets
645 private static readonly int oldFileOffset = Marshal.SizeOf(typeof(Int32)); 645 private static readonly int oldFileOffset = Marshal.SizeOf(typeof(Int32));
646 private static readonly int ignoreRangeCountOffset = Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); 646 private static readonly int ignoreRangeCountOffset = Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
647 private static readonly int ignoreRangeArrayOffset = 2*Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); 647 private static readonly int ignoreRangeArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
648 private static readonly int retainRangeCountOffset = 2*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 648 private static readonly int retainRangeCountOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
649 private static readonly int retainRangeArrayOffset = 3*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); 649 private static readonly int retainRangeArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
650 private static readonly int patchOldFileInfoSize = 3*Marshal.SizeOf(typeof(Int32)) + 3*Marshal.SizeOf(typeof(IntPtr)); 650 private static readonly int patchOldFileInfoSize = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr));
651 651
652 // Methods and data used to preserve data needed for cleanup 652 // Methods and data used to preserve data needed for cleanup
653 653
@@ -658,16 +658,16 @@ namespace WixToolset.PatchAPI
658 private IntPtr CreateMainStruct(int oldFileCount) 658 private IntPtr CreateMainStruct(int oldFileCount)
659 { 659 {
660 int nativeSize; 660 int nativeSize;
661 switch(this.marshalType) 661 switch (this.marshalType)
662 { 662 {
663 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: 663 case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
664 nativeSize = patchOptionDataSize; 664 nativeSize = patchOptionDataSize;
665 break; 665 break;
666 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: 666 case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W:
667 nativeSize = oldFileCount*patchOldFileInfoSize; 667 nativeSize = oldFileCount * patchOldFileInfoSize;
668 break; 668 break;
669 default: 669 default:
670 throw new InvalidOperationException(); 670 throw new InvalidOperationException();
671 } 671 }
672 672
673 IntPtr native = Marshal.AllocCoTaskMem(nativeSize); 673 IntPtr native = Marshal.AllocCoTaskMem(nativeSize);
@@ -722,7 +722,7 @@ namespace WixToolset.PatchAPI
722 722
723 for (int i = 0; i < managed.Length; ++i) 723 for (int i = 0; i < managed.Length; ++i)
724 { 724 {
725 Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), OptionalAnsiString(managed[i])); 725 Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalAnsiString(managed[i]));
726 } 726 }
727 727
728 return native; 728 return native;
@@ -741,7 +741,7 @@ namespace WixToolset.PatchAPI
741 741
742 for (int i = 0; i < managed.Length; ++i) 742 for (int i = 0; i < managed.Length; ++i)
743 { 743 {
744 Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), OptionalUnicodeString(managed[i])); 744 Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalUnicodeString(managed[i]));
745 } 745 }
746 746
747 return native; 747 return native;
@@ -765,12 +765,12 @@ namespace WixToolset.PatchAPI
765 } 765 }
766 766
767 IntPtr native = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt32)) 767 IntPtr native = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt32))
768 + managed.ranges.Length*(Marshal.SizeOf(typeof(PatchInterleaveMap)))); 768 + managed.ranges.Length * (Marshal.SizeOf(typeof(PatchInterleaveMap))));
769 WriteUInt32(native, (uint) managed.ranges.Length); 769 WriteUInt32(native, (uint)managed.ranges.Length);
770 770
771 for (int i = 0; i < managed.ranges.Length; ++i) 771 for (int i = 0; i < managed.ranges.Length; ++i)
772 { 772 {
773 Marshal.StructureToPtr(managed.ranges[i], (IntPtr)((Int64)native + i*Marshal.SizeOf(typeof(PatchInterleaveMap))), false); 773 Marshal.StructureToPtr(managed.ranges[i], (IntPtr)((Int64)native + i * Marshal.SizeOf(typeof(PatchInterleaveMap))), false);
774 } 774 }
775 return native; 775 return native;
776 } 776 }
@@ -786,7 +786,7 @@ namespace WixToolset.PatchAPI
786 786
787 for (int i = 0; i < managed.Length; ++i) 787 for (int i = 0; i < managed.Length; ++i)
788 { 788 {
789 Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), CreateInterleaveMapRange(managed[i])); 789 Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), CreateInterleaveMapRange(managed[i]));
790 } 790 }
791 791
792 return native; 792 return native;
@@ -794,12 +794,12 @@ namespace WixToolset.PatchAPI
794 794
795 private static void WriteUInt32(IntPtr native, uint data) 795 private static void WriteUInt32(IntPtr native, uint data)
796 { 796 {
797 Marshal.WriteInt32(native, unchecked((int) data)); 797 Marshal.WriteInt32(native, unchecked((int)data));
798 } 798 }
799 799
800 private static void WriteUInt32(IntPtr native, int offset, uint data) 800 private static void WriteUInt32(IntPtr native, int offset, uint data)
801 { 801 {
802 Marshal.WriteInt32(native, offset, unchecked((int) data)); 802 Marshal.WriteInt32(native, offset, unchecked((int)data));
803 } 803 }
804 804
805 // Marshal operations 805 // Marshal operations
@@ -813,7 +813,7 @@ namespace WixToolset.PatchAPI
813 813
814 IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length); 814 IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length);
815 Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct 815 Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct
816 WriteUInt32(native, symbolOptionFlagsOffset, (uint) managed.symbolOptionFlags); 816 WriteUInt32(native, symbolOptionFlagsOffset, (uint)managed.symbolOptionFlags);
817 Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath)); 817 Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath));
818 Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray)); 818 Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray));
819 WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags); 819 WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags);
@@ -866,10 +866,10 @@ namespace WixToolset.PatchAPI
866 { 866 {
867 Marshal.WriteInt32(native, patchOldFileInfoSize); // SizeOfThisStruct 867 Marshal.WriteInt32(native, patchOldFileInfoSize); // SizeOfThisStruct
868 WriteUInt32(native, ignoreRangeCountOffset, 868 WriteUInt32(native, ignoreRangeCountOffset,
869 (null == managed.ignoreRange) ? 0 : (uint) managed.ignoreRange.Length); // IgnoreRangeCount // maximum 255 869 (null == managed.ignoreRange) ? 0 : (uint)managed.ignoreRange.Length); // IgnoreRangeCount // maximum 255
870 Marshal.WriteIntPtr(native, ignoreRangeArrayOffset, MarshalPIRArray(managed.ignoreRange)); // IgnoreRangeArray 870 Marshal.WriteIntPtr(native, ignoreRangeArrayOffset, MarshalPIRArray(managed.ignoreRange)); // IgnoreRangeArray
871 WriteUInt32(native, retainRangeCountOffset, 871 WriteUInt32(native, retainRangeCountOffset,
872 (null == managed.retainRange) ? 0 : (uint) managed.retainRange.Length); // RetainRangeCount // maximum 255 872 (null == managed.retainRange) ? 0 : (uint)managed.retainRange.Length); // RetainRangeCount // maximum 255
873 Marshal.WriteIntPtr(native, retainRangeArrayOffset, MarshalPRRArray(managed.retainRange)); // RetainRangeArray 873 Marshal.WriteIntPtr(native, retainRangeArrayOffset, MarshalPRRArray(managed.retainRange)); // RetainRangeArray
874 } 874 }
875 875
@@ -885,11 +885,11 @@ namespace WixToolset.PatchAPI
885 return IntPtr.Zero; 885 return IntPtr.Zero;
886 } 886 }
887 887
888 IntPtr native = Marshal.AllocCoTaskMem(array.Length*Marshal.SizeOf(typeof(PatchIgnoreRange))); 888 IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchIgnoreRange)));
889 889
890 for (int i = 0; i < array.Length; ++i) 890 for (int i = 0; i < array.Length; ++i)
891 { 891 {
892 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i*Marshal.SizeOf(typeof(PatchIgnoreRange)))), false); 892 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchIgnoreRange)))), false);
893 } 893 }
894 894
895 return native; 895 return native;
@@ -907,11 +907,11 @@ namespace WixToolset.PatchAPI
907 return IntPtr.Zero; 907 return IntPtr.Zero;
908 } 908 }
909 909
910 IntPtr native = Marshal.AllocCoTaskMem(array.Length*Marshal.SizeOf(typeof(PatchRetainRange))); 910 IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchRetainRange)));
911 911
912 for (int i = 0; i < array.Length; ++i) 912 for (int i = 0; i < array.Length; ++i)
913 { 913 {
914 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i*Marshal.SizeOf(typeof(PatchRetainRange)))), false); 914 Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchRetainRange)))), false);
915 } 915 }
916 916
917 return native; 917 return native;
@@ -930,7 +930,7 @@ namespace WixToolset.PatchAPI
930 Marshal.FreeCoTaskMem( 930 Marshal.FreeCoTaskMem(
931 Marshal.ReadIntPtr( 931 Marshal.ReadIntPtr(
932 Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset), 932 Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset),
933 i*Marshal.SizeOf(typeof(IntPtr)))); 933 i * Marshal.SizeOf(typeof(IntPtr))));
934 } 934 }
935 935
936 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset)); 936 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset));
@@ -943,7 +943,7 @@ namespace WixToolset.PatchAPI
943 Marshal.FreeCoTaskMem( 943 Marshal.FreeCoTaskMem(
944 Marshal.ReadIntPtr( 944 Marshal.ReadIntPtr(
945 Marshal.ReadIntPtr(native, interleaveMapArrayOffset), 945 Marshal.ReadIntPtr(native, interleaveMapArrayOffset),
946 i*Marshal.SizeOf(typeof(IntPtr)))); 946 i * Marshal.SizeOf(typeof(IntPtr))));
947 } 947 }
948 948
949 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, interleaveMapArrayOffset)); 949 Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, interleaveMapArrayOffset));
@@ -956,7 +956,7 @@ namespace WixToolset.PatchAPI
956 { 956 {
957 for (int i = 0; i < GetOldFileCount(native); ++i) 957 for (int i = 0; i < GetOldFileCount(native); ++i)
958 { 958 {
959 PatchAPIMarshaler.CleanUpPOFI((IntPtr)((Int64)native + i*patchOldFileInfoSize)); 959 PatchAPIMarshaler.CleanUpPOFI((IntPtr)((Int64)native + i * patchOldFileInfoSize));
960 } 960 }
961 961
962 PatchAPIMarshaler.ReleaseMainStruct(native); 962 PatchAPIMarshaler.ReleaseMainStruct(native);
diff --git a/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs b/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs
index bbb97c25..ad7764bc 100644
--- a/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs
+++ b/src/WixToolset.Core.WindowsInstaller/RowDictionary.cs
@@ -21,19 +21,6 @@ namespace WixToolset.Core.WindowsInstaller
21 } 21 }
22 22
23 /// <summary> 23 /// <summary>
24 /// Creates and populates a <see cref="RowDictionary{T}"/> with the rows from the given enumerator.
25 /// </summary>
26 /// <param name="rows">Rows to add.</param>
27 public RowDictionary(IEnumerable<T> rows)
28 : this()
29 {
30 foreach (T row in rows)
31 {
32 this.Add(row);
33 }
34 }
35
36 /// <summary>
37 /// Creates and populates a <see cref="RowDictionary{T}"/> with the rows from the given <see cref="Table"/>. 24 /// Creates and populates a <see cref="RowDictionary{T}"/> with the rows from the given <see cref="Table"/>.
38 /// </summary> 25 /// </summary>
39 /// <param name="table">The table to index.</param> 26 /// <param name="table">The table to index.</param>
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
index 36172b5e..9a55dc77 100644
--- a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
@@ -11,16 +11,16 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
11 using WixToolset.Core.WindowsInstaller.Msi; 11 using WixToolset.Core.WindowsInstaller.Msi;
12 using WixToolset.Data; 12 using WixToolset.Data;
13 using WixToolset.Data.WindowsInstaller; 13 using WixToolset.Data.WindowsInstaller;
14 using WixToolset.Data.WindowsInstaller.Rows;
15 using WixToolset.Extensibility.Services; 14 using WixToolset.Extensibility.Services;
16 15
17 internal class UnbindDatabaseCommand 16 internal class UnbindDatabaseCommand
18 { 17 {
19 private List<string> exportedFiles; 18 private List<string> exportedFiles;
20 19
21 public UnbindDatabaseCommand(IMessaging messaging, Database database, string databasePath, OutputType outputType, string exportBasePath, string intermediateFolder, bool isAdminImage, bool suppressDemodularization, bool skipSummaryInfo) 20 public UnbindDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, Database database, string databasePath, OutputType outputType, string exportBasePath, string intermediateFolder, bool isAdminImage, bool suppressDemodularization, bool skipSummaryInfo)
22 { 21 {
23 this.Messaging = messaging; 22 this.Messaging = messaging;
23 this.BackendHelper = backendHelper;
24 this.Database = database; 24 this.Database = database;
25 this.DatabasePath = databasePath; 25 this.DatabasePath = databasePath;
26 this.OutputType = outputType; 26 this.OutputType = outputType;
@@ -35,6 +35,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
35 35
36 public IMessaging Messaging { get; } 36 public IMessaging Messaging { get; }
37 37
38 public IBackendHelper BackendHelper { get; }
39
38 public Database Database { get; } 40 public Database Database { get; }
39 41
40 public string DatabasePath { get; } 42 public string DatabasePath { get; }
@@ -527,7 +529,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
527 /// </summary> 529 /// </summary>
528 /// <param name="value">The Filename value.</param> 530 /// <param name="value">The Filename value.</param>
529 /// <returns>The source name of the directory in an admin image.</returns> 531 /// <returns>The source name of the directory in an admin image.</returns>
530 private static string GetAdminSourceName(string value) 532 private string GetAdminSourceName(string value)
531 { 533 {
532 string name = null; 534 string name = null;
533 string[] names; 535 string[] names;
@@ -535,7 +537,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
535 string shortsourcename = null; 537 string shortsourcename = null;
536 string sourcename = null; 538 string sourcename = null;
537 539
538 names = Common.GetNames(value); 540 names = this.BackendHelper.SplitMsiFileName(value);
539 541
540 if (null != names[0] && "." != names[0]) 542 if (null != names[0] && "." != names[0])
541 { 543 {
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
index de2c5e37..bde29405 100644
--- a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
@@ -17,9 +17,10 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
17 17
18 internal class UnbindTransformCommand 18 internal class UnbindTransformCommand
19 { 19 {
20 public UnbindTransformCommand(IMessaging messaging, string transformFile, string exportBasePath, string intermediateFolder) 20 public UnbindTransformCommand(IMessaging messaging, IBackendHelper backendHelper, string transformFile, string exportBasePath, string intermediateFolder)
21 { 21 {
22 this.Messaging = messaging; 22 this.Messaging = messaging;
23 this.BackendHelper = backendHelper;
23 this.TransformFile = transformFile; 24 this.TransformFile = transformFile;
24 this.ExportBasePath = exportBasePath; 25 this.ExportBasePath = exportBasePath;
25 this.IntermediateFolder = intermediateFolder; 26 this.IntermediateFolder = intermediateFolder;
@@ -29,6 +30,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
29 30
30 private IMessaging Messaging { get; } 31 private IMessaging Messaging { get; }
31 32
33 private IBackendHelper BackendHelper { get; }
34
32 private string TransformFile { get; } 35 private string TransformFile { get; }
33 36
34 private string ExportBasePath { get; } 37 private string ExportBasePath { get; }
@@ -87,7 +90,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
87 msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform); 90 msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform);
88 91
89 // unbind the database 92 // unbind the database
90 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); 93 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true);
91 var transformViewOutput = unbindCommand.Execute(); 94 var transformViewOutput = unbindCommand.Execute();
92 95
93 // index the added and possibly modified rows (added rows may also appears as modified rows) 96 // index the added and possibly modified rows (added rows may also appears as modified rows)
@@ -157,7 +160,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
157 } 160 }
158 161
159 // unbind the database 162 // unbind the database
160 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); 163 var unbindCommand = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true);
161 var output = unbindCommand.Execute(); 164 var output = unbindCommand.Execute();
162 165
163 // index all the rows to easily find modified rows 166 // index all the rows to easily find modified rows
diff --git a/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs b/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs
index f60a0e1a..acfb8f1e 100644
--- a/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs
+++ b/src/WixToolset.Core.WindowsInstaller/UnbindContext.cs
@@ -2,7 +2,6 @@
2 2
3namespace WixToolset.Core 3namespace WixToolset.Core
4{ 4{
5 using System;
6 using WixToolset.Extensibility.Data; 5 using WixToolset.Extensibility.Data;
7 using WixToolset.Extensibility.Services; 6 using WixToolset.Extensibility.Services;
8 7
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbinder.cs b/src/WixToolset.Core.WindowsInstaller/Unbinder.cs
index 99caaba9..f712ec3f 100644
--- a/src/WixToolset.Core.WindowsInstaller/Unbinder.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Unbinder.cs
@@ -21,6 +21,8 @@ namespace WixToolset.Core
21 this.BackendFactories = extensionManager.GetServices<IBackendFactory>(); 21 this.BackendFactories = extensionManager.GetServices<IBackendFactory>();
22 } 22 }
23 23
24 public IWixToolsetServiceProvider ServiceProvider { get; }
25
24 public IEnumerable<IBackendFactory> BackendFactories { get; } 26 public IEnumerable<IBackendFactory> BackendFactories { get; }
25 27
26 /// <summary> 28 /// <summary>
@@ -29,8 +31,6 @@ namespace WixToolset.Core
29 /// <value>Set to true if the input msi is part of an admin image.</value> 31 /// <value>Set to true if the input msi is part of an admin image.</value>
30 public bool IsAdminImage { get; set; } 32 public bool IsAdminImage { get; set; }
31 33
32 public IWixToolsetServiceProvider ServiceProvider { get; }
33
34 /// <summary> 34 /// <summary>
35 /// Gets or sets the option to suppress demodularizing values. 35 /// Gets or sets the option to suppress demodularizing values.
36 /// </summary> 36 /// </summary>
diff --git a/src/WixToolset.Core.WindowsInstaller/Validator.cs b/src/WixToolset.Core.WindowsInstaller/Validator.cs
index e8117de7..a6a41bd7 100644
--- a/src/WixToolset.Core.WindowsInstaller/Validator.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Validator.cs
@@ -25,10 +25,10 @@ namespace WixToolset.Core.WindowsInstaller
25 internal sealed class Validator 25 internal sealed class Validator
26 { 26 {
27 private string actionName; 27 private string actionName;
28 private StringCollection cubeFiles; 28 private readonly StringCollection cubeFiles;
29 private ValidatorExtension extension; 29 private ValidatorExtension extension;
30 private WindowsInstallerData output; 30 private WindowsInstallerData output;
31 private InstallUIHandler validationUIHandler; 31 private readonly InstallUIHandler validationUIHandler;
32 private bool validationSessionComplete; 32 private bool validationSessionComplete;
33 private readonly IMessaging messaging; 33 private readonly IMessaging messaging;
34 34
@@ -57,7 +57,6 @@ namespace WixToolset.Core.WindowsInstaller
57 /// Gets or sets the list of ICEs to run. 57 /// Gets or sets the list of ICEs to run.
58 /// </summary> 58 /// </summary>
59 /// <value>The list of ICEs.</value> 59 /// <value>The list of ICEs.</value>
60 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
61 public ISet<string> ICEs { get; set; } 60 public ISet<string> ICEs { get; set; }
62 61
63 /// <summary> 62 /// <summary>
@@ -75,7 +74,6 @@ namespace WixToolset.Core.WindowsInstaller
75 /// Gets or sets the suppressed ICEs. 74 /// Gets or sets the suppressed ICEs.
76 /// </summary> 75 /// </summary>
77 /// <value>The suppressed ICEs.</value> 76 /// <value>The suppressed ICEs.</value>
78 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
79 public ISet<string> SuppressedICEs { get; set; } 77 public ISet<string> SuppressedICEs { get; set; }
80 78
81 /// <summary> 79 /// <summary>
@@ -103,13 +101,8 @@ namespace WixToolset.Core.WindowsInstaller
103 IntPtr previousHwnd = IntPtr.Zero; 101 IntPtr previousHwnd = IntPtr.Zero;
104 InstallUIHandler previousUIHandler = null; 102 InstallUIHandler previousUIHandler = null;
105 103
106 if (null == databaseFile)
107 {
108 throw new ArgumentNullException("databaseFile");
109 }
110
111 // initialize the validator extension 104 // initialize the validator extension
112 this.extension.DatabaseFile = databaseFile; 105 this.extension.DatabaseFile = databaseFile ?? throw new ArgumentNullException(nameof(databaseFile));
113 this.extension.Output = this.output; 106 this.extension.Output = this.output;
114 this.extension.InitializeValidator(); 107 this.extension.InitializeValidator();
115 108
diff --git a/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs b/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs
index 968ab387..20606a77 100644
--- a/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs
+++ b/src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs
@@ -181,7 +181,7 @@ namespace WixToolset.Extensibility
181 throw new ArgumentNullException("message"); 181 throw new ArgumentNullException("message");
182 } 182 }
183 183
184 string[] messageParts = message.Split('\t'); 184 var messageParts = message.Split('\t');
185 if (3 > messageParts.Length) 185 if (3 > messageParts.Length)
186 { 186 {
187 if (null == action) 187 if (null == action)
@@ -194,10 +194,10 @@ namespace WixToolset.Extensibility
194 } 194 }
195 } 195 }
196 196
197 SourceLineNumber messageSourceLineNumbers = null; 197 SourceLineNumber messageSourceLineNumbers;
198 if (6 < messageParts.Length) 198 if (6 < messageParts.Length)
199 { 199 {
200 string[] primaryKeys = new string[messageParts.Length - 6]; 200 var primaryKeys = new string[messageParts.Length - 6];
201 201
202 Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length); 202 Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length);
203 203
@@ -242,7 +242,7 @@ namespace WixToolset.Extensibility
242 this.indexedSourceLineNumbers = new Hashtable(); 242 this.indexedSourceLineNumbers = new Hashtable();
243 243
244 // index each real table 244 // index each real table
245 foreach (Table table in this.output.Tables) 245 foreach (var table in this.output.Tables)
246 { 246 {
247 // skip unreal tables 247 // skip unreal tables
248 if (table.Definition.Unreal) 248 if (table.Definition.Unreal)
@@ -251,7 +251,7 @@ namespace WixToolset.Extensibility
251 } 251 }
252 252
253 // index each row 253 // index each row
254 foreach (Row row in table.Rows) 254 foreach (var row in table.Rows)
255 { 255 {
256 // skip rows that don't contain source line information 256 // skip rows that don't contain source line information
257 if (null == row.SourceLineNumbers) 257 if (null == row.SourceLineNumbers)
@@ -260,10 +260,10 @@ namespace WixToolset.Extensibility
260 } 260 }
261 261
262 // index the row using its table name and primary key 262 // index the row using its table name and primary key
263 string primaryKey = row.GetPrimaryKey(';'); 263 var primaryKey = row.GetPrimaryKey(';');
264 if (null != primaryKey) 264 if (null != primaryKey)
265 { 265 {
266 string key = String.Concat(table.Name, ":", primaryKey); 266 var key = String.Concat(table.Name, ":", primaryKey);
267 267
268 if (this.indexedSourceLineNumbers.ContainsKey(key)) 268 if (this.indexedSourceLineNumbers.ContainsKey(key))
269 { 269 {