aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller/Bind
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/Bind
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/Bind')
-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
25 files changed, 204 insertions, 799 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