diff options
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind')
22 files changed, 1825 insertions, 947 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs index 74e2cdb5..f426b96d 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs | |||
@@ -1,43 +1,44 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Globalization; | 7 | using System.Globalization; |
8 | using System.Linq; | ||
8 | using WixToolset.Core.Bind; | 9 | using WixToolset.Core.Bind; |
9 | using WixToolset.Data; | 10 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | 11 | using WixToolset.Data.Rows; |
12 | using WixToolset.Data.Tuples; | ||
11 | 13 | ||
12 | /// <summary> | 14 | /// <summary> |
13 | /// AssignMediaCommand assigns files to cabs based on Media or MediaTemplate rows. | 15 | /// AssignMediaCommand assigns files to cabs based on Media or MediaTemplate rows. |
14 | /// </summary> | 16 | /// </summary> |
15 | public class AssignMediaCommand | 17 | internal class AssignMediaCommand |
16 | { | 18 | { |
17 | public AssignMediaCommand() | 19 | public AssignMediaCommand(IntermediateSection section) |
18 | { | 20 | { |
19 | this.CabinetNameTemplate = "Cab{0}.cab"; | 21 | this.CabinetNameTemplate = "Cab{0}.cab"; |
22 | this.Section = section; | ||
20 | } | 23 | } |
21 | 24 | ||
22 | public Output Output { private get; set; } | 25 | private IntermediateSection Section { get; } |
26 | |||
27 | public IEnumerable<FileFacade> FileFacades { private get; set; } | ||
23 | 28 | ||
24 | public bool FilesCompressed { private get; set; } | 29 | public bool FilesCompressed { private get; set; } |
25 | 30 | ||
26 | public string CabinetNameTemplate { private get; set; } | 31 | public string CabinetNameTemplate { private get; set; } |
27 | 32 | ||
28 | public IEnumerable<FileFacade> FileFacades { private get; set; } | ||
29 | |||
30 | public TableDefinitionCollection TableDefinitions { private get; set; } | ||
31 | |||
32 | /// <summary> | 33 | /// <summary> |
33 | /// Gets cabinets with their file rows. | 34 | /// Gets cabinets with their file rows. |
34 | /// </summary> | 35 | /// </summary> |
35 | public Dictionary<MediaRow, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; } | 36 | public Dictionary<MediaTuple, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; } |
36 | 37 | ||
37 | /// <summary> | 38 | /// <summary> |
38 | /// Get media rows. | 39 | /// Get media rows. |
39 | /// </summary> | 40 | /// </summary> |
40 | public RowDictionary<MediaRow> MediaRows { get; private set; } | 41 | public Dictionary<int, MediaTuple> MediaRows { get; private set; } |
41 | 42 | ||
42 | /// <summary> | 43 | /// <summary> |
43 | /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. | 44 | /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. |
@@ -47,42 +48,41 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
47 | 48 | ||
48 | public void Execute() | 49 | public void Execute() |
49 | { | 50 | { |
50 | Dictionary<MediaRow, List<FileFacade>> filesByCabinetMedia = new Dictionary<MediaRow, List<FileFacade>>(); | 51 | var filesByCabinetMedia = new Dictionary<MediaTuple, List<FileFacade>>(); |
51 | 52 | ||
52 | RowDictionary<MediaRow> mediaRows = new RowDictionary<MediaRow>(); | 53 | var mediaRows = new Dictionary<int, MediaTuple>(); |
53 | 54 | ||
54 | List<FileFacade> uncompressedFiles = new List<FileFacade>(); | 55 | List<FileFacade> uncompressedFiles = new List<FileFacade>(); |
55 | 56 | ||
56 | MediaRow mergeModuleMediaRow = null; | 57 | var mediaTable = this.Section.Tuples.OfType<MediaTuple>().ToList(); |
57 | Table mediaTable = this.Output.Tables["Media"]; | 58 | var mediaTemplateTable = this.Section.Tuples.OfType<WixMediaTemplateTuple>().ToList(); |
58 | Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"]; | ||
59 | 59 | ||
60 | // If both tables are authored, it is an error. | 60 | // If both tables are authored, it is an error. |
61 | if ((mediaTemplateTable != null && mediaTemplateTable.Rows.Count > 0) && (mediaTable != null && mediaTable.Rows.Count > 1)) | 61 | if ((mediaTemplateTable != null && mediaTemplateTable.Count > 0) && (mediaTable != null && mediaTable.Count > 1)) |
62 | { | 62 | { |
63 | throw new WixException(WixErrors.MediaTableCollision(null)); | 63 | throw new WixException(WixErrors.MediaTableCollision(null)); |
64 | } | 64 | } |
65 | 65 | ||
66 | // When building merge module, all the files go to "#MergeModule.CABinet". | 66 | // When building merge module, all the files go to "#MergeModule.CABinet". |
67 | if (OutputType.Module == this.Output.Type) | 67 | if (SectionType.Module == this.Section.Type) |
68 | { | 68 | { |
69 | Table mergeModuleMediaTable = new Table(this.TableDefinitions["Media"]); | 69 | var mergeModuleMediaRow = new MediaTuple(); |
70 | mergeModuleMediaRow = (MediaRow)mergeModuleMediaTable.CreateRow(null); | ||
71 | mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet"; | 70 | mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet"; |
72 | 71 | ||
73 | filesByCabinetMedia.Add(mergeModuleMediaRow, new List<FileFacade>()); | 72 | this.Section.Tuples.Add(mergeModuleMediaRow); |
74 | } | ||
75 | 73 | ||
76 | if (OutputType.Module == this.Output.Type || null == mediaTemplateTable) | 74 | filesByCabinetMedia.Add(mergeModuleMediaRow, new List<FileFacade>(this.FileFacades)); |
75 | } | ||
76 | else if (null == mediaTemplateTable) | ||
77 | { | 77 | { |
78 | this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); | 78 | this.ManuallyAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); |
79 | } | 79 | } |
80 | else | 80 | else |
81 | { | 81 | { |
82 | this.AutoAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); | 82 | this.AutoAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); |
83 | } | 83 | } |
84 | 84 | ||
85 | this.FileFacadesByCabinetMedia = new Dictionary<MediaRow, IEnumerable<FileFacade>>(); | 85 | this.FileFacadesByCabinetMedia = new Dictionary<MediaTuple, IEnumerable<FileFacade>>(); |
86 | 86 | ||
87 | foreach (var mediaRowWithFiles in filesByCabinetMedia) | 87 | foreach (var mediaRowWithFiles in filesByCabinetMedia) |
88 | { | 88 | { |
@@ -98,7 +98,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
98 | /// Assign files to cabinets based on MediaTemplate authoring. | 98 | /// Assign files to cabinets based on MediaTemplate authoring. |
99 | /// </summary> | 99 | /// </summary> |
100 | /// <param name="fileFacades">FileRowCollection</param> | 100 | /// <param name="fileFacades">FileRowCollection</param> |
101 | private void AutoAssignFiles(Table mediaTable, IEnumerable<FileFacade> fileFacades, Dictionary<MediaRow, List<FileFacade>> filesByCabinetMedia, RowDictionary<MediaRow> mediaRows, List<FileFacade> uncompressedFiles) | 101 | private void AutoAssignFiles(List<MediaTuple> mediaTable, IEnumerable<FileFacade> fileFacades, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, Dictionary<int, MediaTuple> mediaRows, List<FileFacade> uncompressedFiles) |
102 | { | 102 | { |
103 | const int MaxCabIndex = 999; | 103 | const int MaxCabIndex = 999; |
104 | 104 | ||
@@ -107,13 +107,19 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
107 | int maxPreCabSizeInMB = 0; | 107 | int maxPreCabSizeInMB = 0; |
108 | int currentCabIndex = 0; | 108 | int currentCabIndex = 0; |
109 | 109 | ||
110 | MediaRow currentMediaRow = null; | 110 | MediaTuple currentMediaRow = null; |
111 | 111 | ||
112 | Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"]; | 112 | var mediaTemplateTable = this.Section.Tuples.OfType<WixMediaTemplateTuple>(); |
113 | |||
114 | // Remove all previous media tuples since they will be replaced with | ||
115 | // media template. | ||
116 | foreach (var mediaTuple in mediaTable) | ||
117 | { | ||
118 | this.Section.Tuples.Remove(mediaTuple); | ||
119 | } | ||
113 | 120 | ||
114 | // Auto assign files to cabinets based on maximum uncompressed media size | 121 | // Auto assign files to cabinets based on maximum uncompressed media size |
115 | mediaTable.Rows.Clear(); | 122 | var mediaTemplateRow = mediaTemplateTable.Single(); |
116 | WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0]; | ||
117 | 123 | ||
118 | if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate)) | 124 | if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate)) |
119 | { | 125 | { |
@@ -149,9 +155,9 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
149 | { | 155 | { |
150 | // When building a product, if the current file is not to be compressed or if | 156 | // When building a product, if the current file is not to be compressed or if |
151 | // the package set not to be compressed, don't cab it. | 157 | // the package set not to be compressed, don't cab it. |
152 | if (OutputType.Product == this.Output.Type && | 158 | if (SectionType.Product == this.Section.Type && |
153 | (!facade.File.Compressed.Value || | 159 | ((facade.File.Compressed.HasValue && !facade.File.Compressed.Value) || |
154 | (!facade.File.Compressed.HasValue && !this.FilesCompressed))) | 160 | (!facade.File.Compressed.HasValue && !this.FilesCompressed))) |
155 | { | 161 | { |
156 | uncompressedFiles.Add(facade); | 162 | uncompressedFiles.Add(facade); |
157 | continue; | 163 | continue; |
@@ -172,8 +178,8 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
172 | if (currentPreCabSize > maxPreCabSizeInBytes) | 178 | if (currentPreCabSize > maxPreCabSizeInBytes) |
173 | { | 179 | { |
174 | // Overflow due to current file | 180 | // Overflow due to current file |
175 | currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex); | 181 | currentMediaRow = this.AddMediaRow(mediaTemplateRow, ++currentCabIndex); |
176 | mediaRows.Add(currentMediaRow); | 182 | mediaRows.Add(currentMediaRow.DiskId, currentMediaRow); |
177 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); | 183 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); |
178 | 184 | ||
179 | List<FileFacade> cabinetFileRows = filesByCabinetMedia[currentMediaRow]; | 185 | List<FileFacade> cabinetFileRows = filesByCabinetMedia[currentMediaRow]; |
@@ -188,8 +194,8 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
188 | if (currentMediaRow == null) | 194 | if (currentMediaRow == null) |
189 | { | 195 | { |
190 | // Create new cab and MediaRow | 196 | // Create new cab and MediaRow |
191 | currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex); | 197 | currentMediaRow = this.AddMediaRow(mediaTemplateRow, ++currentCabIndex); |
192 | mediaRows.Add(currentMediaRow); | 198 | mediaRows.Add(currentMediaRow.DiskId, currentMediaRow); |
193 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); | 199 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); |
194 | } | 200 | } |
195 | 201 | ||
@@ -201,11 +207,13 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
201 | } | 207 | } |
202 | 208 | ||
203 | // If there are uncompressed files and no MediaRow, create a default one. | 209 | // If there are uncompressed files and no MediaRow, create a default one. |
204 | if (uncompressedFiles.Count > 0 && mediaTable.Rows.Count == 0) | 210 | if (uncompressedFiles.Count > 0 && !this.Section.Tuples.OfType<MediaTuple>().Any()) |
205 | { | 211 | { |
206 | MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null); | 212 | var defaultMediaRow = new MediaTuple(null, new Identifier(1, AccessModifier.Private)); |
207 | defaultMediaRow.DiskId = 1; | 213 | defaultMediaRow.DiskId = 1; |
208 | mediaRows.Add(defaultMediaRow); | 214 | |
215 | mediaRows.Add(1, defaultMediaRow); | ||
216 | this.Section.Tuples.Add(defaultMediaRow); | ||
209 | } | 217 | } |
210 | } | 218 | } |
211 | 219 | ||
@@ -213,79 +221,65 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
213 | /// Assign files to cabinets based on Media authoring. | 221 | /// Assign files to cabinets based on Media authoring. |
214 | /// </summary> | 222 | /// </summary> |
215 | /// <param name="mediaTable"></param> | 223 | /// <param name="mediaTable"></param> |
216 | /// <param name="mergeModuleMediaRow"></param> | ||
217 | /// <param name="fileFacades"></param> | 224 | /// <param name="fileFacades"></param> |
218 | private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, IEnumerable<FileFacade> fileFacades, Dictionary<MediaRow, List<FileFacade>> filesByCabinetMedia, RowDictionary<MediaRow> mediaRows, List<FileFacade> uncompressedFiles) | 225 | private void ManuallyAssignFiles(List<MediaTuple> mediaTable, IEnumerable<FileFacade> fileFacades, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, Dictionary<int, MediaTuple> mediaRows, List<FileFacade> uncompressedFiles) |
219 | { | 226 | { |
220 | if (OutputType.Module != this.Output.Type) | 227 | if (mediaTable.Any()) |
221 | { | 228 | { |
222 | if (null != mediaTable) | 229 | var cabinetMediaRows = new Dictionary<string, MediaTuple>(StringComparer.OrdinalIgnoreCase); |
230 | foreach (var mediaRow in mediaTable) | ||
223 | { | 231 | { |
224 | Dictionary<string, MediaRow> cabinetMediaRows = new Dictionary<string, MediaRow>(StringComparer.InvariantCultureIgnoreCase); | 232 | // If the Media row has a cabinet, make sure it is unique across all Media rows. |
225 | foreach (MediaRow mediaRow in mediaTable.Rows) | 233 | if (!String.IsNullOrEmpty(mediaRow.Cabinet)) |
226 | { | 234 | { |
227 | // If the Media row has a cabinet, make sure it is unique across all Media rows. | 235 | if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out var existingRow)) |
228 | if (!String.IsNullOrEmpty(mediaRow.Cabinet)) | ||
229 | { | 236 | { |
230 | MediaRow existingRow; | 237 | Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); |
231 | if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow)) | 238 | Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); |
232 | { | 239 | } |
233 | Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); | 240 | else |
234 | Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); | 241 | { |
235 | } | 242 | cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow); |
236 | else | ||
237 | { | ||
238 | cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow); | ||
239 | } | ||
240 | } | 243 | } |
241 | |||
242 | mediaRows.Add(mediaRow); | ||
243 | } | 244 | } |
245 | |||
246 | mediaRows.Add(mediaRow.DiskId, mediaRow); | ||
244 | } | 247 | } |
248 | } | ||
245 | 249 | ||
246 | foreach (MediaRow mediaRow in mediaRows.Values) | 250 | foreach (var mediaRow in mediaRows.Values) |
251 | { | ||
252 | if (null != mediaRow.Cabinet) | ||
247 | { | 253 | { |
248 | if (null != mediaRow.Cabinet) | 254 | filesByCabinetMedia.Add(mediaRow, new List<FileFacade>()); |
249 | { | ||
250 | filesByCabinetMedia.Add(mediaRow, new List<FileFacade>()); | ||
251 | } | ||
252 | } | 255 | } |
253 | } | 256 | } |
254 | 257 | ||
255 | foreach (FileFacade facade in fileFacades) | 258 | foreach (FileFacade facade in fileFacades) |
256 | { | 259 | { |
257 | if (OutputType.Module == this.Output.Type) | 260 | if (!mediaRows.TryGetValue(facade.WixFile.DiskId, out var mediaRow)) |
258 | { | 261 | { |
259 | filesByCabinetMedia[mergeModuleMediaRow].Add(facade); | 262 | Messaging.Instance.OnMessage(WixErrors.MissingMedia(facade.File.SourceLineNumbers, facade.WixFile.DiskId)); |
263 | continue; | ||
260 | } | 264 | } |
261 | else | ||
262 | { | ||
263 | MediaRow mediaRow; | ||
264 | if (!mediaRows.TryGetValue(facade.WixFile.DiskId.ToString(CultureInfo.InvariantCulture), out mediaRow)) | ||
265 | { | ||
266 | Messaging.Instance.OnMessage(WixErrors.MissingMedia(facade.File.SourceLineNumbers, facade.WixFile.DiskId)); | ||
267 | continue; | ||
268 | } | ||
269 | 265 | ||
270 | // When building a product, if the current file is not to be compressed or if | 266 | // When building a product, if the current file is not to be compressed or if |
271 | // the package set not to be compressed, don't cab it. | 267 | // the package set not to be compressed, don't cab it. |
272 | if (OutputType.Product == this.Output.Type && | 268 | if (SectionType.Product == this.Section.Type && |
273 | (!facade.File.Compressed.Value || | 269 | (!facade.File.Compressed.Value || |
274 | (!facade.File.Compressed.HasValue && !this.FilesCompressed))) | 270 | (!facade.File.Compressed.HasValue && !this.FilesCompressed))) |
271 | { | ||
272 | uncompressedFiles.Add(facade); | ||
273 | } | ||
274 | else // file is marked compressed. | ||
275 | { | ||
276 | if (filesByCabinetMedia.TryGetValue(mediaRow, out var cabinetFiles)) | ||
275 | { | 277 | { |
276 | uncompressedFiles.Add(facade); | 278 | cabinetFiles.Add(facade); |
277 | } | 279 | } |
278 | else // file is marked compressed. | 280 | else |
279 | { | 281 | { |
280 | List<FileFacade> cabinetFiles; | 282 | Messaging.Instance.OnMessage(WixErrors.ExpectedMediaCabinet(facade.File.SourceLineNumbers, facade.File.File, facade.WixFile.DiskId)); |
281 | if (filesByCabinetMedia.TryGetValue(mediaRow, out cabinetFiles)) | ||
282 | { | ||
283 | cabinetFiles.Add(facade); | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | Messaging.Instance.OnMessage(WixErrors.ExpectedMediaCabinet(facade.File.SourceLineNumbers, facade.File.File, facade.WixFile.DiskId)); | ||
288 | } | ||
289 | } | 283 | } |
290 | } | 284 | } |
291 | } | 285 | } |
@@ -297,17 +291,20 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
297 | /// <param name="mediaTable"></param> | 291 | /// <param name="mediaTable"></param> |
298 | /// <param name="cabIndex"></param> | 292 | /// <param name="cabIndex"></param> |
299 | /// <returns></returns> | 293 | /// <returns></returns> |
300 | private MediaRow AddMediaRow(WixMediaTemplateRow mediaTemplateRow, Table mediaTable, int cabIndex) | 294 | private MediaTuple AddMediaRow(WixMediaTemplateTuple mediaTemplateRow, int cabIndex) |
301 | { | 295 | { |
302 | MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers); | 296 | var currentMediaRow = new MediaTuple(mediaTemplateRow.SourceLineNumbers, new Identifier(cabIndex, AccessModifier.Private)); |
303 | currentMediaRow.DiskId = cabIndex; | 297 | currentMediaRow.DiskId = cabIndex; |
304 | currentMediaRow.Cabinet = String.Format(CultureInfo.InvariantCulture, this.CabinetNameTemplate, cabIndex); | 298 | currentMediaRow.Cabinet = String.Format(CultureInfo.InvariantCulture, this.CabinetNameTemplate, cabIndex); |
305 | 299 | ||
306 | Table wixMediaTable = this.Output.EnsureTable(this.TableDefinitions["WixMedia"]); | 300 | this.Section.Tuples.Add(currentMediaRow); |
307 | WixMediaRow row = (WixMediaRow)wixMediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers); | 301 | |
308 | row.DiskId = cabIndex; | 302 | var row = new WixMediaTuple(mediaTemplateRow.SourceLineNumbers, new Identifier(cabIndex, AccessModifier.Private)); |
303 | row.DiskId_ = cabIndex; | ||
309 | row.CompressionLevel = mediaTemplateRow.CompressionLevel; | 304 | row.CompressionLevel = mediaTemplateRow.CompressionLevel; |
310 | 305 | ||
306 | this.Section.Tuples.Add(row); | ||
307 | |||
311 | return currentMediaRow; | 308 | return currentMediaRow; |
312 | } | 309 | } |
313 | } | 310 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 5a61b63c..30a19a4b 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -3,21 +3,15 @@ | |||
3 | namespace WixToolset.Core.WindowsInstaller.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
8 | using System.Diagnostics; | ||
9 | using System.Globalization; | ||
10 | using System.IO; | 7 | using System.IO; |
11 | using System.Linq; | 8 | using System.Linq; |
12 | using WixToolset.Bind; | ||
13 | using WixToolset.Core.Bind; | 9 | using WixToolset.Core.Bind; |
14 | using WixToolset.Core.WindowsInstaller.Databases; | ||
15 | using WixToolset.Data; | 10 | using WixToolset.Data; |
16 | using WixToolset.Data.Bind; | 11 | using WixToolset.Data.Bind; |
17 | using WixToolset.Data.Rows; | 12 | using WixToolset.Data.Tuples; |
18 | using WixToolset.Extensibility; | 13 | using WixToolset.Extensibility; |
19 | using WixToolset.Extensibility.Services; | 14 | using WixToolset.Extensibility.Services; |
20 | using WixToolset.Msi; | ||
21 | 15 | ||
22 | /// <summary> | 16 | /// <summary> |
23 | /// Binds a databse. | 17 | /// Binds a databse. |
@@ -25,11 +19,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
25 | internal class BindDatabaseCommand | 19 | internal class BindDatabaseCommand |
26 | { | 20 | { |
27 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. | 21 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. |
28 | private static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); | 22 | internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); |
29 | 23 | ||
30 | public BindDatabaseCommand(IBindContext context, Validator validator) | 24 | public BindDatabaseCommand(IBindContext context, Validator validator) |
31 | { | 25 | { |
32 | this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); | 26 | this.TableDefinitions = WindowsInstallerStandardInternal.GetTableDefinitions(); |
33 | 27 | ||
34 | this.BindPaths = context.BindPaths; | 28 | this.BindPaths = context.BindPaths; |
35 | this.CabbingThreadCount = context.CabbingThreadCount; | 29 | this.CabbingThreadCount = context.CabbingThreadCount; |
@@ -73,8 +67,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
73 | 67 | ||
74 | private Intermediate Intermediate { get; } | 68 | private Intermediate Intermediate { get; } |
75 | 69 | ||
76 | private Output Output { get; } | ||
77 | |||
78 | private string OutputPath { get; } | 70 | private string OutputPath { get; } |
79 | 71 | ||
80 | private bool SuppressAddingValidationRows { get; } | 72 | private bool SuppressAddingValidationRows { get; } |
@@ -95,22 +87,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
95 | 87 | ||
96 | public void Execute() | 88 | public void Execute() |
97 | { | 89 | { |
98 | this.Intermediate.Save(this.OutputPath); | 90 | var section = this.Intermediate.Sections.Single(); |
99 | #if FINISH | ||
100 | List<FileTransfer> fileTransfers = new List<FileTransfer>(); | ||
101 | 91 | ||
102 | HashSet<string> suppressedTableNames = new HashSet<string>(); | 92 | var fileTransfers = new List<FileTransfer>(); |
103 | 93 | ||
104 | // If there are any fields to resolve later, create the cache to populate during bind. | 94 | var suppressedTableNames = new HashSet<string>(); |
105 | IDictionary<string, string> variableCache = null; | ||
106 | if (this.DelayedFields.Any()) | ||
107 | { | ||
108 | variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); | ||
109 | } | ||
110 | 95 | ||
111 | this.LocalizeUI(this.Output.Tables); | 96 | // If there are any fields to resolve later, create the cache to populate during bind. |
97 | var variableCache = this.DelayedFields.Any() ? new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) : null; | ||
112 | 98 | ||
113 | this.Output = CreateOutputFromIR(this.Intermediate); | 99 | this.LocalizeUI(section); |
114 | 100 | ||
115 | // Process the summary information table before the other tables. | 101 | // Process the summary information table before the other tables. |
116 | bool compressed; | 102 | bool compressed; |
@@ -118,8 +104,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
118 | int installerVersion; | 104 | int installerVersion; |
119 | string modularizationGuid; | 105 | string modularizationGuid; |
120 | { | 106 | { |
121 | BindSummaryInfoCommand command = new BindSummaryInfoCommand(); | 107 | var command = new BindSummaryInfoCommand(section); |
122 | command.Output = this.Output; | ||
123 | command.Execute(); | 108 | command.Execute(); |
124 | 109 | ||
125 | compressed = command.Compressed; | 110 | compressed = command.Compressed; |
@@ -128,42 +113,61 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
128 | modularizationGuid = command.ModularizationGuid; | 113 | modularizationGuid = command.ModularizationGuid; |
129 | } | 114 | } |
130 | 115 | ||
131 | // Stop processing if an error previously occurred. | 116 | // Add binder variables for all properties. |
132 | if (Messaging.Instance.EncounteredError) | 117 | if (SectionType.Product == section.Type || variableCache != null) |
133 | { | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | // Modularize identifiers and add tables with real streams to the import tables. | ||
138 | if (OutputType.Module == this.Output.Type) | ||
139 | { | 118 | { |
140 | // Gather all the suppress modularization identifiers | 119 | foreach (var propertyRow in section.Tuples.OfType<PropertyTuple>()) |
141 | HashSet<string> suppressModularizationIdentifiers = null; | ||
142 | Table wixSuppressModularizationTable = this.Output.Tables["WixSuppressModularization"]; | ||
143 | if (null != wixSuppressModularizationTable) | ||
144 | { | 120 | { |
145 | suppressModularizationIdentifiers = new HashSet<string>(wixSuppressModularizationTable.Rows.Select(row => (string)row[0])); | 121 | // Set the ProductCode if it is to be generated. |
146 | } | 122 | if ("ProductCode".Equals(propertyRow.Property, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal)) |
123 | { | ||
124 | propertyRow.Value = Common.GenerateGuid(); | ||
147 | 125 | ||
148 | foreach (Table table in this.Output.Tables) | 126 | #if TODO_FIX_INSTANCE_TRANSFORM |
149 | { | 127 | // Update the target ProductCode in any instance transforms. |
150 | table.Modularize(modularizationGuid, suppressModularizationIdentifiers); | 128 | foreach (SubStorage subStorage in this.Output.SubStorages) |
129 | { | ||
130 | Output subStorageOutput = subStorage.Data; | ||
131 | if (OutputType.Transform != subStorageOutput.Type) | ||
132 | { | ||
133 | continue; | ||
134 | } | ||
135 | |||
136 | Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; | ||
137 | foreach (Row row in instanceSummaryInformationTable.Rows) | ||
138 | { | ||
139 | if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) | ||
140 | { | ||
141 | row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | #endif | ||
147 | } | ||
148 | |||
149 | // Add the property name and value to the variableCache. | ||
150 | if (variableCache != null) | ||
151 | { | ||
152 | var key = String.Concat("property.", propertyRow.Property); | ||
153 | variableCache[key] = propertyRow.Value; | ||
154 | } | ||
151 | } | 155 | } |
152 | } | 156 | } |
153 | 157 | ||
154 | // This must occur after all variables and source paths have been resolved and after modularization. | 158 | // Sequence all the actions. |
155 | List<FileFacade> fileFacades; | ||
156 | { | 159 | { |
157 | GetFileFacadesCommand command = new GetFileFacadesCommand(); | 160 | var command = new SequenceActionsCommand(section); |
158 | command.FileTable = this.Output.Tables["File"]; | 161 | command.Messaging = Messaging.Instance; |
159 | command.WixFileTable = this.Output.Tables["WixFile"]; | ||
160 | command.WixDeltaPatchFileTable = this.Output.Tables["WixDeltaPatchFile"]; | ||
161 | command.WixDeltaPatchSymbolPathsTable = this.Output.Tables["WixDeltaPatchSymbolPaths"]; | ||
162 | command.Execute(); | 162 | command.Execute(); |
163 | } | ||
163 | 164 | ||
164 | fileFacades = command.FileFacades; | 165 | { |
166 | var command = new CreateSpecialPropertiesCommand(section); | ||
167 | command.Execute(); | ||
165 | } | 168 | } |
166 | 169 | ||
170 | #if TODO_FINISH_PATCH | ||
167 | ////if (OutputType.Patch == this.Output.Type) | 171 | ////if (OutputType.Patch == this.Output.Type) |
168 | ////{ | 172 | ////{ |
169 | //// foreach (SubStorage substorage in this.Output.SubStorages) | 173 | //// foreach (SubStorage substorage in this.Output.SubStorages) |
@@ -183,87 +187,72 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
183 | //// this.MergeUnrealTables(transform.Tables); | 187 | //// this.MergeUnrealTables(transform.Tables); |
184 | //// } | 188 | //// } |
185 | ////} | 189 | ////} |
186 | 190 | #endif | |
187 | { | ||
188 | CreateSpecialPropertiesCommand command = new CreateSpecialPropertiesCommand(); | ||
189 | command.PropertyTable = this.Output.Tables["Property"]; | ||
190 | command.WixPropertyTable = this.Output.Tables["WixProperty"]; | ||
191 | command.Execute(); | ||
192 | } | ||
193 | 191 | ||
194 | if (Messaging.Instance.EncounteredError) | 192 | if (Messaging.Instance.EncounteredError) |
195 | { | 193 | { |
196 | return; | 194 | return; |
197 | } | 195 | } |
198 | 196 | ||
199 | // Add binder variables for all properties. | 197 | Messaging.Instance.OnMessage(WixVerboses.UpdatingFileInformation()); |
200 | Table propertyTable = this.Output.Tables["Property"]; | 198 | |
201 | if (null != propertyTable) | 199 | // This must occur after all variables and source paths have been resolved. |
200 | List<FileFacade> fileFacades; | ||
202 | { | 201 | { |
203 | foreach (PropertyRow propertyRow in propertyTable.Rows) | 202 | var command = new GetFileFacadesCommand(section); |
204 | { | 203 | command.Execute(); |
205 | // Set the ProductCode if it is to be generated. | ||
206 | if (OutputType.Product == this.Output.Type && "ProductCode".Equals(propertyRow.Property, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal)) | ||
207 | { | ||
208 | propertyRow.Value = Common.GenerateGuid(); | ||
209 | 204 | ||
210 | // Update the target ProductCode in any instance transforms. | 205 | fileFacades = command.FileFacades; |
211 | foreach (SubStorage subStorage in this.Output.SubStorages) | 206 | } |
212 | { | ||
213 | Output subStorageOutput = subStorage.Data; | ||
214 | if (OutputType.Transform != subStorageOutput.Type) | ||
215 | { | ||
216 | continue; | ||
217 | } | ||
218 | 207 | ||
219 | Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; | 208 | // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). |
220 | foreach (Row row in instanceSummaryInformationTable.Rows) | 209 | { |
221 | { | 210 | var command = new ExtractEmbeddedFilesCommand(this.ExpectedEmbeddedFiles); |
222 | if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) | 211 | command.Execute(); |
223 | { | 212 | } |
224 | row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | 213 | ||
231 | // Add the property name and value to the variableCache. | 214 | // Gather information about files that did not come from merge modules (i.e. rows with a reference to the File table). |
232 | if (null != variableCache) | 215 | { |
233 | { | 216 | var command = new UpdateFileFacadesCommand(section); |
234 | string key = String.Concat("property.", Common.Demodularize(this.Output.Type, modularizationGuid, propertyRow.Property)); | 217 | command.FileFacades = fileFacades; |
235 | variableCache[key] = propertyRow.Value; | 218 | command.UpdateFileFacades = fileFacades.Where(f => !f.FromModule); |
236 | } | 219 | command.OverwriteHash = true; |
237 | } | 220 | command.TableDefinitions = this.TableDefinitions; |
221 | command.VariableCache = variableCache; | ||
222 | command.Execute(); | ||
238 | } | 223 | } |
239 | 224 | ||
240 | // Extract files that come from cabinet files (this does not extract files from merge modules). | 225 | // Now that the variable cache is populated, resolve any delayed fields. |
226 | if (this.DelayedFields.Any()) | ||
241 | { | 227 | { |
242 | ExtractEmbeddedFilesCommand command = new ExtractEmbeddedFilesCommand(); | 228 | var command = new ResolveDelayedFieldsCommand(this.DelayedFields, variableCache); |
243 | command.FilesWithEmbeddedFiles = this.ExpectedEmbeddedFiles; | ||
244 | command.Execute(); | 229 | command.Execute(); |
245 | } | 230 | } |
246 | 231 | ||
247 | if (OutputType.Product == this.Output.Type) | 232 | // Set generated component guids. |
233 | { | ||
234 | var command = new CalculateComponentGuids(section); | ||
235 | command.Execute(); | ||
236 | } | ||
237 | |||
238 | if (SectionType.Product == section.Type) | ||
248 | { | 239 | { |
249 | // Retrieve files and their information from merge modules. | 240 | // Retrieve files and their information from merge modules. |
250 | Table wixMergeTable = this.Output.Tables["WixMerge"]; | 241 | var wixMergeTuples = section.Tuples.OfType<WixMergeTuple>().ToList(); |
251 | 242 | ||
252 | if (null != wixMergeTable) | 243 | if (wixMergeTuples.Any()) |
253 | { | 244 | { |
254 | ExtractMergeModuleFilesCommand command = new ExtractMergeModuleFilesCommand(); | 245 | var command = new ExtractMergeModuleFilesCommand(section, wixMergeTuples); |
255 | command.FileFacades = fileFacades; | 246 | command.FileFacades = fileFacades; |
256 | command.FileTable = this.Output.Tables["File"]; | ||
257 | command.WixFileTable = this.Output.Tables["WixFile"]; | ||
258 | command.WixMergeTable = wixMergeTable; | ||
259 | command.OutputInstallerVersion = installerVersion; | 247 | command.OutputInstallerVersion = installerVersion; |
260 | command.SuppressLayout = this.SuppressLayout; | 248 | command.SuppressLayout = this.SuppressLayout; |
261 | command.TempFilesLocation = this.IntermediateFolder; | 249 | command.IntermediateFolder = this.IntermediateFolder; |
262 | command.Execute(); | 250 | command.Execute(); |
263 | 251 | ||
264 | fileFacades.AddRange(command.MergeModulesFileFacades); | 252 | fileFacades.AddRange(command.MergeModulesFileFacades); |
265 | } | 253 | } |
266 | } | 254 | } |
255 | #if TODO_FINISH_PATCH | ||
267 | else if (OutputType.Patch == this.Output.Type) | 256 | else if (OutputType.Patch == this.Output.Type) |
268 | { | 257 | { |
269 | // Merge transform data into the output object. | 258 | // Merge transform data into the output object. |
@@ -271,6 +260,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
271 | 260 | ||
272 | fileFacades.AddRange(filesFromTransform); | 261 | fileFacades.AddRange(filesFromTransform); |
273 | } | 262 | } |
263 | #endif | ||
274 | 264 | ||
275 | // stop processing if an error previously occurred | 265 | // stop processing if an error previously occurred |
276 | if (Messaging.Instance.EncounteredError) | 266 | if (Messaging.Instance.EncounteredError) |
@@ -278,51 +268,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
278 | return; | 268 | return; |
279 | } | 269 | } |
280 | 270 | ||
281 | Messaging.Instance.OnMessage(WixVerboses.UpdatingFileInformation()); | 271 | #if TODO_FIX_INSTANCE_TRANSFORM |
282 | |||
283 | // Gather information about files that did not come from merge modules (i.e. rows with a reference to the File table). | ||
284 | { | ||
285 | UpdateFileFacadesCommand command = new UpdateFileFacadesCommand(); | ||
286 | command.FileFacades = fileFacades; | ||
287 | command.UpdateFileFacades = fileFacades.Where(f => !f.FromModule); | ||
288 | command.ModularizationGuid = modularizationGuid; | ||
289 | command.Output = this.Output; | ||
290 | command.OverwriteHash = true; | ||
291 | command.TableDefinitions = this.TableDefinitions; | ||
292 | command.VariableCache = variableCache; | ||
293 | command.Execute(); | ||
294 | } | ||
295 | |||
296 | // Set generated component guids. | ||
297 | this.SetComponentGuids(this.Output); | ||
298 | |||
299 | // With the Component Guids set now we can create instance transforms. | 272 | // With the Component Guids set now we can create instance transforms. |
300 | this.CreateInstanceTransforms(this.Output); | 273 | this.CreateInstanceTransforms(this.Output); |
301 | 274 | #endif | |
302 | this.ValidateComponentGuids(this.Output); | ||
303 | |||
304 | this.UpdateControlText(this.Output); | ||
305 | |||
306 | if (this.DelayedFields.Any()) | ||
307 | { | ||
308 | ResolveDelayedFieldsCommand command = new ResolveDelayedFieldsCommand(); | ||
309 | command.OutputType = this.Output.Type; | ||
310 | command.DelayedFields = this.DelayedFields; | ||
311 | command.ModularizationGuid = null; | ||
312 | command.VariableCache = variableCache; | ||
313 | command.Execute(); | ||
314 | } | ||
315 | 275 | ||
316 | // Assign files to media. | 276 | // Assign files to media. |
317 | RowDictionary<MediaRow> assignedMediaRows; | 277 | Dictionary<int, MediaTuple> assignedMediaRows; |
318 | Dictionary<MediaRow, IEnumerable<FileFacade>> filesByCabinetMedia; | 278 | Dictionary<MediaTuple, IEnumerable<FileFacade>> filesByCabinetMedia; |
319 | IEnumerable<FileFacade> uncompressedFiles; | 279 | IEnumerable<FileFacade> uncompressedFiles; |
320 | { | 280 | { |
321 | AssignMediaCommand command = new AssignMediaCommand(); | 281 | var command = new AssignMediaCommand(section); |
322 | command.FilesCompressed = compressed; | ||
323 | command.FileFacades = fileFacades; | 282 | command.FileFacades = fileFacades; |
324 | command.Output = this.Output; | 283 | command.FilesCompressed = compressed; |
325 | command.TableDefinitions = this.TableDefinitions; | ||
326 | command.Execute(); | 284 | command.Execute(); |
327 | 285 | ||
328 | assignedMediaRows = command.MediaRows; | 286 | assignedMediaRows = command.MediaRows; |
@@ -330,15 +288,40 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
330 | uncompressedFiles = command.UncompressedFileFacades; | 288 | uncompressedFiles = command.UncompressedFileFacades; |
331 | } | 289 | } |
332 | 290 | ||
333 | // Update file sequence. | ||
334 | this.UpdateMediaSequences(this.Output.Type, fileFacades, assignedMediaRows); | ||
335 | |||
336 | // stop processing if an error previously occurred | 291 | // stop processing if an error previously occurred |
337 | if (Messaging.Instance.EncounteredError) | 292 | if (Messaging.Instance.EncounteredError) |
338 | { | 293 | { |
339 | return; | 294 | return; |
340 | } | 295 | } |
341 | 296 | ||
297 | // Try to put as much above here as possible, updating the IR is better. | ||
298 | Output output; | ||
299 | { | ||
300 | var command = new CreateOutputFromIRCommand(section, this.TableDefinitions); | ||
301 | command.Execute(); | ||
302 | |||
303 | output = command.Output; | ||
304 | } | ||
305 | |||
306 | // Update file sequence. | ||
307 | { | ||
308 | var command = new UpdateMediaSequencesCommand(output, fileFacades, assignedMediaRows); | ||
309 | command.Execute(); | ||
310 | } | ||
311 | |||
312 | // Modularize identifiers and add tables with real streams to the import tables. | ||
313 | if (OutputType.Module == output.Type) | ||
314 | { | ||
315 | // Gather all the suppress modularization identifiers | ||
316 | var suppressModularizationIdentifiers = new HashSet<string>(section.Tuples.OfType<WixSuppressModularizationTuple>().Select(s => s.WixSuppressModularization)); | ||
317 | |||
318 | foreach (var table in output.Tables) | ||
319 | { | ||
320 | table.Modularize(modularizationGuid, suppressModularizationIdentifiers); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | #if TODO_FINISH_UPDATE | ||
342 | // Extended binder extensions can be called now that fields are resolved. | 325 | // Extended binder extensions can be called now that fields are resolved. |
343 | { | 326 | { |
344 | Table updatedFiles = this.Output.EnsureTable(this.TableDefinitions["WixBindUpdatedFiles"]); | 327 | Table updatedFiles = this.Output.EnsureTable(this.TableDefinitions["WixBindUpdatedFiles"]); |
@@ -372,27 +355,27 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
372 | command.Execute(); | 355 | command.Execute(); |
373 | } | 356 | } |
374 | } | 357 | } |
358 | #endif | ||
375 | 359 | ||
376 | // stop processing if an error previously occurred | 360 | // Stop processing if an error previously occurred. |
377 | if (Messaging.Instance.EncounteredError) | 361 | if (Messaging.Instance.EncounteredError) |
378 | { | 362 | { |
379 | return; | 363 | return; |
380 | } | 364 | } |
381 | 365 | ||
366 | // Ensure the intermediate folder is created since delta patches will be | ||
367 | // created there. | ||
382 | Directory.CreateDirectory(this.IntermediateFolder); | 368 | Directory.CreateDirectory(this.IntermediateFolder); |
383 | 369 | ||
384 | if (OutputType.Patch == this.Output.Type && this.DeltaBinaryPatch) | 370 | if (SectionType.Patch == section.Type && this.DeltaBinaryPatch) |
385 | { | 371 | { |
386 | CreateDeltaPatchesCommand command = new CreateDeltaPatchesCommand(); | 372 | var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Tuples.OfType<WixPatchIdTuple>().FirstOrDefault()); |
387 | command.FileFacades = fileFacades; | ||
388 | command.WixPatchIdTable = this.Output.Tables["WixPatchId"]; | ||
389 | command.TempFilesLocation = this.IntermediateFolder; | ||
390 | command.Execute(); | 373 | command.Execute(); |
391 | } | 374 | } |
392 | 375 | ||
393 | // create cabinet files and process uncompressed files | 376 | // create cabinet files and process uncompressed files |
394 | string layoutDirectory = Path.GetDirectoryName(this.OutputPath); | 377 | string layoutDirectory = Path.GetDirectoryName(this.OutputPath); |
395 | if (!this.SuppressLayout || OutputType.Module == this.Output.Type) | 378 | if (!this.SuppressLayout || OutputType.Module == output.Type) |
396 | { | 379 | { |
397 | Messaging.Instance.OnMessage(WixVerboses.CreatingCabinetFiles()); | 380 | Messaging.Instance.OnMessage(WixVerboses.CreatingCabinetFiles()); |
398 | 381 | ||
@@ -400,7 +383,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
400 | command.CabbingThreadCount = this.CabbingThreadCount; | 383 | command.CabbingThreadCount = this.CabbingThreadCount; |
401 | command.CabCachePath = this.CabCachePath; | 384 | command.CabCachePath = this.CabCachePath; |
402 | command.DefaultCompressionLevel = this.DefaultCompressionLevel; | 385 | command.DefaultCompressionLevel = this.DefaultCompressionLevel; |
403 | command.Output = this.Output; | 386 | command.Output = output; |
404 | command.BackendExtensions = this.BackendExtensions; | 387 | command.BackendExtensions = this.BackendExtensions; |
405 | command.LayoutDirectory = layoutDirectory; | 388 | command.LayoutDirectory = layoutDirectory; |
406 | command.Compressed = compressed; | 389 | command.Compressed = compressed; |
@@ -408,39 +391,35 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
408 | command.ResolveMedia = this.ResolveMedia; | 391 | command.ResolveMedia = this.ResolveMedia; |
409 | command.TableDefinitions = this.TableDefinitions; | 392 | command.TableDefinitions = this.TableDefinitions; |
410 | command.TempFilesLocation = this.IntermediateFolder; | 393 | command.TempFilesLocation = this.IntermediateFolder; |
411 | command.WixMediaTable = this.Output.Tables["WixMedia"]; | 394 | command.WixMediaTable = output.Tables["WixMedia"]; |
412 | command.Execute(); | 395 | command.Execute(); |
413 | 396 | ||
414 | fileTransfers.AddRange(command.FileTransfers); | 397 | fileTransfers.AddRange(command.FileTransfers); |
415 | } | 398 | } |
416 | 399 | ||
400 | #if TODO_FINISH_PATCH | ||
417 | if (OutputType.Patch == this.Output.Type) | 401 | if (OutputType.Patch == this.Output.Type) |
418 | { | 402 | { |
419 | // copy output data back into the transforms | 403 | // copy output data back into the transforms |
420 | this.CopyToTransformData(this.Output); | 404 | this.CopyToTransformData(this.Output); |
421 | } | 405 | } |
406 | #endif | ||
422 | 407 | ||
423 | // stop processing if an error previously occurred | 408 | // Add back suppressed tables which must be present prior to merging in modules. |
424 | if (Messaging.Instance.EncounteredError) | 409 | if (OutputType.Product == output.Type) |
425 | { | ||
426 | return; | ||
427 | } | ||
428 | |||
429 | // add back suppressed tables which must be present prior to merging in modules | ||
430 | if (OutputType.Product == this.Output.Type) | ||
431 | { | 410 | { |
432 | Table wixMergeTable = this.Output.Tables["WixMerge"]; | 411 | Table wixMergeTable = output.Tables["WixMerge"]; |
433 | 412 | ||
434 | if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count) | 413 | if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count) |
435 | { | 414 | { |
436 | foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) | 415 | foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) |
437 | { | 416 | { |
438 | string sequenceTableName = sequence.ToString(); | 417 | string sequenceTableName = sequence.ToString(); |
439 | Table sequenceTable = this.Output.Tables[sequenceTableName]; | 418 | Table sequenceTable = output.Tables[sequenceTableName]; |
440 | 419 | ||
441 | if (null == sequenceTable) | 420 | if (null == sequenceTable) |
442 | { | 421 | { |
443 | sequenceTable = this.Output.EnsureTable(this.TableDefinitions[sequenceTableName]); | 422 | sequenceTable = output.EnsureTable(this.TableDefinitions[sequenceTableName]); |
444 | } | 423 | } |
445 | 424 | ||
446 | if (0 == sequenceTable.Rows.Count) | 425 | if (0 == sequenceTable.Rows.Count) |
@@ -456,67 +435,59 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
456 | // extension.PostBind(this.Context); | 435 | // extension.PostBind(this.Context); |
457 | //} | 436 | //} |
458 | 437 | ||
459 | // generate database file | 438 | this.ValidateComponentGuids(output); |
439 | |||
440 | // stop processing if an error previously occurred | ||
441 | if (Messaging.Instance.EncounteredError) | ||
442 | { | ||
443 | return; | ||
444 | } | ||
445 | |||
446 | // Generate database file. | ||
460 | Messaging.Instance.OnMessage(WixVerboses.GeneratingDatabase()); | 447 | Messaging.Instance.OnMessage(WixVerboses.GeneratingDatabase()); |
461 | string tempDatabaseFile = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); | 448 | string tempDatabaseFile = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); |
462 | this.GenerateDatabase(this.Output, tempDatabaseFile, false, false); | 449 | this.GenerateDatabase(output, tempDatabaseFile, false, false); |
463 | 450 | ||
464 | FileTransfer transfer; | 451 | if (FileTransfer.TryCreate(tempDatabaseFile, this.OutputPath, true, output.Type.ToString(), null, out var transfer)) // note where this database needs to move in the future |
465 | if (FileTransfer.TryCreate(tempDatabaseFile, this.OutputPath, true, this.Output.Type.ToString(), null, out transfer)) // note where this database needs to move in the future | ||
466 | { | 452 | { |
467 | transfer.Built = true; | 453 | transfer.Built = true; |
468 | fileTransfers.Add(transfer); | 454 | fileTransfers.Add(transfer); |
469 | } | 455 | } |
470 | 456 | ||
471 | // stop processing if an error previously occurred | 457 | // Stop processing if an error previously occurred. |
472 | if (Messaging.Instance.EncounteredError) | 458 | if (Messaging.Instance.EncounteredError) |
473 | { | 459 | { |
474 | return; | 460 | return; |
475 | } | 461 | } |
476 | 462 | ||
477 | // Output the output to a file | 463 | // Output the output to a file. |
478 | Pdb pdb = new Pdb(); | 464 | Pdb pdb = new Pdb(); |
479 | pdb.Output = this.Output; | 465 | pdb.Output = output; |
480 | if (!String.IsNullOrEmpty(this.PdbFile)) | 466 | if (!String.IsNullOrEmpty(this.PdbFile)) |
481 | { | 467 | { |
482 | pdb.Save(this.PdbFile); | 468 | pdb.Save(this.PdbFile); |
483 | } | 469 | } |
484 | 470 | ||
485 | // Merge modules. | 471 | // Merge modules. |
486 | if (OutputType.Product == this.Output.Type) | 472 | if (OutputType.Product == output.Type) |
487 | { | 473 | { |
488 | Messaging.Instance.OnMessage(WixVerboses.MergingModules()); | 474 | Messaging.Instance.OnMessage(WixVerboses.MergingModules()); |
489 | 475 | ||
490 | MergeModulesCommand command = new MergeModulesCommand(); | 476 | var command = new MergeModulesCommand(); |
491 | command.FileFacades = fileFacades; | 477 | command.FileFacades = fileFacades; |
492 | command.Output = this.Output; | 478 | command.Output = output; |
493 | command.OutputPath = tempDatabaseFile; | 479 | command.OutputPath = tempDatabaseFile; |
494 | command.SuppressedTableNames = suppressedTableNames; | 480 | command.SuppressedTableNames = suppressedTableNames; |
495 | command.Execute(); | 481 | command.Execute(); |
496 | |||
497 | // stop processing if an error previously occurred | ||
498 | if (Messaging.Instance.EncounteredError) | ||
499 | { | ||
500 | return; | ||
501 | } | ||
502 | } | 482 | } |
503 | 483 | ||
504 | // inspect the MSI prior to running ICEs | ||
505 | //InspectorCore inspectorCore = new InspectorCore(); | ||
506 | //foreach (InspectorExtension inspectorExtension in this.InspectorExtensions) | ||
507 | //{ | ||
508 | // inspectorExtension.Core = inspectorCore; | ||
509 | // inspectorExtension.InspectDatabase(tempDatabaseFile, pdb); | ||
510 | |||
511 | // inspectorExtension.Core = null; // reset. | ||
512 | //} | ||
513 | |||
514 | if (Messaging.Instance.EncounteredError) | 484 | if (Messaging.Instance.EncounteredError) |
515 | { | 485 | { |
516 | return; | 486 | return; |
517 | } | 487 | } |
518 | 488 | ||
519 | // validate the output if there is an MSI validator | 489 | #if TODO_FINISH_VALIDATION |
490 | // Validate the output if there is an MSI validator. | ||
520 | if (null != this.Validator) | 491 | if (null != this.Validator) |
521 | { | 492 | { |
522 | Stopwatch stopwatch = Stopwatch.StartNew(); | 493 | Stopwatch stopwatch = Stopwatch.StartNew(); |
@@ -537,19 +508,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
537 | return; | 508 | return; |
538 | } | 509 | } |
539 | } | 510 | } |
511 | #endif | ||
540 | 512 | ||
541 | // Process uncompressed files. | 513 | // Process uncompressed files. |
542 | if (!Messaging.Instance.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any()) | 514 | if (!Messaging.Instance.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any()) |
543 | { | 515 | { |
544 | var command = new ProcessUncompressedFilesCommand(); | 516 | var command = new ProcessUncompressedFilesCommand(section); |
545 | command.Compressed = compressed; | 517 | command.Compressed = compressed; |
546 | command.FileFacades = uncompressedFiles; | 518 | command.FileFacades = uncompressedFiles; |
547 | command.LayoutDirectory = layoutDirectory; | 519 | command.LayoutDirectory = layoutDirectory; |
548 | command.LongNamesInImage = longNames; | 520 | command.LongNamesInImage = longNames; |
549 | command.MediaRows = assignedMediaRows; | ||
550 | command.ResolveMedia = this.ResolveMedia; | 521 | command.ResolveMedia = this.ResolveMedia; |
551 | command.DatabasePath = tempDatabaseFile; | 522 | command.DatabasePath = tempDatabaseFile; |
552 | command.WixMediaTable = this.Output.Tables["WixMedia"]; | ||
553 | command.Execute(); | 523 | command.Execute(); |
554 | 524 | ||
555 | fileTransfers.AddRange(command.FileTransfers); | 525 | fileTransfers.AddRange(command.FileTransfers); |
@@ -557,94 +527,92 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
557 | 527 | ||
558 | this.FileTransfers = fileTransfers; | 528 | this.FileTransfers = fileTransfers; |
559 | this.ContentFilePaths = fileFacades.Select(r => r.WixFile.Source).ToList(); | 529 | this.ContentFilePaths = fileFacades.Select(r => r.WixFile.Source).ToList(); |
530 | |||
531 | // TODO: Eventually this gets removed | ||
532 | var intermediate = new Intermediate(this.Intermediate.Id, new[] { section }, this.Intermediate.Localizations.ToDictionary(l => l.Culture, StringComparer.OrdinalIgnoreCase), this.Intermediate.EmbedFilePaths); | ||
533 | intermediate.Save(Path.ChangeExtension(this.OutputPath, "wir")); | ||
560 | } | 534 | } |
561 | 535 | ||
562 | /// <summary> | 536 | /// <summary> |
563 | /// Localize dialogs and controls. | 537 | /// Localize dialogs and controls. |
564 | /// </summary> | 538 | /// </summary> |
565 | /// <param name="tables">The tables to localize.</param> | 539 | /// <param name="tables">The tables to localize.</param> |
566 | private void LocalizeUI(TableIndexedCollection tables) | 540 | private void LocalizeUI(IntermediateSection section) |
567 | { | 541 | { |
568 | Table dialogTable = tables["Dialog"]; | 542 | foreach (var row in section.Tuples.OfType<DialogTuple>()) |
569 | if (null != dialogTable) | ||
570 | { | 543 | { |
571 | foreach (Row row in dialogTable.Rows) | 544 | string dialog = row.Dialog; |
572 | { | ||
573 | string dialog = (string)row[0]; | ||
574 | 545 | ||
575 | if (this.WixVariableResolver.TryGetLocalizedControl(dialog, null, out LocalizedControl localizedControl)) | 546 | if (this.WixVariableResolver.TryGetLocalizedControl(dialog, null, out LocalizedControl localizedControl)) |
547 | { | ||
548 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | ||
576 | { | 549 | { |
577 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | 550 | row.HCentering = localizedControl.X; |
578 | { | 551 | } |
579 | row[1] = localizedControl.X; | ||
580 | } | ||
581 | 552 | ||
582 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) | 553 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) |
583 | { | 554 | { |
584 | row[2] = localizedControl.Y; | 555 | row.VCentering = localizedControl.Y; |
585 | } | 556 | } |
586 | 557 | ||
587 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) | 558 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) |
588 | { | 559 | { |
589 | row[3] = localizedControl.Width; | 560 | row.Width = localizedControl.Width; |
590 | } | 561 | } |
591 | 562 | ||
592 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) | 563 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) |
593 | { | 564 | { |
594 | row[4] = localizedControl.Height; | 565 | row.Height = localizedControl.Height; |
595 | } | 566 | } |
596 | 567 | ||
597 | row[5] = (int)row[5] | localizedControl.Attributes; | 568 | row.Attributes = row.Attributes | localizedControl.Attributes; |
598 | 569 | ||
599 | if (!String.IsNullOrEmpty(localizedControl.Text)) | 570 | if (!String.IsNullOrEmpty(localizedControl.Text)) |
600 | { | 571 | { |
601 | row[6] = localizedControl.Text; | 572 | row.Title = localizedControl.Text; |
602 | } | ||
603 | } | 573 | } |
604 | } | 574 | } |
605 | } | 575 | } |
606 | 576 | ||
607 | Table controlTable = tables["Control"]; | 577 | |
608 | if (null != controlTable) | 578 | foreach (var row in section.Tuples.OfType<ControlTuple>()) |
609 | { | 579 | { |
610 | foreach (Row row in controlTable.Rows) | 580 | string dialog = row.Dialog_; |
611 | { | 581 | string control = row.Control; |
612 | string dialog = (string)row[0]; | ||
613 | string control = (string)row[1]; | ||
614 | 582 | ||
615 | if (this.WixVariableResolver.TryGetLocalizedControl(dialog, control, out LocalizedControl localizedControl)) | 583 | if (this.WixVariableResolver.TryGetLocalizedControl(dialog, control, out LocalizedControl localizedControl)) |
584 | { | ||
585 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | ||
616 | { | 586 | { |
617 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | 587 | row.X = localizedControl.X; |
618 | { | 588 | } |
619 | row[3] = localizedControl.X.ToString(); | ||
620 | } | ||
621 | 589 | ||
622 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) | 590 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) |
623 | { | 591 | { |
624 | row[4] = localizedControl.Y.ToString(); | 592 | row.Y = localizedControl.Y; |
625 | } | 593 | } |
626 | 594 | ||
627 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) | 595 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) |
628 | { | 596 | { |
629 | row[5] = localizedControl.Width.ToString(); | 597 | row.Width = localizedControl.Width; |
630 | } | 598 | } |
631 | 599 | ||
632 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) | 600 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) |
633 | { | 601 | { |
634 | row[6] = localizedControl.Height.ToString(); | 602 | row.Height = localizedControl.Height; |
635 | } | 603 | } |
636 | 604 | ||
637 | row[7] = (int)row[7] | localizedControl.Attributes; | 605 | row.Attributes = row.Attributes | localizedControl.Attributes; |
638 | 606 | ||
639 | if (!String.IsNullOrEmpty(localizedControl.Text)) | 607 | if (!String.IsNullOrEmpty(localizedControl.Text)) |
640 | { | 608 | { |
641 | row[9] = localizedControl.Text; | 609 | row.Text = localizedControl.Text; |
642 | } | ||
643 | } | 610 | } |
644 | } | 611 | } |
645 | } | 612 | } |
646 | } | 613 | } |
647 | 614 | ||
615 | #if TODO_FINISH_PATCH | ||
648 | /// <summary> | 616 | /// <summary> |
649 | /// Copy file data between transform substorages and the patch output object | 617 | /// Copy file data between transform substorages and the patch output object |
650 | /// </summary> | 618 | /// </summary> |
@@ -674,269 +642,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
674 | command.TableDefinitions = this.TableDefinitions; | 642 | command.TableDefinitions = this.TableDefinitions; |
675 | command.Execute(); | 643 | command.Execute(); |
676 | } | 644 | } |
645 | #endif | ||
677 | 646 | ||
678 | private void UpdateMediaSequences(OutputType outputType, IEnumerable<FileFacade> fileFacades, RowDictionary<MediaRow> mediaRows) | ||
679 | { | ||
680 | // Calculate sequence numbers and media disk id layout for all file media information objects. | ||
681 | if (OutputType.Module == outputType) | ||
682 | { | ||
683 | int lastSequence = 0; | ||
684 | foreach (FileFacade facade in fileFacades) // TODO: Sort these rows directory path and component id and maybe file size or file extension and other creative ideas to get optimal install speed out of MSI. | ||
685 | { | ||
686 | facade.File.Sequence = ++lastSequence; | ||
687 | } | ||
688 | } | ||
689 | else | ||
690 | { | ||
691 | int lastSequence = 0; | ||
692 | MediaRow mediaRow = null; | ||
693 | Dictionary<int, List<FileFacade>> patchGroups = new Dictionary<int, List<FileFacade>>(); | ||
694 | |||
695 | // sequence the non-patch-added files | ||
696 | foreach (FileFacade facade in fileFacades) // TODO: Sort these rows directory path and component id and maybe file size or file extension and other creative ideas to get optimal install speed out of MSI. | ||
697 | { | ||
698 | if (null == mediaRow) | ||
699 | { | ||
700 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
701 | if (OutputType.Patch == outputType) | ||
702 | { | ||
703 | // patch Media cannot start at zero | ||
704 | lastSequence = mediaRow.LastSequence; | ||
705 | } | ||
706 | } | ||
707 | else if (mediaRow.DiskId != facade.WixFile.DiskId) | ||
708 | { | ||
709 | mediaRow.LastSequence = lastSequence; | ||
710 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
711 | } | ||
712 | |||
713 | if (0 < facade.WixFile.PatchGroup) | ||
714 | { | ||
715 | List<FileFacade> patchGroup = patchGroups[facade.WixFile.PatchGroup]; | ||
716 | |||
717 | if (null == patchGroup) | ||
718 | { | ||
719 | patchGroup = new List<FileFacade>(); | ||
720 | patchGroups.Add(facade.WixFile.PatchGroup, patchGroup); | ||
721 | } | ||
722 | |||
723 | patchGroup.Add(facade); | ||
724 | } | ||
725 | else | ||
726 | { | ||
727 | facade.File.Sequence = ++lastSequence; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | if (null != mediaRow) | ||
732 | { | ||
733 | mediaRow.LastSequence = lastSequence; | ||
734 | mediaRow = null; | ||
735 | } | ||
736 | |||
737 | // sequence the patch-added files | ||
738 | foreach (List<FileFacade> patchGroup in patchGroups.Values) | ||
739 | { | ||
740 | foreach (FileFacade facade in patchGroup) | ||
741 | { | ||
742 | if (null == mediaRow) | ||
743 | { | ||
744 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
745 | } | ||
746 | else if (mediaRow.DiskId != facade.WixFile.DiskId) | ||
747 | { | ||
748 | mediaRow.LastSequence = lastSequence; | ||
749 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
750 | } | ||
751 | |||
752 | facade.File.Sequence = ++lastSequence; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | if (null != mediaRow) | ||
757 | { | ||
758 | mediaRow.LastSequence = lastSequence; | ||
759 | } | ||
760 | } | ||
761 | } | ||
762 | |||
763 | /// <summary> | ||
764 | /// Set the guids for components with generatable guids. | ||
765 | /// </summary> | ||
766 | /// <param name="output">Internal representation of the database to operate on.</param> | ||
767 | private void SetComponentGuids(Output output) | ||
768 | { | ||
769 | Table componentTable = output.Tables["Component"]; | ||
770 | if (null != componentTable) | ||
771 | { | ||
772 | Hashtable registryKeyRows = null; | ||
773 | Hashtable directories = null; | ||
774 | Hashtable componentIdGenSeeds = null; | ||
775 | Dictionary<string, List<FileRow>> fileRows = null; | ||
776 | |||
777 | // find components with generatable guids | ||
778 | foreach (ComponentRow componentRow in componentTable.Rows) | ||
779 | { | ||
780 | // component guid will be generated | ||
781 | if ("*" == componentRow.Guid) | ||
782 | { | ||
783 | if (null == componentRow.KeyPath || componentRow.IsOdbcDataSourceKeyPath) | ||
784 | { | ||
785 | Messaging.Instance.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(componentRow.SourceLineNumbers)); | ||
786 | } | ||
787 | else if (componentRow.IsRegistryKeyPath) | ||
788 | { | ||
789 | if (null == registryKeyRows) | ||
790 | { | ||
791 | Table registryTable = output.Tables["Registry"]; | ||
792 | |||
793 | registryKeyRows = new Hashtable(registryTable.Rows.Count); | ||
794 | |||
795 | foreach (Row registryRow in registryTable.Rows) | ||
796 | { | ||
797 | registryKeyRows.Add((string)registryRow[0], registryRow); | ||
798 | } | ||
799 | } | ||
800 | |||
801 | Row foundRow = registryKeyRows[componentRow.KeyPath] as Row; | ||
802 | |||
803 | string bitness = componentRow.Is64Bit ? "64" : String.Empty; | ||
804 | if (null != foundRow) | ||
805 | { | ||
806 | string regkey = String.Concat(bitness, foundRow[1], "\\", foundRow[2], "\\", foundRow[3]); | ||
807 | componentRow.Guid = Uuid.NewUuid(BindDatabaseCommand.WixComponentGuidNamespace, regkey.ToLowerInvariant()).ToString("B").ToUpperInvariant(); | ||
808 | } | ||
809 | } | ||
810 | else // must be a File KeyPath | ||
811 | { | ||
812 | // if the directory table hasn't been loaded into an indexed hash | ||
813 | // of directory ids to target names do that now. | ||
814 | if (null == directories) | ||
815 | { | ||
816 | Table directoryTable = output.Tables["Directory"]; | ||
817 | |||
818 | int numDirectoryTableRows = (null != directoryTable) ? directoryTable.Rows.Count : 0; | ||
819 | |||
820 | directories = new Hashtable(numDirectoryTableRows); | ||
821 | |||
822 | // get the target paths for all directories | ||
823 | if (null != directoryTable) | ||
824 | { | ||
825 | foreach (Row row in directoryTable.Rows) | ||
826 | { | ||
827 | // if the directory Id already exists, we will skip it here since | ||
828 | // checking for duplicate primary keys is done later when importing tables | ||
829 | // into database | ||
830 | if (directories.ContainsKey(row[0])) | ||
831 | { | ||
832 | continue; | ||
833 | } | ||
834 | |||
835 | string targetName = Common.GetName((string)row[2], false, true); | ||
836 | directories.Add(row[0], new ResolvedDirectory((string)row[1], targetName)); | ||
837 | } | ||
838 | } | ||
839 | } | ||
840 | |||
841 | // if the component id generation seeds have not been indexed | ||
842 | // from the WixDirectory table do that now. | ||
843 | if (null == componentIdGenSeeds) | ||
844 | { | ||
845 | Table wixDirectoryTable = output.Tables["WixDirectory"]; | ||
846 | |||
847 | int numWixDirectoryRows = (null != wixDirectoryTable) ? wixDirectoryTable.Rows.Count : 0; | ||
848 | |||
849 | componentIdGenSeeds = new Hashtable(numWixDirectoryRows); | ||
850 | |||
851 | // if there are any WixDirectory rows, build up the Component Guid | ||
852 | // generation seeds indexed by Directory/@Id. | ||
853 | if (null != wixDirectoryTable) | ||
854 | { | ||
855 | foreach (Row row in wixDirectoryTable.Rows) | ||
856 | { | ||
857 | componentIdGenSeeds.Add(row[0], (string)row[1]); | ||
858 | } | ||
859 | } | ||
860 | } | ||
861 | |||
862 | // if the file rows have not been indexed by File.Component yet | ||
863 | // then do that now | ||
864 | if (null == fileRows) | ||
865 | { | ||
866 | Table fileTable = output.Tables["File"]; | ||
867 | |||
868 | int numFileRows = (null != fileTable) ? fileTable.Rows.Count : 0; | ||
869 | |||
870 | fileRows = new Dictionary<string, List<FileRow>>(numFileRows); | ||
871 | |||
872 | if (null != fileTable) | ||
873 | { | ||
874 | foreach (FileRow file in fileTable.Rows) | ||
875 | { | ||
876 | List<FileRow> files; | ||
877 | if (!fileRows.TryGetValue(file.Component, out files)) | ||
878 | { | ||
879 | files = new List<FileRow>(); | ||
880 | fileRows.Add(file.Component, files); | ||
881 | } | ||
882 | |||
883 | files.Add(file); | ||
884 | } | ||
885 | } | ||
886 | } | ||
887 | |||
888 | // validate component meets all the conditions to have a generated guid | ||
889 | List<FileRow> currentComponentFiles = fileRows[componentRow.Component]; | ||
890 | int numFilesInComponent = currentComponentFiles.Count; | ||
891 | string path = null; | ||
892 | |||
893 | foreach (FileRow fileRow in currentComponentFiles) | ||
894 | { | ||
895 | if (fileRow.File == componentRow.KeyPath) | ||
896 | { | ||
897 | // calculate the key file's canonical target path | ||
898 | string directoryPath = Binder.GetDirectoryPath(directories, componentIdGenSeeds, componentRow.Directory, true); | ||
899 | string fileName = Common.GetName(fileRow.FileName, false, true).ToLower(CultureInfo.InvariantCulture); | ||
900 | path = Path.Combine(directoryPath, fileName); | ||
901 | |||
902 | // find paths that are not canonicalized | ||
903 | if (path.StartsWith(@"PersonalFolder\my pictures", StringComparison.Ordinal) || | ||
904 | path.StartsWith(@"ProgramFilesFolder\common files", StringComparison.Ordinal) || | ||
905 | path.StartsWith(@"ProgramMenuFolder\startup", StringComparison.Ordinal) || | ||
906 | path.StartsWith("TARGETDIR", StringComparison.Ordinal) || | ||
907 | path.StartsWith(@"StartMenuFolder\programs", StringComparison.Ordinal) || | ||
908 | path.StartsWith(@"WindowsFolder\fonts", StringComparison.Ordinal)) | ||
909 | { | ||
910 | Messaging.Instance.OnMessage(WixErrors.IllegalPathForGeneratedComponentGuid(componentRow.SourceLineNumbers, fileRow.Component, path)); | ||
911 | } | ||
912 | |||
913 | // if component has more than one file, the key path must be versioned | ||
914 | if (1 < numFilesInComponent && String.IsNullOrEmpty(fileRow.Version)) | ||
915 | { | ||
916 | Messaging.Instance.OnMessage(WixErrors.IllegalGeneratedGuidComponentUnversionedKeypath(componentRow.SourceLineNumbers)); | ||
917 | } | ||
918 | } | ||
919 | else | ||
920 | { | ||
921 | // not a key path, so it must be an unversioned file if component has more than one file | ||
922 | if (1 < numFilesInComponent && !String.IsNullOrEmpty(fileRow.Version)) | ||
923 | { | ||
924 | Messaging.Instance.OnMessage(WixErrors.IllegalGeneratedGuidComponentVersionedNonkeypath(componentRow.SourceLineNumbers)); | ||
925 | } | ||
926 | } | ||
927 | } | ||
928 | |||
929 | // if the rules were followed, reward with a generated guid | ||
930 | if (!Messaging.Instance.EncounteredError) | ||
931 | { | ||
932 | componentRow.Guid = Uuid.NewUuid(BindDatabaseCommand.WixComponentGuidNamespace, path).ToString("B").ToUpperInvariant(); | ||
933 | } | ||
934 | } | ||
935 | } | ||
936 | } | ||
937 | } | ||
938 | } | ||
939 | 647 | ||
648 | #if TODO_FIX_INSTANCE_TRANSFORM | ||
940 | /// <summary> | 649 | /// <summary> |
941 | /// Creates instance transform substorages in the output. | 650 | /// Creates instance transform substorages in the output. |
942 | /// </summary> | 651 | /// </summary> |
@@ -1171,6 +880,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1171 | } | 880 | } |
1172 | } | 881 | } |
1173 | } | 882 | } |
883 | #endif | ||
1174 | 884 | ||
1175 | /// <summary> | 885 | /// <summary> |
1176 | /// Validate that there are no duplicate GUIDs in the output. | 886 | /// Validate that there are no duplicate GUIDs in the output. |
@@ -1186,7 +896,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1186 | { | 896 | { |
1187 | Dictionary<string, bool> componentGuidConditions = new Dictionary<string, bool>(componentTable.Rows.Count); | 897 | Dictionary<string, bool> componentGuidConditions = new Dictionary<string, bool>(componentTable.Rows.Count); |
1188 | 898 | ||
1189 | foreach (ComponentRow row in componentTable.Rows) | 899 | foreach (Data.Rows.ComponentRow row in componentTable.Rows) |
1190 | { | 900 | { |
1191 | // we don't care about unmanaged components and if there's a * GUID remaining, | 901 | // we don't care about unmanaged components and if there's a * GUID remaining, |
1192 | // there's already an error that prevented it from being replaced with a real GUID. | 902 | // there's already an error that prevented it from being replaced with a real GUID. |
@@ -1221,7 +931,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1221 | /// <param name="output">Internal representation of the msi database to operate upon.</param> | 931 | /// <param name="output">Internal representation of the msi database to operate upon.</param> |
1222 | private void UpdateControlText(Output output) | 932 | private void UpdateControlText(Output output) |
1223 | { | 933 | { |
1224 | UpdateControlTextCommand command = new UpdateControlTextCommand(); | 934 | var command = new UpdateControlTextCommand(); |
1225 | command.BBControlTable = output.Tables["BBControl"]; | 935 | command.BBControlTable = output.Tables["BBControl"]; |
1226 | command.WixBBControlTable = output.Tables["WixBBControl"]; | 936 | command.WixBBControlTable = output.Tables["WixBBControl"]; |
1227 | command.ControlTable = output.Tables["Control"]; | 937 | command.ControlTable = output.Tables["Control"]; |
@@ -1229,7 +939,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1229 | command.Execute(); | 939 | command.Execute(); |
1230 | } | 940 | } |
1231 | 941 | ||
1232 | private string ResolveMedia(MediaRow mediaRow, string mediaLayoutDirectory, string layoutDirectory) | 942 | private string ResolveMedia(MediaTuple mediaRow, string mediaLayoutDirectory, string layoutDirectory) |
1233 | { | 943 | { |
1234 | string layout = null; | 944 | string layout = null; |
1235 | 945 | ||
@@ -1282,7 +992,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1282 | command.TempFilesLocation = this.IntermediateFolder; | 992 | command.TempFilesLocation = this.IntermediateFolder; |
1283 | command.Codepage = this.Codepage; | 993 | command.Codepage = this.Codepage; |
1284 | command.Execute(); | 994 | command.Execute(); |
1285 | #endif | ||
1286 | } | 995 | } |
1287 | } | 996 | } |
1288 | } | 997 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs index 5471792d..c9286a38 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs | |||
@@ -1,20 +1,24 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Globalization; | 6 | using System.Globalization; |
7 | using System.Linq; | ||
7 | using WixToolset.Data; | 8 | using WixToolset.Data; |
9 | using WixToolset.Data.Tuples; | ||
8 | 10 | ||
9 | /// <summary> | 11 | /// <summary> |
10 | /// Binds the summary information table of a database. | 12 | /// Binds the summary information table of a database. |
11 | /// </summary> | 13 | /// </summary> |
12 | internal class BindSummaryInfoCommand | 14 | internal class BindSummaryInfoCommand |
13 | { | 15 | { |
14 | /// <summary> | 16 | public BindSummaryInfoCommand(IntermediateSection section) |
15 | /// The output to bind. | 17 | { |
16 | /// </summary> | 18 | this.Section = section; |
17 | public Output Output { private get; set; } | 19 | } |
20 | |||
21 | private IntermediateSection Section { get; } | ||
18 | 22 | ||
19 | /// <summary> | 23 | /// <summary> |
20 | /// Returns a flag indicating if files are compressed by default. | 24 | /// Returns a flag indicating if files are compressed by default. |
@@ -40,95 +44,97 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
40 | this.InstallerVersion = 0; | 44 | this.InstallerVersion = 0; |
41 | this.ModularizationGuid = null; | 45 | this.ModularizationGuid = null; |
42 | 46 | ||
43 | Table summaryInformationTable = this.Output.Tables["_SummaryInformation"]; | 47 | bool foundCreateDataTime = false; |
48 | bool foundLastSaveDataTime = false; | ||
49 | bool foundCreatingApplication = false; | ||
50 | string now = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture); | ||
44 | 51 | ||
45 | if (null != summaryInformationTable) | 52 | foreach (var summaryInformationRow in this.Section.Tuples.OfType<_SummaryInformationTuple>()) |
46 | { | 53 | { |
47 | bool foundCreateDataTime = false; | 54 | switch (summaryInformationRow.PropertyId) |
48 | bool foundLastSaveDataTime = false; | ||
49 | bool foundCreatingApplication = false; | ||
50 | string now = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture); | ||
51 | |||
52 | foreach (Row summaryInformationRow in summaryInformationTable.Rows) | ||
53 | { | 55 | { |
54 | switch (summaryInformationRow.FieldAsInteger(0)) | 56 | case 1: // PID_CODEPAGE |
55 | { | ||
56 | case 1: // PID_CODEPAGE | ||
57 | // make sure the code page is an int and not a web name or null | 57 | // make sure the code page is an int and not a web name or null |
58 | string codepage = summaryInformationRow.FieldAsString(1); | 58 | var codepage = summaryInformationRow.Value; |
59 | |||
60 | if (null == codepage) | ||
61 | { | ||
62 | codepage = "0"; | ||
63 | } | ||
64 | else | ||
65 | { | ||
66 | summaryInformationRow[1] = Common.GetValidCodePage(codepage, false, false, summaryInformationRow.SourceLineNumbers).ToString(CultureInfo.InvariantCulture); | ||
67 | } | ||
68 | break; | ||
69 | case 9: // PID_REVNUMBER | ||
70 | string packageCode = (string)summaryInformationRow[1]; | ||
71 | |||
72 | if (OutputType.Module == this.Output.Type) | ||
73 | { | ||
74 | this.ModularizationGuid = packageCode.Substring(1, 36).Replace('-', '_'); | ||
75 | } | ||
76 | else if ("*" == packageCode) | ||
77 | { | ||
78 | // set the revision number (package/patch code) if it should be automatically generated | ||
79 | summaryInformationRow[1] = Common.GenerateGuid(); | ||
80 | } | ||
81 | break; | ||
82 | case 12: // PID_CREATE_DTM | ||
83 | foundCreateDataTime = true; | ||
84 | break; | ||
85 | case 13: // PID_LASTSAVE_DTM | ||
86 | foundLastSaveDataTime = true; | ||
87 | break; | ||
88 | case 14: | ||
89 | this.InstallerVersion = summaryInformationRow.FieldAsInteger(1); | ||
90 | break; | ||
91 | case 15: // PID_WORDCOUNT | ||
92 | if (OutputType.Patch == this.Output.Type) | ||
93 | { | ||
94 | this.LongNames = true; | ||
95 | this.Compressed = true; | ||
96 | } | ||
97 | else | ||
98 | { | ||
99 | this.LongNames = (0 == (summaryInformationRow.FieldAsInteger(1) & 1)); | ||
100 | this.Compressed = (2 == (summaryInformationRow.FieldAsInteger(1) & 2)); | ||
101 | } | ||
102 | break; | ||
103 | case 18: // PID_APPNAME | ||
104 | foundCreatingApplication = true; | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | 59 | ||
109 | // add a summary information row for the create time/date property if its not already set | 60 | if (String.IsNullOrEmpty(codepage)) |
110 | if (!foundCreateDataTime) | 61 | { |
111 | { | 62 | codepage = "0"; |
112 | Row createTimeDateRow = summaryInformationTable.CreateRow(null); | 63 | } |
113 | createTimeDateRow[0] = 12; | 64 | else |
114 | createTimeDateRow[1] = now; | 65 | { |
115 | } | 66 | summaryInformationRow.Value = Common.GetValidCodePage(codepage, false, false, summaryInformationRow.SourceLineNumbers).ToString(CultureInfo.InvariantCulture); |
67 | } | ||
68 | break; | ||
69 | case 9: // PID_REVNUMBER | ||
70 | var packageCode = summaryInformationRow.Value; | ||
116 | 71 | ||
117 | // add a summary information row for the last save time/date property if its not already set | 72 | if (SectionType.Module == this.Section.Type) |
118 | if (!foundLastSaveDataTime) | 73 | { |
119 | { | 74 | this.ModularizationGuid = packageCode.Substring(1, 36).Replace('-', '_'); |
120 | Row lastSaveTimeDateRow = summaryInformationTable.CreateRow(null); | 75 | } |
121 | lastSaveTimeDateRow[0] = 13; | 76 | else if ("*" == packageCode) |
122 | lastSaveTimeDateRow[1] = now; | 77 | { |
78 | // set the revision number (package/patch code) if it should be automatically generated | ||
79 | summaryInformationRow.Value = Common.GenerateGuid(); | ||
80 | } | ||
81 | break; | ||
82 | case 12: // PID_CREATE_DTM | ||
83 | foundCreateDataTime = true; | ||
84 | break; | ||
85 | case 13: // PID_LASTSAVE_DTM | ||
86 | foundLastSaveDataTime = true; | ||
87 | break; | ||
88 | case 14: | ||
89 | this.InstallerVersion = summaryInformationRow[_SummaryInformationTupleFields.Value].AsNumber(); | ||
90 | break; | ||
91 | case 15: // PID_WORDCOUNT | ||
92 | if (SectionType.Patch == this.Section.Type) | ||
93 | { | ||
94 | this.LongNames = true; | ||
95 | this.Compressed = true; | ||
96 | } | ||
97 | else | ||
98 | { | ||
99 | var attributes = summaryInformationRow[_SummaryInformationTupleFields.Value].AsNumber(); | ||
100 | this.LongNames = (0 == (attributes & 1)); | ||
101 | this.Compressed = (2 == (attributes & 2)); | ||
102 | } | ||
103 | break; | ||
104 | case 18: // PID_APPNAME | ||
105 | foundCreatingApplication = true; | ||
106 | break; | ||
123 | } | 107 | } |
108 | } | ||
124 | 109 | ||
125 | // add a summary information row for the creating application property if its not already set | 110 | // add a summary information row for the create time/date property if its not already set |
126 | if (!foundCreatingApplication) | 111 | if (!foundCreateDataTime) |
127 | { | 112 | { |
128 | Row creatingApplicationRow = summaryInformationTable.CreateRow(null); | 113 | var createTimeDateRow = new _SummaryInformationTuple(null, new Identifier(12, AccessModifier.Private)); |
129 | creatingApplicationRow[0] = 18; | 114 | createTimeDateRow.PropertyId = 12; |
130 | creatingApplicationRow[1] = String.Format(CultureInfo.InvariantCulture, AppCommon.GetCreatingApplicationString()); | 115 | createTimeDateRow.Value = now; |
131 | } | 116 | |
117 | this.Section.Tuples.Add(createTimeDateRow); | ||
118 | } | ||
119 | |||
120 | // add a summary information row for the last save time/date property if its not already set | ||
121 | if (!foundLastSaveDataTime) | ||
122 | { | ||
123 | var lastSaveTimeDateRow = new _SummaryInformationTuple(null, new Identifier(13, AccessModifier.Private)); | ||
124 | lastSaveTimeDateRow.PropertyId = 13; | ||
125 | lastSaveTimeDateRow.Value = now; | ||
126 | |||
127 | this.Section.Tuples.Add(lastSaveTimeDateRow); | ||
128 | } | ||
129 | |||
130 | // add a summary information row for the creating application property if its not already set | ||
131 | if (!foundCreatingApplication) | ||
132 | { | ||
133 | var creatingApplicationRow = new _SummaryInformationTuple(null, new Identifier(18, AccessModifier.Private)); | ||
134 | creatingApplicationRow.PropertyId = 18; | ||
135 | creatingApplicationRow.Value = String.Format(CultureInfo.InvariantCulture, AppCommon.GetCreatingApplicationString()); | ||
136 | |||
137 | this.Section.Tuples.Add(creatingApplicationRow); | ||
132 | } | 138 | } |
133 | } | 139 | } |
134 | } | 140 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs index 425d1f9c..b4027834 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs index b2cc76fc..c25a497e 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs index dcafcd36..405b840b 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs | |||
@@ -1,11 +1,10 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
6 | using WixToolset.Core.Bind; | 6 | using WixToolset.Core.Bind; |
7 | using WixToolset.Data; | 7 | using WixToolset.Data; |
8 | using WixToolset.Data.Rows; | ||
9 | 8 | ||
10 | /// <summary> | 9 | /// <summary> |
11 | /// A cabinet builder work item. | 10 | /// A cabinet builder work item. |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs new file mode 100644 index 00000000..0c0aea1f --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs | |||
@@ -0,0 +1,174 @@ | |||
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 | namespace WixToolset.Core.WindowsInstaller.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.IO; | ||
8 | using System.Linq; | ||
9 | using WixToolset.Bind; | ||
10 | using WixToolset.Core.Native; | ||
11 | using WixToolset.Data; | ||
12 | using WixToolset.Data.Tuples; | ||
13 | |||
14 | /// <summary> | ||
15 | /// Set the guids for components with generatable guids. | ||
16 | /// </summary> | ||
17 | internal class CalculateComponentGuids | ||
18 | { | ||
19 | public CalculateComponentGuids(IntermediateSection section) | ||
20 | { | ||
21 | this.Section = section; | ||
22 | } | ||
23 | |||
24 | private IntermediateSection Section { get; } | ||
25 | |||
26 | public void Execute() | ||
27 | { | ||
28 | Dictionary<string, RegistryTuple> registryKeyRows = null; | ||
29 | Dictionary<string, ResolvedDirectory> targetPathsByDirectoryId = null; | ||
30 | Dictionary<string, string> componentIdGenSeeds = null; | ||
31 | Dictionary<string, List<FileTuple>> filesByComponentId = null; | ||
32 | |||
33 | // Find components with generatable guids. | ||
34 | foreach (var componentRow in this.Section.Tuples.OfType<ComponentTuple>()) | ||
35 | { | ||
36 | // Skip components that do not specify generate guid. | ||
37 | if (componentRow.ComponentId != "*") | ||
38 | { | ||
39 | continue; | ||
40 | } | ||
41 | |||
42 | var odbcDataSourceKeyPath = (componentRow.Attributes & MsiInterop.MsidbComponentAttributesODBCDataSource) != 0; | ||
43 | |||
44 | if (String.IsNullOrEmpty(componentRow.KeyPath) || odbcDataSourceKeyPath) | ||
45 | { | ||
46 | Messaging.Instance.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(componentRow.SourceLineNumbers)); | ||
47 | continue; | ||
48 | } | ||
49 | |||
50 | var registryKeyPath = (componentRow.Attributes & MsiInterop.MsidbComponentAttributesRegistryKeyPath) != 0; | ||
51 | |||
52 | if (registryKeyPath) | ||
53 | { | ||
54 | if (registryKeyRows is null) | ||
55 | { | ||
56 | registryKeyRows = this.Section.Tuples.OfType<RegistryTuple>().ToDictionary(t => t.Registry); | ||
57 | } | ||
58 | |||
59 | if (registryKeyRows.TryGetValue(componentRow.KeyPath, out var foundRow)) | ||
60 | { | ||
61 | var is64Bit = (componentRow.Attributes & MsiInterop.MsidbComponentAttributes64bit) != 0; | ||
62 | var bitness = is64Bit ? "64" : String.Empty; | ||
63 | var regkey = String.Concat(bitness, foundRow[1], "\\", foundRow[2], "\\", foundRow[3]); | ||
64 | componentRow.ComponentId = Uuid.NewUuid(BindDatabaseCommand.WixComponentGuidNamespace, regkey.ToLowerInvariant()).ToString("B").ToUpperInvariant(); | ||
65 | } | ||
66 | } | ||
67 | else // must be a File KeyPath. | ||
68 | { | ||
69 | // If the directory table hasn't been loaded into an indexed hash | ||
70 | // of directory ids to target names do that now. | ||
71 | if (targetPathsByDirectoryId is null) | ||
72 | { | ||
73 | var directories = this.Section.Tuples.OfType<DirectoryTuple>().ToList(); | ||
74 | |||
75 | targetPathsByDirectoryId = new Dictionary<string, ResolvedDirectory>(directories.Count); | ||
76 | |||
77 | // Get the target paths for all directories. | ||
78 | foreach (var row in directories) | ||
79 | { | ||
80 | // If the directory Id already exists, we will skip it here since | ||
81 | // checking for duplicate primary keys is done later when importing tables | ||
82 | // into database | ||
83 | if (targetPathsByDirectoryId.ContainsKey(row.Directory)) | ||
84 | { | ||
85 | continue; | ||
86 | } | ||
87 | |||
88 | var targetName = Common.GetName(row.DefaultDir, false, true); | ||
89 | targetPathsByDirectoryId.Add(row.Directory, new ResolvedDirectory(row.Directory_Parent, targetName)); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // If the component id generation seeds have not been indexed | ||
94 | // from the WixDirectory table do that now. | ||
95 | if (componentIdGenSeeds is null) | ||
96 | { | ||
97 | // If there are any WixDirectory rows, build up the Component Guid | ||
98 | // generation seeds indexed by Directory/@Id. | ||
99 | componentIdGenSeeds = this.Section.Tuples.OfType<WixDirectoryTuple>() | ||
100 | .Where(t => !String.IsNullOrEmpty(t.ComponentGuidGenerationSeed)) | ||
101 | .ToDictionary(t => t.Directory_, t => t.ComponentGuidGenerationSeed); | ||
102 | } | ||
103 | |||
104 | // if the file rows have not been indexed by File.Component yet | ||
105 | // then do that now | ||
106 | if (filesByComponentId is null) | ||
107 | { | ||
108 | var files = this.Section.Tuples.OfType<FileTuple>().ToList(); | ||
109 | |||
110 | filesByComponentId = new Dictionary<string, List<FileTuple>>(files.Count); | ||
111 | |||
112 | foreach (var file in files) | ||
113 | { | ||
114 | if (!filesByComponentId.TryGetValue(file.Component_, out var componentFiles)) | ||
115 | { | ||
116 | componentFiles = new List<FileTuple>(); | ||
117 | filesByComponentId.Add(file.Component_, componentFiles); | ||
118 | } | ||
119 | |||
120 | componentFiles.Add(file); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | // validate component meets all the conditions to have a generated guid | ||
125 | var currentComponentFiles = filesByComponentId[componentRow.Component]; | ||
126 | var numFilesInComponent = currentComponentFiles.Count; | ||
127 | string path = null; | ||
128 | |||
129 | foreach (var fileRow in currentComponentFiles) | ||
130 | { | ||
131 | if (fileRow.File == componentRow.KeyPath) | ||
132 | { | ||
133 | // calculate the key file's canonical target path | ||
134 | string directoryPath = Binder.GetDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentRow.Directory_, true); | ||
135 | string fileName = Common.GetName(fileRow.LongFileName, false, true).ToLowerInvariant(); | ||
136 | path = Path.Combine(directoryPath, fileName); | ||
137 | |||
138 | // find paths that are not canonicalized | ||
139 | if (path.StartsWith(@"PersonalFolder\my pictures", StringComparison.Ordinal) || | ||
140 | path.StartsWith(@"ProgramFilesFolder\common files", StringComparison.Ordinal) || | ||
141 | path.StartsWith(@"ProgramMenuFolder\startup", StringComparison.Ordinal) || | ||
142 | path.StartsWith("TARGETDIR", StringComparison.Ordinal) || | ||
143 | path.StartsWith(@"StartMenuFolder\programs", StringComparison.Ordinal) || | ||
144 | path.StartsWith(@"WindowsFolder\fonts", StringComparison.Ordinal)) | ||
145 | { | ||
146 | Messaging.Instance.OnMessage(WixErrors.IllegalPathForGeneratedComponentGuid(componentRow.SourceLineNumbers, fileRow.Component_, path)); | ||
147 | } | ||
148 | |||
149 | // if component has more than one file, the key path must be versioned | ||
150 | if (1 < numFilesInComponent && String.IsNullOrEmpty(fileRow.Version)) | ||
151 | { | ||
152 | Messaging.Instance.OnMessage(WixErrors.IllegalGeneratedGuidComponentUnversionedKeypath(componentRow.SourceLineNumbers)); | ||
153 | } | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | // not a key path, so it must be an unversioned file if component has more than one file | ||
158 | if (1 < numFilesInComponent && !String.IsNullOrEmpty(fileRow.Version)) | ||
159 | { | ||
160 | Messaging.Instance.OnMessage(WixErrors.IllegalGeneratedGuidComponentVersionedNonkeypath(componentRow.SourceLineNumbers)); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // if the rules were followed, reward with a generated guid | ||
166 | if (!Messaging.Instance.EncounteredError) | ||
167 | { | ||
168 | componentRow.ComponentId = Uuid.NewUuid(BindDatabaseCommand.WixComponentGuidNamespace, path).ToString("B").ToUpperInvariant(); | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs index d4d3799f..9a8e2bba 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs index 6388a352..0dcddb99 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CopyTransformDataCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -10,6 +10,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
10 | using WixToolset.Extensibility; | 10 | using WixToolset.Extensibility; |
11 | using WixToolset.Core.Native; | 11 | using WixToolset.Core.Native; |
12 | using WixToolset.Core.Bind; | 12 | using WixToolset.Core.Bind; |
13 | using WixToolset.Data.Tuples; | ||
13 | 14 | ||
14 | internal class CopyTransformDataCommand | 15 | internal class CopyTransformDataCommand |
15 | { | 16 | { |
@@ -29,7 +30,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
29 | 30 | ||
30 | List<FileFacade> allFileRows = this.CopyOutFileRows ? new List<FileFacade>() : null; | 31 | List<FileFacade> allFileRows = this.CopyOutFileRows ? new List<FileFacade>() : null; |
31 | 32 | ||
32 | #if false // TODO: Fix this patching related code to work correctly with FileFacades. | 33 | #if REVISIT_FOR_PATCHING // TODO: Fix this patching related code to work correctly with FileFacades. |
33 | bool copyToPatch = (allFileRows != null); | 34 | bool copyToPatch = (allFileRows != null); |
34 | bool copyFromPatch = !copyToPatch; | 35 | bool copyFromPatch = !copyToPatch; |
35 | 36 | ||
@@ -454,7 +455,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
454 | } | 455 | } |
455 | 456 | ||
456 | Row patchAction = iesTable.CreateRow(null); | 457 | Row patchAction = iesTable.CreateRow(null); |
457 | WixActionRow wixPatchAction = WindowsInstallerStandard.GetStandardActions()[table, "PatchFiles"]; | 458 | WixActionRow wixPatchAction = WindowsInstallerStandardInternal.GetStandardActionRows()[table, "PatchFiles"]; |
458 | int sequence = wixPatchAction.Sequence; | 459 | int sequence = wixPatchAction.Sequence; |
459 | // Test for default sequence value's appropriateness | 460 | // Test for default sequence value's appropriateness |
460 | if (seqInstallFiles >= sequence || (0 != seqDuplicateFiles && seqDuplicateFiles <= sequence)) | 461 | if (seqInstallFiles >= sequence || (0 != seqDuplicateFiles && seqDuplicateFiles <= sequence)) |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs index 02015744..b5a436c5 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -10,10 +10,10 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
10 | using System.Runtime.InteropServices; | 10 | using System.Runtime.InteropServices; |
11 | using System.Threading; | 11 | using System.Threading; |
12 | using WixToolset.Core.Bind; | 12 | using WixToolset.Core.Bind; |
13 | using WixToolset.Core.WindowsInstaller.Bind; | ||
14 | using WixToolset.Data; | 13 | using WixToolset.Data; |
15 | using WixToolset.Data.Bind; | 14 | using WixToolset.Data.Bind; |
16 | using WixToolset.Data.Rows; | 15 | using WixToolset.Data.Rows; |
16 | using WixToolset.Data.Tuples; | ||
17 | using WixToolset.Extensibility; | 17 | using WixToolset.Extensibility; |
18 | 18 | ||
19 | /// <summary> | 19 | /// <summary> |
@@ -60,9 +60,9 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
60 | 60 | ||
61 | public bool Compressed { private get; set; } | 61 | public bool Compressed { private get; set; } |
62 | 62 | ||
63 | public Dictionary<MediaRow, IEnumerable<FileFacade>> FileRowsByCabinet { private get; set; } | 63 | public Dictionary<MediaTuple, IEnumerable<FileFacade>> FileRowsByCabinet { private get; set; } |
64 | 64 | ||
65 | public Func<MediaRow, string, string, string> ResolveMedia { private get; set; } | 65 | public Func<MediaTuple, string, string, string> ResolveMedia { private get; set; } |
66 | 66 | ||
67 | public TableDefinitionCollection TableDefinitions { private get; set; } | 67 | public TableDefinitionCollection TableDefinitions { private get; set; } |
68 | 68 | ||
@@ -77,7 +77,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
77 | /// <returns>The uncompressed file rows.</returns> | 77 | /// <returns>The uncompressed file rows.</returns> |
78 | public void Execute() | 78 | public void Execute() |
79 | { | 79 | { |
80 | RowDictionary<WixMediaRow> wixMediaRows = new RowDictionary<WixMediaRow>(this.WixMediaTable); | 80 | var wixMediaRows = new RowDictionary<WixMediaRow>(this.WixMediaTable); |
81 | 81 | ||
82 | this.lastCabinetAddedToMediaTable = new Dictionary<string, string>(); | 82 | this.lastCabinetAddedToMediaTable = new Dictionary<string, string>(); |
83 | 83 | ||
@@ -87,22 +87,19 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
87 | CabinetBuilder cabinetBuilder = new CabinetBuilder(this.CabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack)); | 87 | CabinetBuilder cabinetBuilder = new CabinetBuilder(this.CabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack)); |
88 | 88 | ||
89 | // Supply Compile MediaTemplate Attributes to Cabinet Builder | 89 | // Supply Compile MediaTemplate Attributes to Cabinet Builder |
90 | int MaximumCabinetSizeForLargeFileSplitting; | 90 | this.GetMediaTemplateAttributes(out var MaximumCabinetSizeForLargeFileSplitting, out var MaximumUncompressedMediaSize); |
91 | int MaximumUncompressedMediaSize; | ||
92 | this.GetMediaTemplateAttributes(out MaximumCabinetSizeForLargeFileSplitting, out MaximumUncompressedMediaSize); | ||
93 | cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = MaximumCabinetSizeForLargeFileSplitting; | 91 | cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = MaximumCabinetSizeForLargeFileSplitting; |
94 | cabinetBuilder.MaximumUncompressedMediaSize = MaximumUncompressedMediaSize; | 92 | cabinetBuilder.MaximumUncompressedMediaSize = MaximumUncompressedMediaSize; |
95 | 93 | ||
96 | foreach (var entry in this.FileRowsByCabinet) | 94 | foreach (var entry in this.FileRowsByCabinet) |
97 | { | 95 | { |
98 | MediaRow mediaRow = entry.Key; | 96 | var mediaRow = entry.Key; |
99 | IEnumerable<FileFacade> files = entry.Value; | 97 | IEnumerable<FileFacade> files = entry.Value; |
100 | CompressionLevel compressionLevel = this.DefaultCompressionLevel; | 98 | CompressionLevel compressionLevel = this.DefaultCompressionLevel; |
101 | 99 | ||
102 | WixMediaRow wixMediaRow = null; | ||
103 | string mediaLayoutFolder = null; | 100 | string mediaLayoutFolder = null; |
104 | 101 | ||
105 | if (wixMediaRows.TryGetValue(mediaRow.GetKey(), out wixMediaRow)) | 102 | if (wixMediaRows.TryGetValue(mediaRow.Id.Id, out var wixMediaRow)) |
106 | { | 103 | { |
107 | mediaLayoutFolder = wixMediaRow.Layout; | 104 | mediaLayoutFolder = wixMediaRow.Layout; |
108 | 105 | ||
@@ -185,7 +182,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
185 | /// <param name="fileFacades">Collection of files in this cabinet.</param> | 182 | /// <param name="fileFacades">Collection of files in this cabinet.</param> |
186 | /// <param name="fileTransfers">Array of files to be transfered.</param> | 183 | /// <param name="fileTransfers">Array of files to be transfered.</param> |
187 | /// <returns>created CabinetWorkItem object</returns> | 184 | /// <returns>created CabinetWorkItem object</returns> |
188 | private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaRow mediaRow, CompressionLevel compressionLevel, IEnumerable<FileFacade> fileFacades, List<FileTransfer> fileTransfers) | 185 | private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaTuple mediaRow, CompressionLevel compressionLevel, IEnumerable<FileFacade> fileFacades, List<FileTransfer> fileTransfers) |
189 | { | 186 | { |
190 | CabinetWorkItem cabinetWorkItem = null; | 187 | CabinetWorkItem cabinetWorkItem = null; |
191 | string tempCabinetFileX = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet); | 188 | string tempCabinetFileX = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet); |
@@ -254,8 +251,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
254 | else | 251 | else |
255 | { | 252 | { |
256 | string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet); | 253 | string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet); |
257 | FileTransfer transfer; | 254 | if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out var transfer)) |
258 | if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out transfer)) | ||
259 | { | 255 | { |
260 | transfer.Built = true; | 256 | transfer.Built = true; |
261 | fileTransfers.Add(transfer); | 257 | fileTransfers.Add(transfer); |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs index 42a69310..7c7b07cc 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -9,49 +9,40 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
9 | using WixToolset.Core.Bind; | 9 | using WixToolset.Core.Bind; |
10 | using WixToolset.Data; | 10 | using WixToolset.Data; |
11 | using WixToolset.Data.Rows; | 11 | using WixToolset.Data.Rows; |
12 | using WixToolset.Data.Tuples; | ||
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 IEnumerable<FileFacade> FileFacades { private get; set; } | 19 | public CreateDeltaPatchesCommand(List<FileFacade> fileFacades, string intermediateFolder, WixPatchIdTuple wixPatchId) |
20 | { | ||
21 | this.FileFacades = fileFacades; | ||
22 | this.IntermediateFolder = intermediateFolder; | ||
23 | this.WixPatchId = wixPatchId; | ||
24 | } | ||
19 | 25 | ||
20 | public Table WixPatchIdTable { private get; set; } | 26 | private IEnumerable<FileFacade> FileFacades { get; } |
21 | 27 | ||
22 | public string TempFilesLocation { private get; set; } | 28 | private WixPatchIdTuple WixPatchId { get; } |
29 | |||
30 | private string IntermediateFolder { get; } | ||
23 | 31 | ||
24 | public void Execute() | 32 | public void Execute() |
25 | { | 33 | { |
26 | #if REVISIT_FOR_PATCHING | 34 | var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false; |
27 | bool optimizePatchSizeForLargeFiles = false; | 35 | var apiPatchingSymbolFlags = (PatchSymbolFlagsType)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0); |
28 | PatchSymbolFlagsType apiPatchingSymbolFlags = 0; | ||
29 | |||
30 | if (null != this.WixPatchIdTable) | ||
31 | { | ||
32 | Row row = this.WixPatchIdTable.Rows[0]; | ||
33 | if (null != row) | ||
34 | { | ||
35 | if (null != row[2]) | ||
36 | { | ||
37 | optimizePatchSizeForLargeFiles = (1 == Convert.ToUInt32(row[2], CultureInfo.InvariantCulture)); | ||
38 | } | ||
39 | |||
40 | if (null != row[3]) | ||
41 | { | ||
42 | apiPatchingSymbolFlags = (PatchSymbolFlagsType)Convert.ToUInt32(row[3], CultureInfo.InvariantCulture); | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | 36 | ||
37 | #if REVISIT_FOR_PATCHING | ||
47 | foreach (FileFacade facade in this.FileFacades) | 38 | foreach (FileFacade facade in this.FileFacades) |
48 | { | 39 | { |
49 | if (RowOperation.Modify == facade.File.Operation && | 40 | if (RowOperation.Modify == facade.File.Operation && |
50 | 0 != (facade.WixFile.PatchAttributes & PatchAttributeType.IncludeWholeFile)) | 41 | 0 != (facade.WixFile.PatchAttributes & PatchAttributeType.IncludeWholeFile)) |
51 | { | 42 | { |
52 | string deltaBase = String.Concat("delta_", facade.File.File); | 43 | string deltaBase = String.Concat("delta_", facade.File.File); |
53 | string deltaFile = Path.Combine(this.TempFilesLocation, String.Concat(deltaBase, ".dpf")); | 44 | string deltaFile = Path.Combine(this.IntermediateFolder, String.Concat(deltaBase, ".dpf")); |
54 | string headerFile = Path.Combine(this.TempFilesLocation, String.Concat(deltaBase, ".phd")); | 45 | string headerFile = Path.Combine(this.IntermediateFolder, String.Concat(deltaBase, ".phd")); |
55 | 46 | ||
56 | bool retainRangeWarning = false; | 47 | bool retainRangeWarning = false; |
57 | 48 | ||
@@ -84,6 +75,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
84 | } | 75 | } |
85 | } | 76 | } |
86 | #endif | 77 | #endif |
78 | |||
87 | throw new NotImplementedException(); | 79 | throw new NotImplementedException(); |
88 | } | 80 | } |
89 | } | 81 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs new file mode 100644 index 00000000..85b3b25a --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs | |||
@@ -0,0 +1,230 @@ | |||
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 | namespace WixToolset.Core.WindowsInstaller.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Linq; | ||
7 | using WixToolset.Core.Native; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Data.Rows; | ||
10 | using WixToolset.Data.Tuples; | ||
11 | |||
12 | internal class CreateOutputFromIRCommand | ||
13 | { | ||
14 | public CreateOutputFromIRCommand(IntermediateSection section, TableDefinitionCollection tableDefinitions) | ||
15 | { | ||
16 | this.Section = section; | ||
17 | this.TableDefinitions = tableDefinitions; | ||
18 | } | ||
19 | |||
20 | private TableDefinitionCollection TableDefinitions { get; } | ||
21 | |||
22 | private IntermediateSection Section { get; } | ||
23 | |||
24 | public Output Output { get; private set; } | ||
25 | |||
26 | public void Execute() | ||
27 | { | ||
28 | var output = new Output(this.Section.Tuples.First().SourceLineNumbers); | ||
29 | output.Codepage = this.Section.Codepage; | ||
30 | output.Type = SectionTypeToOutputType(this.Section.Type); | ||
31 | |||
32 | this.AddSectionToOutput(this.Section, output); | ||
33 | |||
34 | this.Output = output; | ||
35 | } | ||
36 | |||
37 | private void AddSectionToOutput(IntermediateSection section, Output output) | ||
38 | { | ||
39 | foreach (var tuple in section.Tuples) | ||
40 | { | ||
41 | switch (tuple.Definition.Type) | ||
42 | { | ||
43 | case TupleDefinitionType.File: | ||
44 | this.AddFileTuple((FileTuple)tuple, output); | ||
45 | break; | ||
46 | |||
47 | case TupleDefinitionType.WixAction: | ||
48 | this.AddWixActionTuple((WixActionTuple)tuple, output); | ||
49 | break; | ||
50 | |||
51 | default: | ||
52 | this.AddTupleDefaultly(tuple, output); | ||
53 | break; | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | |||
58 | private void AddFileTuple(FileTuple tuple, Output output) | ||
59 | { | ||
60 | var table = output.EnsureTable(this.TableDefinitions["File"]); | ||
61 | var row = (FileRow)table.CreateRow(tuple.SourceLineNumbers); | ||
62 | row.File = tuple.File; | ||
63 | row.Component = tuple.Component_; | ||
64 | row.FileName = GetMsiFilenameValue(tuple.ShortFileName, tuple.LongFileName); | ||
65 | row.FileSize = tuple.FileSize; | ||
66 | row.Version = tuple.Version; | ||
67 | row.Language = tuple.Language; | ||
68 | |||
69 | var attributes = tuple.Checksum ? MsiInterop.MsidbFileAttributesChecksum : 0; | ||
70 | attributes |= (tuple.Compressed.HasValue && tuple.Compressed.Value) ? MsiInterop.MsidbFileAttributesCompressed : 0; | ||
71 | attributes |= (tuple.Compressed.HasValue && !tuple.Compressed.Value) ? MsiInterop.MsidbFileAttributesNoncompressed : 0; | ||
72 | attributes |= tuple.Hidden ? MsiInterop.MsidbFileAttributesHidden : 0; | ||
73 | attributes |= tuple.ReadOnly ? MsiInterop.MsidbFileAttributesReadOnly : 0; | ||
74 | attributes |= tuple.System ? MsiInterop.MsidbFileAttributesSystem : 0; | ||
75 | attributes |= tuple.Vital ? MsiInterop.MsidbFileAttributesVital : 0; | ||
76 | row.Attributes = attributes; | ||
77 | } | ||
78 | |||
79 | private void AddWixActionTuple(WixActionTuple actionRow, Output output) | ||
80 | { | ||
81 | // Get the table definition for the action (and ensure the proper table exists for a module). | ||
82 | TableDefinition sequenceTableDefinition = null; | ||
83 | switch (actionRow.SequenceTable) | ||
84 | { | ||
85 | case SequenceTable.AdminExecuteSequence: | ||
86 | if (OutputType.Module == output.Type) | ||
87 | { | ||
88 | output.EnsureTable(this.TableDefinitions["AdminExecuteSequence"]); | ||
89 | sequenceTableDefinition = this.TableDefinitions["ModuleAdminExecuteSequence"]; | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | sequenceTableDefinition = this.TableDefinitions["AdminExecuteSequence"]; | ||
94 | } | ||
95 | break; | ||
96 | case SequenceTable.AdminUISequence: | ||
97 | if (OutputType.Module == output.Type) | ||
98 | { | ||
99 | output.EnsureTable(this.TableDefinitions["AdminUISequence"]); | ||
100 | sequenceTableDefinition = this.TableDefinitions["ModuleAdminUISequence"]; | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | sequenceTableDefinition = this.TableDefinitions["AdminUISequence"]; | ||
105 | } | ||
106 | break; | ||
107 | case SequenceTable.AdvtExecuteSequence: | ||
108 | if (OutputType.Module == output.Type) | ||
109 | { | ||
110 | output.EnsureTable(this.TableDefinitions["AdvtExecuteSequence"]); | ||
111 | sequenceTableDefinition = this.TableDefinitions["ModuleAdvtExecuteSequence"]; | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | sequenceTableDefinition = this.TableDefinitions["AdvtExecuteSequence"]; | ||
116 | } | ||
117 | break; | ||
118 | case SequenceTable.InstallExecuteSequence: | ||
119 | if (OutputType.Module == output.Type) | ||
120 | { | ||
121 | output.EnsureTable(this.TableDefinitions["InstallExecuteSequence"]); | ||
122 | sequenceTableDefinition = this.TableDefinitions["ModuleInstallExecuteSequence"]; | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | sequenceTableDefinition = this.TableDefinitions["InstallExecuteSequence"]; | ||
127 | } | ||
128 | break; | ||
129 | case SequenceTable.InstallUISequence: | ||
130 | if (OutputType.Module == output.Type) | ||
131 | { | ||
132 | output.EnsureTable(this.TableDefinitions["InstallUISequence"]); | ||
133 | sequenceTableDefinition = this.TableDefinitions["ModuleInstallUISequence"]; | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | sequenceTableDefinition = this.TableDefinitions["InstallUISequence"]; | ||
138 | } | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | // create the action sequence row in the output | ||
143 | var sequenceTable = output.EnsureTable(sequenceTableDefinition); | ||
144 | var row = sequenceTable.CreateRow(actionRow.SourceLineNumbers); | ||
145 | |||
146 | if (SectionType.Module == this.Section.Type) | ||
147 | { | ||
148 | row[0] = actionRow.Action; | ||
149 | if (0 != actionRow.Sequence) | ||
150 | { | ||
151 | row[1] = actionRow.Sequence; | ||
152 | } | ||
153 | else | ||
154 | { | ||
155 | bool after = (null == actionRow.Before); | ||
156 | row[2] = after ? actionRow.After : actionRow.Before; | ||
157 | row[3] = after ? 1 : 0; | ||
158 | } | ||
159 | row[4] = actionRow.Condition; | ||
160 | } | ||
161 | else | ||
162 | { | ||
163 | row[0] = actionRow.Action; | ||
164 | row[1] = actionRow.Condition; | ||
165 | row[2] = actionRow.Sequence; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | private void AddTupleDefaultly(IntermediateTuple tuple, Output output) | ||
170 | { | ||
171 | if (!this.TableDefinitions.TryGet(tuple.Definition.Name, out var tableDefinition)) | ||
172 | { | ||
173 | return; | ||
174 | } | ||
175 | |||
176 | var table = output.EnsureTable(tableDefinition); | ||
177 | var row = table.CreateRow(tuple.SourceLineNumbers); | ||
178 | for (var i = 0; i < tuple.Fields.Length; ++i) | ||
179 | { | ||
180 | if (i < tableDefinition.Columns.Count) | ||
181 | { | ||
182 | var column = tableDefinition.Columns[i]; | ||
183 | |||
184 | switch (column.Type) | ||
185 | { | ||
186 | case ColumnType.Number: | ||
187 | row[i] = tuple.AsNumber(i); | ||
188 | break; | ||
189 | |||
190 | default: | ||
191 | row[i] = tuple.AsString(i); | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | private static OutputType SectionTypeToOutputType(SectionType type) | ||
199 | { | ||
200 | switch (type) | ||
201 | { | ||
202 | case SectionType.Bundle: | ||
203 | return OutputType.Bundle; | ||
204 | case SectionType.Module: | ||
205 | return OutputType.Module; | ||
206 | case SectionType.Product: | ||
207 | return OutputType.Product; | ||
208 | case SectionType.PatchCreation: | ||
209 | return OutputType.PatchCreation; | ||
210 | case SectionType.Patch: | ||
211 | return OutputType.Patch; | ||
212 | |||
213 | default: | ||
214 | throw new ArgumentOutOfRangeException(nameof(type)); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | private static string GetMsiFilenameValue(string shortName, string longName) | ||
219 | { | ||
220 | if (String.IsNullOrEmpty(shortName)) | ||
221 | { | ||
222 | return longName; | ||
223 | } | ||
224 | else | ||
225 | { | ||
226 | return shortName + "|" + longName; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateSpecialPropertiesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateSpecialPropertiesCommand.cs index aef130b0..ab2e8201 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateSpecialPropertiesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateSpecialPropertiesCommand.cs | |||
@@ -1,67 +1,72 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Linq; | ||
7 | using WixToolset.Data; | 8 | using WixToolset.Data; |
8 | using WixToolset.Data.Rows; | 9 | using WixToolset.Data.Tuples; |
9 | 10 | ||
10 | internal class CreateSpecialPropertiesCommand | 11 | internal class CreateSpecialPropertiesCommand |
11 | { | 12 | { |
12 | public Table PropertyTable { private get; set; } | 13 | public CreateSpecialPropertiesCommand(IntermediateSection section) |
14 | { | ||
15 | this.Section = section; | ||
16 | } | ||
13 | 17 | ||
14 | public Table WixPropertyTable { private get; set; } | 18 | private IntermediateSection Section { get; } |
15 | 19 | ||
16 | public void Execute() | 20 | public void Execute() |
17 | { | 21 | { |
18 | // Create the special properties. | 22 | // Create lists of the properties that contribute to the special lists of properties. |
19 | if (null != this.WixPropertyTable) | 23 | SortedSet<string> adminProperties = new SortedSet<string>(); |
20 | { | 24 | SortedSet<string> secureProperties = new SortedSet<string>(); |
21 | // Create lists of the properties that contribute to the special lists of properties. | 25 | SortedSet<string> hiddenProperties = new SortedSet<string>(); |
22 | SortedSet<string> adminProperties = new SortedSet<string>(); | ||
23 | SortedSet<string> secureProperties = new SortedSet<string>(); | ||
24 | SortedSet<string> hiddenProperties = new SortedSet<string>(); | ||
25 | 26 | ||
26 | foreach (WixPropertyRow wixPropertyRow in this.WixPropertyTable.Rows) | 27 | foreach (var wixPropertyRow in this.Section.Tuples.OfType<WixPropertyTuple>()) |
28 | { | ||
29 | if (wixPropertyRow.Admin) | ||
27 | { | 30 | { |
28 | if (wixPropertyRow.Admin) | 31 | adminProperties.Add(wixPropertyRow.Property_); |
29 | { | ||
30 | adminProperties.Add(wixPropertyRow.Id); | ||
31 | } | ||
32 | |||
33 | if (wixPropertyRow.Hidden) | ||
34 | { | ||
35 | hiddenProperties.Add(wixPropertyRow.Id); | ||
36 | } | ||
37 | |||
38 | if (wixPropertyRow.Secure) | ||
39 | { | ||
40 | secureProperties.Add(wixPropertyRow.Id); | ||
41 | } | ||
42 | } | 32 | } |
43 | 33 | ||
44 | Table propertyTable = this.PropertyTable; | 34 | if (wixPropertyRow.Hidden) |
45 | if (0 < adminProperties.Count) | ||
46 | { | 35 | { |
47 | PropertyRow row = (PropertyRow)propertyTable.CreateRow(null); | 36 | hiddenProperties.Add(wixPropertyRow.Property_); |
48 | row.Property = "AdminProperties"; | ||
49 | row.Value = String.Join(";", adminProperties); | ||
50 | } | 37 | } |
51 | 38 | ||
52 | if (0 < secureProperties.Count) | 39 | if (wixPropertyRow.Secure) |
53 | { | 40 | { |
54 | PropertyRow row = (PropertyRow)propertyTable.CreateRow(null); | 41 | secureProperties.Add(wixPropertyRow.Property_); |
55 | row.Property = "SecureCustomProperties"; | ||
56 | row.Value = String.Join(";", secureProperties); | ||
57 | } | 42 | } |
43 | } | ||
58 | 44 | ||
59 | if (0 < hiddenProperties.Count) | 45 | if (0 < adminProperties.Count) |
60 | { | 46 | { |
61 | PropertyRow row = (PropertyRow)propertyTable.CreateRow(null); | 47 | var tuple = new PropertyTuple(null, new Identifier("AdminProperties", AccessModifier.Private)); |
62 | row.Property = "MsiHiddenProperties"; | 48 | tuple.Property = "AdminProperties"; |
63 | row.Value = String.Join(";", hiddenProperties); | 49 | tuple.Value = String.Join(";", adminProperties); |
64 | } | 50 | |
51 | this.Section.Tuples.Add(tuple); | ||
52 | } | ||
53 | |||
54 | if (0 < secureProperties.Count) | ||
55 | { | ||
56 | var tuple = new PropertyTuple(null, new Identifier("SecureCustomProperties", AccessModifier.Private)); | ||
57 | tuple.Property = "SecureCustomProperties"; | ||
58 | tuple.Value = String.Join(";", secureProperties); | ||
59 | |||
60 | this.Section.Tuples.Add(tuple); | ||
61 | } | ||
62 | |||
63 | if (0 < hiddenProperties.Count) | ||
64 | { | ||
65 | var tuple = new PropertyTuple(null, new Identifier("MsiHiddenProperties", AccessModifier.Private)); | ||
66 | tuple.Property = "MsiHiddenProperties"; | ||
67 | tuple.Value = String.Join(";", hiddenProperties); | ||
68 | |||
69 | this.Section.Tuples.Add(tuple); | ||
65 | } | 70 | } |
66 | } | 71 | } |
67 | } | 72 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs index 0d3e7bd1..32d1cfda 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -10,7 +10,6 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
10 | using System.Linq; | 10 | using System.Linq; |
11 | using System.Runtime.InteropServices; | 11 | using System.Runtime.InteropServices; |
12 | using WixToolset.Data; | 12 | using WixToolset.Data; |
13 | using WixToolset.Data.Rows; | ||
14 | using WixToolset.MergeMod; | 13 | using WixToolset.MergeMod; |
15 | using WixToolset.Msi; | 14 | using WixToolset.Msi; |
16 | using WixToolset.Core.Native; | 15 | using WixToolset.Core.Native; |
@@ -23,13 +22,17 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
23 | /// </summary> | 22 | /// </summary> |
24 | internal class ExtractMergeModuleFilesCommand | 23 | internal class ExtractMergeModuleFilesCommand |
25 | { | 24 | { |
26 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 25 | public ExtractMergeModuleFilesCommand(IntermediateSection section, List<WixMergeTuple> wixMergeTuples) |
26 | { | ||
27 | this.Section = section; | ||
28 | this.WixMergeTuples = wixMergeTuples; | ||
29 | } | ||
27 | 30 | ||
28 | public Table FileTable { private get; set; } | 31 | private IntermediateSection Section { get; } |
29 | 32 | ||
30 | public Table WixFileTable { private get; set; } | 33 | private List<WixMergeTuple> WixMergeTuples { get; } |
31 | 34 | ||
32 | public Table WixMergeTable { private get; set; } | 35 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
33 | 36 | ||
34 | public int OutputInstallerVersion { private get; set; } | 37 | public int OutputInstallerVersion { private get; set; } |
35 | 38 | ||
@@ -41,7 +44,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
41 | 44 | ||
42 | public void Execute() | 45 | public void Execute() |
43 | { | 46 | { |
44 | List<FileFacade> mergeModulesFileFacades = new List<FileFacade>(); | 47 | var mergeModulesFileFacades = new List<FileFacade>(); |
45 | 48 | ||
46 | IMsmMerge2 merge = MsmInterop.GetMsmMerge(); | 49 | IMsmMerge2 merge = MsmInterop.GetMsmMerge(); |
47 | 50 | ||
@@ -52,9 +55,9 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
52 | // Now since Merge Modules are already slow and generally less desirable than .wixlibs we'll let | 55 | // Now since Merge Modules are already slow and generally less desirable than .wixlibs we'll let |
53 | // this case be slightly more expensive because the cost of maintaining an indexed file row collection | 56 | // this case be slightly more expensive because the cost of maintaining an indexed file row collection |
54 | // is a lot more costly for the common cases. | 57 | // is a lot more costly for the common cases. |
55 | Dictionary<string, FileFacade> indexedFileFacades = this.FileFacades.ToDictionary(f => f.File.File, StringComparer.Ordinal); | 58 | var indexedFileFacades = this.FileFacades.ToDictionary(f => f.File.File, StringComparer.Ordinal); |
56 | 59 | ||
57 | foreach (WixMergeRow wixMergeRow in this.WixMergeTable.Rows) | 60 | foreach (var wixMergeRow in this.WixMergeTuples) |
58 | { | 61 | { |
59 | bool containsFiles = this.CreateFacadesForMergeModuleFiles(wixMergeRow, mergeModulesFileFacades, indexedFileFacades); | 62 | bool containsFiles = this.CreateFacadesForMergeModuleFiles(wixMergeRow, mergeModulesFileFacades, indexedFileFacades); |
60 | 63 | ||
@@ -68,7 +71,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
68 | this.MergeModulesFileFacades = mergeModulesFileFacades; | 71 | this.MergeModulesFileFacades = mergeModulesFileFacades; |
69 | } | 72 | } |
70 | 73 | ||
71 | private bool CreateFacadesForMergeModuleFiles(WixMergeRow wixMergeRow, List<FileFacade> mergeModulesFileFacades, Dictionary<string, FileFacade> indexedFileFacades) | 74 | private bool CreateFacadesForMergeModuleFiles(WixMergeTuple wixMergeRow, List<FileFacade> mergeModulesFileFacades, Dictionary<string, FileFacade> indexedFileFacades) |
72 | { | 75 | { |
73 | bool containsFiles = false; | 76 | bool containsFiles = false; |
74 | 77 | ||
@@ -98,7 +101,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
98 | // rows are created by merging in the actual modules. | 101 | // rows are created by merging in the actual modules. |
99 | var fileRow = new FileTuple(wixMergeRow.SourceLineNumbers, new Identifier(record[1], AccessModifier.Private)); | 102 | var fileRow = new FileTuple(wixMergeRow.SourceLineNumbers, new Identifier(record[1], AccessModifier.Private)); |
100 | fileRow.File = record[1]; | 103 | fileRow.File = record[1]; |
101 | fileRow.Compressed = (wixMergeRow.FileCompression == YesNoType.Yes) ? true : (wixMergeRow.FileCompression == YesNoType.No) ? (bool?)false : null; | 104 | fileRow.Compressed = wixMergeRow.FileCompression; |
102 | //FileRow fileRow = (FileRow)this.FileTable.CreateRow(wixMergeRow.SourceLineNumbers, false); | 105 | //FileRow fileRow = (FileRow)this.FileTable.CreateRow(wixMergeRow.SourceLineNumbers, false); |
103 | //fileRow.File = record[1]; | 106 | //fileRow.File = record[1]; |
104 | //fileRow.Compressed = wixMergeRow.FileCompression; | 107 | //fileRow.Compressed = wixMergeRow.FileCompression; |
@@ -107,7 +110,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
107 | wixFileRow.Directory_ = record[2]; | 110 | wixFileRow.Directory_ = record[2]; |
108 | wixFileRow.DiskId = wixMergeRow.DiskId; | 111 | wixFileRow.DiskId = wixMergeRow.DiskId; |
109 | wixFileRow.PatchGroup = -1; | 112 | wixFileRow.PatchGroup = -1; |
110 | wixFileRow.Source = Path.Combine(this.IntermediateFolder, "MergeId.", wixMergeRow.Number.ToString(CultureInfo.InvariantCulture), record[1]); | 113 | wixFileRow.Source = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]); |
111 | //WixFileRow wixFileRow = (WixFileRow)this.WixFileTable.CreateRow(wixMergeRow.SourceLineNumbers, false); | 114 | //WixFileRow wixFileRow = (WixFileRow)this.WixFileTable.CreateRow(wixMergeRow.SourceLineNumbers, false); |
112 | //wixFileRow.Directory = record[2]; | 115 | //wixFileRow.Directory = record[2]; |
113 | //wixFileRow.DiskId = wixMergeRow.DiskId; | 116 | //wixFileRow.DiskId = wixMergeRow.DiskId; |
@@ -119,11 +122,11 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
119 | // If case-sensitive collision with another merge module or a user-authored file identifier. | 122 | // If case-sensitive collision with another merge module or a user-authored file identifier. |
120 | if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.File.File, out var collidingFacade)) | 123 | if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.File.File, out var collidingFacade)) |
121 | { | 124 | { |
122 | Messaging.Instance.OnMessage(WixErrors.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, collidingFacade.File.File)); | 125 | Messaging.Instance.OnMessage(WixErrors.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, collidingFacade.File.File)); |
123 | } | 126 | } |
124 | else if (uniqueModuleFileIdentifiers.TryGetValue(mergeModuleFileFacade.File.File, out collidingFacade)) // case-insensitive collision with another file identifier in the same merge module | 127 | else if (uniqueModuleFileIdentifiers.TryGetValue(mergeModuleFileFacade.File.File, out collidingFacade)) // case-insensitive collision with another file identifier in the same merge module |
125 | { | 128 | { |
126 | Messaging.Instance.OnMessage(WixErrors.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, mergeModuleFileFacade.File.File, collidingFacade.File.File)); | 129 | Messaging.Instance.OnMessage(WixErrors.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, mergeModuleFileFacade.File.File, collidingFacade.File.File)); |
127 | } | 130 | } |
128 | else // no collision | 131 | else // no collision |
129 | { | 132 | { |
@@ -150,12 +153,12 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
150 | int moduleInstallerVersion = Convert.ToInt32(moduleInstallerVersionString, CultureInfo.InvariantCulture); | 153 | int moduleInstallerVersion = Convert.ToInt32(moduleInstallerVersionString, CultureInfo.InvariantCulture); |
151 | if (moduleInstallerVersion > this.OutputInstallerVersion) | 154 | if (moduleInstallerVersion > this.OutputInstallerVersion) |
152 | { | 155 | { |
153 | Messaging.Instance.OnMessage(WixWarnings.InvalidHigherInstallerVersionInModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleInstallerVersion, this.OutputInstallerVersion)); | 156 | Messaging.Instance.OnMessage(WixWarnings.InvalidHigherInstallerVersionInModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, moduleInstallerVersion, this.OutputInstallerVersion)); |
154 | } | 157 | } |
155 | } | 158 | } |
156 | catch (FormatException) | 159 | catch (FormatException) |
157 | { | 160 | { |
158 | throw new WixException(WixErrors.MissingOrInvalidModuleInstallerVersion(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile, moduleInstallerVersionString)); | 161 | throw new WixException(WixErrors.MissingOrInvalidModuleInstallerVersion(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, wixMergeRow.SourceFile, moduleInstallerVersionString)); |
159 | } | 162 | } |
160 | } | 163 | } |
161 | } | 164 | } |
@@ -166,24 +169,26 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
166 | } | 169 | } |
167 | catch (Win32Exception) | 170 | catch (Win32Exception) |
168 | { | 171 | { |
169 | throw new WixException(WixErrors.CannotOpenMergeModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile)); | 172 | throw new WixException(WixErrors.CannotOpenMergeModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, wixMergeRow.SourceFile)); |
170 | } | 173 | } |
171 | 174 | ||
172 | return containsFiles; | 175 | return containsFiles; |
173 | } | 176 | } |
174 | 177 | ||
175 | private void ExtractFilesFromMergeModule(IMsmMerge2 merge, WixMergeRow wixMergeRow) | 178 | private void ExtractFilesFromMergeModule(IMsmMerge2 merge, WixMergeTuple wixMergeRow) |
176 | { | 179 | { |
177 | bool moduleOpen = false; | 180 | bool moduleOpen = false; |
178 | short mergeLanguage; | 181 | short mergeLanguage; |
179 | 182 | ||
183 | var mergeId = wixMergeRow.Id.Id; | ||
184 | |||
180 | try | 185 | try |
181 | { | 186 | { |
182 | mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); | 187 | mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); |
183 | } | 188 | } |
184 | catch (System.FormatException) | 189 | catch (FormatException) |
185 | { | 190 | { |
186 | Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); | 191 | Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, mergeId, wixMergeRow.Language.ToString())); |
187 | return; | 192 | return; |
188 | } | 193 | } |
189 | 194 | ||
@@ -192,13 +197,11 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
192 | merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); | 197 | merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); |
193 | moduleOpen = true; | 198 | moduleOpen = true; |
194 | 199 | ||
195 | string safeMergeId = wixMergeRow.Number.ToString(CultureInfo.InvariantCulture.NumberFormat); | ||
196 | |||
197 | // extract the module cabinet, then explode all of the files to a temp directory | 200 | // extract the module cabinet, then explode all of the files to a temp directory |
198 | string moduleCabPath = String.Concat(this.IntermediateFolder, Path.DirectorySeparatorChar, safeMergeId, ".module.cab"); | 201 | string moduleCabPath = Path.Combine(this.IntermediateFolder, mergeId + ".cab"); |
199 | merge.ExtractCAB(moduleCabPath); | 202 | merge.ExtractCAB(moduleCabPath); |
200 | 203 | ||
201 | string mergeIdPath = String.Concat(this.IntermediateFolder, Path.DirectorySeparatorChar, "MergeId.", safeMergeId); | 204 | string mergeIdPath = Path.Combine(this.IntermediateFolder, mergeId); |
202 | Directory.CreateDirectory(mergeIdPath); | 205 | Directory.CreateDirectory(mergeIdPath); |
203 | 206 | ||
204 | using (var extractCab = new WixExtractCab()) | 207 | using (var extractCab = new WixExtractCab()) |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs index 47b58058..a3d3ecf7 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs index 9bbb4763..70ba971f 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -8,57 +8,50 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
8 | using System.Linq; | 8 | using System.Linq; |
9 | using WixToolset.Core.Bind; | 9 | using WixToolset.Core.Bind; |
10 | using WixToolset.Data; | 10 | using WixToolset.Data; |
11 | using WixToolset.Data.Rows; | 11 | using WixToolset.Data.Tuples; |
12 | 12 | ||
13 | internal class GetFileFacadesCommand | 13 | internal class GetFileFacadesCommand |
14 | { | 14 | { |
15 | public Table FileTable { private get; set; } | 15 | public GetFileFacadesCommand(IntermediateSection section) |
16 | 16 | { | |
17 | public Table WixFileTable { private get; set; } | 17 | this.Section = section; |
18 | 18 | } | |
19 | public Table WixDeltaPatchFileTable { private get; set; } | ||
20 | 19 | ||
21 | public Table WixDeltaPatchSymbolPathsTable { private get; set; } | 20 | private IntermediateSection Section { get; } |
22 | 21 | ||
23 | public List<FileFacade> FileFacades { get; private set; } | 22 | public List<FileFacade> FileFacades { get; private set; } |
24 | 23 | ||
25 | public void Execute() | 24 | public void Execute() |
26 | { | 25 | { |
27 | throw new NotImplementedException(); | 26 | var facades = new List<FileFacade>(); |
28 | #if TODO | ||
29 | List<FileFacade> facades = new List<FileFacade>(this.FileTable.Rows.Count); | ||
30 | 27 | ||
31 | RowDictionary<WixFileRow> wixFiles = new RowDictionary<WixFileRow>(this.WixFileTable); | 28 | var wixFiles = this.Section.Tuples.OfType<WixFileTuple>().ToDictionary(t => t.File_); |
32 | RowDictionary<WixDeltaPatchFileRow> deltaPatchFiles = new RowDictionary<WixDeltaPatchFileRow>(this.WixDeltaPatchFileTable); | 29 | var deltaPatchFiles = this.Section.Tuples.OfType<WixDeltaPatchFileTuple>().ToDictionary(t => t.File_); |
33 | 30 | ||
34 | foreach (FileRow file in this.FileTable.Rows) | 31 | foreach (var file in this.Section.Tuples.OfType<FileTuple>()) |
35 | { | 32 | { |
36 | WixDeltaPatchFileRow deltaPatchFile = null; | 33 | var wixFile = wixFiles[file.File]; |
37 | 34 | ||
38 | deltaPatchFiles.TryGetValue(file.File, out deltaPatchFile); | 35 | deltaPatchFiles.TryGetValue(file.File, out var deltaPatchFile); |
39 | 36 | ||
40 | facades.Add(new FileFacade(file, wixFiles[file.File], deltaPatchFile)); | 37 | facades.Add(new FileFacade(file, wixFile, deltaPatchFile)); |
41 | } | 38 | } |
42 | 39 | ||
43 | if (null != this.WixDeltaPatchSymbolPathsTable) | 40 | this.ResolveDeltaPatchSymbolPaths(deltaPatchFiles, facades); |
44 | { | ||
45 | this.ResolveDeltaPatchSymbolPaths(deltaPatchFiles, facades); | ||
46 | } | ||
47 | 41 | ||
48 | this.FileFacades = facades; | 42 | this.FileFacades = facades; |
49 | #endif | ||
50 | } | 43 | } |
51 | 44 | ||
52 | /// <summary> | 45 | /// <summary> |
53 | /// Merge data from the WixPatchSymbolPaths rows into the WixDeltaPatchFile rows. | 46 | /// Merge data from the WixPatchSymbolPaths rows into the WixDeltaPatchFile rows. |
54 | /// </summary> | 47 | /// </summary> |
55 | public RowDictionary<WixDeltaPatchFileRow> ResolveDeltaPatchSymbolPaths(RowDictionary<WixDeltaPatchFileRow> deltaPatchFiles, IEnumerable<FileFacade> facades) | 48 | public void ResolveDeltaPatchSymbolPaths(Dictionary<string, WixDeltaPatchFileTuple> deltaPatchFiles, IEnumerable<FileFacade> facades) |
56 | { | 49 | { |
57 | ILookup<string, FileFacade> filesByComponent = null; | 50 | ILookup<string, FileFacade> filesByComponent = null; |
58 | ILookup<string, FileFacade> filesByDirectory = null; | 51 | ILookup<string, FileFacade> filesByDirectory = null; |
59 | ILookup<string, FileFacade> filesByDiskId = null; | 52 | ILookup<string, FileFacade> filesByDiskId = null; |
60 | 53 | ||
61 | foreach (WixDeltaPatchSymbolPathsRow row in this.WixDeltaPatchSymbolPathsTable.RowsAs<WixDeltaPatchSymbolPathsRow>().OrderBy(r => r.Type)) | 54 | foreach (var row in this.Section.Tuples.OfType<WixDeltaPatchSymbolPathsTuple>().OrderBy(r => r.Type)) |
62 | { | 55 | { |
63 | switch (row.Type) | 56 | switch (row.Type) |
64 | { | 57 | { |
@@ -72,7 +65,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
72 | filesByComponent = facades.ToLookup(f => f.File.Component_); | 65 | filesByComponent = facades.ToLookup(f => f.File.Component_); |
73 | } | 66 | } |
74 | 67 | ||
75 | foreach (FileFacade facade in filesByComponent[row.Id]) | 68 | foreach (var facade in filesByComponent[row.Id]) |
76 | { | 69 | { |
77 | this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); | 70 | this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); |
78 | } | 71 | } |
@@ -84,7 +77,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
84 | filesByDirectory = facades.ToLookup(f => f.WixFile.Directory_); | 77 | filesByDirectory = facades.ToLookup(f => f.WixFile.Directory_); |
85 | } | 78 | } |
86 | 79 | ||
87 | foreach (FileFacade facade in filesByDirectory[row.Id]) | 80 | foreach (var facade in filesByDirectory[row.Id]) |
88 | { | 81 | { |
89 | this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); | 82 | this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); |
90 | } | 83 | } |
@@ -96,14 +89,14 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
96 | filesByDiskId = facades.ToLookup(f => f.WixFile.DiskId.ToString(CultureInfo.InvariantCulture)); | 89 | filesByDiskId = facades.ToLookup(f => f.WixFile.DiskId.ToString(CultureInfo.InvariantCulture)); |
97 | } | 90 | } |
98 | 91 | ||
99 | foreach (FileFacade facade in filesByDiskId[row.Id]) | 92 | foreach (var facade in filesByDiskId[row.Id]) |
100 | { | 93 | { |
101 | this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); | 94 | this.MergeSymbolPaths(row, deltaPatchFiles[facade.File.File]); |
102 | } | 95 | } |
103 | break; | 96 | break; |
104 | 97 | ||
105 | case SymbolPathType.Product: | 98 | case SymbolPathType.Product: |
106 | foreach (WixDeltaPatchFileRow fileRow in deltaPatchFiles.Values) | 99 | foreach (var fileRow in deltaPatchFiles.Values) |
107 | { | 100 | { |
108 | this.MergeSymbolPaths(row, fileRow); | 101 | this.MergeSymbolPaths(row, fileRow); |
109 | } | 102 | } |
@@ -114,8 +107,6 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
114 | break; | 107 | break; |
115 | } | 108 | } |
116 | } | 109 | } |
117 | |||
118 | return deltaPatchFiles; | ||
119 | } | 110 | } |
120 | 111 | ||
121 | /// <summary> | 112 | /// <summary> |
@@ -124,17 +115,18 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
124 | /// <param name="row">Row from the WixPatchSymbolsPaths table.</param> | 115 | /// <param name="row">Row from the WixPatchSymbolsPaths table.</param> |
125 | /// <param name="file">FileRow into which to set symbol information.</param> | 116 | /// <param name="file">FileRow into which to set symbol information.</param> |
126 | /// <comment>This includes PreviousData as well.</comment> | 117 | /// <comment>This includes PreviousData as well.</comment> |
127 | private void MergeSymbolPaths(WixDeltaPatchSymbolPathsRow row, WixDeltaPatchFileRow file) | 118 | private void MergeSymbolPaths(WixDeltaPatchSymbolPathsTuple row, WixDeltaPatchFileTuple file) |
128 | { | 119 | { |
129 | if (null == file.Symbols) | 120 | if (file.SymbolPaths is null) |
130 | { | 121 | { |
131 | file.Symbols = row.SymbolPaths; | 122 | file.SymbolPaths = row.SymbolPaths; |
132 | } | 123 | } |
133 | else | 124 | else |
134 | { | 125 | { |
135 | file.Symbols = String.Concat(file.Symbols, ";", row.SymbolPaths); | 126 | file.SymbolPaths = String.Concat(file.SymbolPaths, ";", row.SymbolPaths); |
136 | } | 127 | } |
137 | 128 | ||
129 | #if REVISIT_FOR_PATCHING | ||
138 | Field field = row.Fields[2]; | 130 | Field field = row.Fields[2]; |
139 | if (null != field.PreviousData) | 131 | if (null != field.PreviousData) |
140 | { | 132 | { |
@@ -147,6 +139,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
147 | file.PreviousSymbols = String.Concat(file.PreviousSymbols, ";", field.PreviousData); | 139 | file.PreviousSymbols = String.Concat(file.PreviousSymbols, ";", field.PreviousData); |
148 | } | 140 | } |
149 | } | 141 | } |
142 | #endif | ||
150 | } | 143 | } |
151 | } | 144 | } |
152 | } | 145 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index f1605eca..dcf67c05 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs | |||
@@ -1,20 +1,13 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Collections.Specialized; | ||
8 | using System.ComponentModel; | ||
9 | using System.Diagnostics; | ||
10 | using System.Globalization; | 7 | using System.Globalization; |
11 | using System.IO; | 8 | using System.IO; |
12 | using System.Linq; | ||
13 | using System.Runtime.InteropServices; | 9 | using System.Runtime.InteropServices; |
14 | using System.Text; | 10 | using System.Text; |
15 | using System.Xml; | ||
16 | using System.Xml.XPath; | ||
17 | using WixToolset.Clr.Interop; | ||
18 | using WixToolset.Data; | 11 | using WixToolset.Data; |
19 | using WixToolset.Data.Rows; | 12 | using WixToolset.Data.Rows; |
20 | using WixToolset.MergeMod; | 13 | using WixToolset.MergeMod; |
@@ -35,12 +28,10 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
35 | 28 | ||
36 | public IEnumerable<string> SuppressedTableNames { private get; set; } | 29 | public IEnumerable<string> SuppressedTableNames { private get; set; } |
37 | 30 | ||
38 | public string TempFilesLocation { private get; set; } | 31 | public string IntermediateFolder { private get; set; } |
39 | 32 | ||
40 | public void Execute() | 33 | public void Execute() |
41 | { | 34 | { |
42 | Debug.Assert(OutputType.Product == this.Output.Type); | ||
43 | |||
44 | Table wixMergeTable = this.Output.Tables["WixMerge"]; | 35 | Table wixMergeTable = this.Output.Tables["WixMerge"]; |
45 | Table wixFeatureModulesTable = this.Output.Tables["WixFeatureModules"]; | 36 | Table wixFeatureModulesTable = this.Output.Tables["WixFeatureModules"]; |
46 | 37 | ||
@@ -59,7 +50,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
59 | { | 50 | { |
60 | merge = MsmInterop.GetMsmMerge(); | 51 | merge = MsmInterop.GetMsmMerge(); |
61 | 52 | ||
62 | logPath = Path.Combine(this.TempFilesLocation, "merge.log"); | 53 | logPath = Path.Combine(this.IntermediateFolder, "merge.log"); |
63 | merge.OpenLog(logPath); | 54 | merge.OpenLog(logPath); |
64 | logOpen = true; | 55 | logOpen = true; |
65 | 56 | ||
@@ -79,7 +70,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
79 | { | 70 | { |
80 | mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); | 71 | mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); |
81 | } | 72 | } |
82 | catch (System.FormatException) | 73 | catch (FormatException) |
83 | { | 74 | { |
84 | Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); | 75 | Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); |
85 | continue; | 76 | continue; |
@@ -284,7 +275,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
284 | Messaging.Instance.OnMessage(WixVerboses.ResequencingMergeModuleFiles()); | 275 | Messaging.Instance.OnMessage(WixVerboses.ResequencingMergeModuleFiles()); |
285 | using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) | 276 | using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) |
286 | { | 277 | { |
287 | foreach (FileFacade file in this.FileFacades) | 278 | foreach (var file in this.FileFacades) |
288 | { | 279 | { |
289 | if (!file.FromModule) | 280 | if (!file.FromModule) |
290 | { | 281 | { |
@@ -307,32 +298,29 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
307 | //recordUpdate.SetInteger(1, file.File.Sequence); | 298 | //recordUpdate.SetInteger(1, file.File.Sequence); |
308 | throw new NotImplementedException(); | 299 | throw new NotImplementedException(); |
309 | 300 | ||
310 | // update the file attributes to match the compression specified | 301 | // Update the file attributes to match the compression specified |
311 | // on the Merge element or on the Package element | 302 | // on the Merge element or on the Package element. |
312 | int attributes = 0; | 303 | var attributes = 0; |
313 | 304 | ||
314 | // get the current value if its not null | 305 | // Get the current value if its not null. |
315 | if (!recordUpdate.IsNull(2)) | 306 | if (!recordUpdate.IsNull(2)) |
316 | { | 307 | { |
317 | attributes = recordUpdate.GetInteger(2); | 308 | attributes = recordUpdate.GetInteger(2); |
318 | } | 309 | } |
319 | 310 | ||
320 | // not specified | ||
321 | if (!file.File.Compressed.HasValue) | 311 | if (!file.File.Compressed.HasValue) |
322 | { | 312 | { |
323 | // clear any compression bits | 313 | // Clear all compression bits. |
324 | attributes &= ~MsiInterop.MsidbFileAttributesCompressed; | 314 | attributes &= ~MsiInterop.MsidbFileAttributesCompressed; |
325 | attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; | 315 | attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; |
326 | } | 316 | } |
327 | else if (file.File.Compressed.Value) | 317 | else if (file.File.Compressed.Value) |
328 | { | 318 | { |
329 | // these are mutually exclusive | ||
330 | attributes |= MsiInterop.MsidbFileAttributesCompressed; | 319 | attributes |= MsiInterop.MsidbFileAttributesCompressed; |
331 | attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; | 320 | attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; |
332 | } | 321 | } |
333 | else if (!file.File.Compressed.Value) | 322 | else if (!file.File.Compressed.Value) |
334 | { | 323 | { |
335 | // these are mutually exclusive | ||
336 | attributes |= MsiInterop.MsidbFileAttributesNoncompressed; | 324 | attributes |= MsiInterop.MsidbFileAttributesNoncompressed; |
337 | attributes &= ~MsiInterop.MsidbFileAttributesCompressed; | 325 | attributes &= ~MsiInterop.MsidbFileAttributesCompressed; |
338 | } | 326 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs index b3c09b9e..d71724d1 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs | |||
@@ -1,39 +1,42 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
8 | using System.IO; | 7 | using System.IO; |
9 | using WixToolset.Data; | 8 | using WixToolset.Data; |
10 | using WixToolset.Data.Rows; | ||
11 | using WixToolset.Msi; | 9 | using WixToolset.Msi; |
12 | using WixToolset.Core.Native; | 10 | using WixToolset.Core.Native; |
13 | using WixToolset.Bind; | 11 | using WixToolset.Bind; |
14 | using WixToolset.Core.Bind; | 12 | using WixToolset.Core.Bind; |
15 | using WixToolset.Data.Bind; | 13 | using WixToolset.Data.Bind; |
14 | using WixToolset.Data.Tuples; | ||
15 | using System.Linq; | ||
16 | 16 | ||
17 | /// <summary> | 17 | /// <summary> |
18 | /// Defines the file transfers necessary to layout the uncompressed files. | 18 | /// Defines the file transfers necessary to layout the uncompressed files. |
19 | /// </summary> | 19 | /// </summary> |
20 | internal class ProcessUncompressedFilesCommand | 20 | internal class ProcessUncompressedFilesCommand |
21 | { | 21 | { |
22 | public ProcessUncompressedFilesCommand(IntermediateSection section) | ||
23 | { | ||
24 | this.Section = section; | ||
25 | } | ||
26 | |||
27 | private IntermediateSection Section { get; } | ||
28 | |||
22 | public string DatabasePath { private get; set; } | 29 | public string DatabasePath { private get; set; } |
23 | 30 | ||
24 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 31 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
25 | 32 | ||
26 | public RowDictionary<MediaRow> MediaRows { private get; set; } | ||
27 | |||
28 | public string LayoutDirectory { private get; set; } | 33 | public string LayoutDirectory { private get; set; } |
29 | 34 | ||
30 | public bool Compressed { private get; set; } | 35 | public bool Compressed { private get; set; } |
31 | 36 | ||
32 | public bool LongNamesInImage { private get; set; } | 37 | public bool LongNamesInImage { private get; set; } |
33 | 38 | ||
34 | public Func<MediaRow, string, string, string> ResolveMedia { private get; set; } | 39 | public Func<MediaTuple, string, string, string> ResolveMedia { private get; set; } |
35 | |||
36 | public Table WixMediaTable { private get; set; } | ||
37 | 40 | ||
38 | public IEnumerable<FileTransfer> FileTransfers { get; private set; } | 41 | public IEnumerable<FileTransfer> FileTransfers { get; private set; } |
39 | 42 | ||
@@ -41,9 +44,11 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
41 | { | 44 | { |
42 | List<FileTransfer> fileTransfers = new List<FileTransfer>(); | 45 | List<FileTransfer> fileTransfers = new List<FileTransfer>(); |
43 | 46 | ||
44 | Hashtable directories = new Hashtable(); | 47 | var directories = new Dictionary<string, ResolvedDirectory>(); |
45 | 48 | ||
46 | RowDictionary<WixMediaRow> wixMediaRows = new RowDictionary<WixMediaRow>(this.WixMediaTable); | 49 | var mediaRows = this.Section.Tuples.OfType<MediaTuple>().ToDictionary(t => t.DiskId); |
50 | |||
51 | var wixMediaRows = this.Section.Tuples.OfType<WixMediaTuple>().ToDictionary(t => t.DiskId_); | ||
47 | 52 | ||
48 | using (Database db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) | 53 | using (Database db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) |
49 | { | 54 | { |
@@ -72,18 +77,16 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
72 | // for each file in the array of uncompressed files | 77 | // for each file in the array of uncompressed files |
73 | foreach (FileFacade facade in this.FileFacades) | 78 | foreach (FileFacade facade in this.FileFacades) |
74 | { | 79 | { |
75 | MediaRow mediaRow = this.MediaRows.Get(facade.WixFile.DiskId); | 80 | var mediaTuple = mediaRows[facade.WixFile.DiskId]; |
76 | string relativeFileLayoutPath = null; | 81 | string relativeFileLayoutPath = null; |
77 | |||
78 | WixMediaRow wixMediaRow = null; | ||
79 | string mediaLayoutFolder = null; | 82 | string mediaLayoutFolder = null; |
80 | 83 | ||
81 | if (wixMediaRows.TryGetValue(mediaRow.GetKey(), out wixMediaRow)) | 84 | if (wixMediaRows.TryGetValue(facade.WixFile.DiskId, out var wixMediaRow)) |
82 | { | 85 | { |
83 | mediaLayoutFolder = wixMediaRow.Layout; | 86 | mediaLayoutFolder = wixMediaRow.Layout; |
84 | } | 87 | } |
85 | 88 | ||
86 | string mediaLayoutDirectory = this.ResolveMedia(mediaRow, mediaLayoutFolder, this.LayoutDirectory); | 89 | var mediaLayoutDirectory = this.ResolveMedia(mediaTuple, mediaLayoutFolder, this.LayoutDirectory); |
87 | 90 | ||
88 | // setup up the query record and find the appropriate file in the | 91 | // setup up the query record and find the appropriate file in the |
89 | // previously executed file view | 92 | // previously executed file view |
@@ -102,8 +105,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
102 | 105 | ||
103 | // finally put together the base media layout path and the relative file layout path | 106 | // finally put together the base media layout path and the relative file layout path |
104 | string fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath); | 107 | string fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath); |
105 | FileTransfer transfer; | 108 | if (FileTransfer.TryCreate(facade.WixFile.Source, fileLayoutPath, false, "File", facade.File.SourceLineNumbers, out var transfer)) |
106 | if (FileTransfer.TryCreate(facade.WixFile.Source, fileLayoutPath, false, "File", facade.File.SourceLineNumbers, out transfer)) | ||
107 | { | 109 | { |
108 | fileTransfers.Add(transfer); | 110 | fileTransfers.Add(transfer); |
109 | } | 111 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs new file mode 100644 index 00000000..cf9c0332 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs | |||
@@ -0,0 +1,671 @@ | |||
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 | namespace WixToolset.Core.WindowsInstaller.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.Linq; | ||
9 | using WixToolset.Core.Native; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Data.Tuples; | ||
12 | |||
13 | internal class SequenceActionsCommand | ||
14 | { | ||
15 | public SequenceActionsCommand(IntermediateSection section) | ||
16 | { | ||
17 | this.Section = section; | ||
18 | |||
19 | this.RelativeActionsForActions = new Dictionary<string, RelativeActions>(); | ||
20 | |||
21 | this.StandardActionsById = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id); | ||
22 | } | ||
23 | |||
24 | private IntermediateSection Section { get; } | ||
25 | |||
26 | private Dictionary<string, RelativeActions> RelativeActionsForActions { get; } | ||
27 | |||
28 | private Dictionary<string, WixActionTuple> StandardActionsById { get; } | ||
29 | |||
30 | public Messaging Messaging { private get; set; } | ||
31 | |||
32 | public void Execute() | ||
33 | { | ||
34 | var actions = this.Section.Tuples.OfType<WixActionTuple>().ToList(); | ||
35 | var suppressActions = this.Section.Tuples.OfType<WixSuppressActionTuple>().ToList(); | ||
36 | |||
37 | this.SequenceActions(actions, suppressActions); | ||
38 | } | ||
39 | |||
40 | /// <summary> | ||
41 | /// Set sequence numbers for all the actions and create rows in the output object. | ||
42 | /// </summary> | ||
43 | /// <param name="actionRows">Collection of actions to schedule.</param> | ||
44 | /// <param name="suppressActionRows">Collection of actions to suppress.</param> | ||
45 | private void SequenceActions(List<WixActionTuple> actionRows, List<WixSuppressActionTuple> suppressActionRows) | ||
46 | { | ||
47 | var overridableActionRows = new Dictionary<string, WixActionTuple>(); | ||
48 | var requiredActionRows = new Dictionary<string, WixActionTuple>(); | ||
49 | |||
50 | // Get the standard actions required based on tuples in the section. | ||
51 | var requiredActionIds = this.GetRequiredActionIds(); | ||
52 | |||
53 | foreach (var actionId in requiredActionIds) | ||
54 | { | ||
55 | var standardAction = this.StandardActionsById[actionId]; | ||
56 | |||
57 | overridableActionRows.Add(standardAction.Id.Id, standardAction); | ||
58 | } | ||
59 | |||
60 | // Index all the action rows and look for collisions. | ||
61 | foreach (var actionRow in this.Section.Tuples.OfType<WixActionTuple>()) | ||
62 | { | ||
63 | if (actionRow.Overridable) // overridable action | ||
64 | { | ||
65 | if (overridableActionRows.TryGetValue(actionRow.Id.Id, out var collidingActionRow)) | ||
66 | { | ||
67 | this.Messaging.OnMessage(WixErrors.OverridableActionCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); | ||
68 | if (null != collidingActionRow.SourceLineNumbers) | ||
69 | { | ||
70 | this.Messaging.OnMessage(WixErrors.OverridableActionCollision2(collidingActionRow.SourceLineNumbers)); | ||
71 | } | ||
72 | } | ||
73 | else | ||
74 | { | ||
75 | overridableActionRows.Add(actionRow.Id.Id, actionRow); | ||
76 | } | ||
77 | } | ||
78 | else // unsequenced or sequenced action. | ||
79 | { | ||
80 | // Unsequenced action (allowed for certain standard actions). | ||
81 | if (null == actionRow.Before && null == actionRow.After && 0 == actionRow.Sequence) | ||
82 | { | ||
83 | if (this.StandardActionsById.TryGetValue(actionRow.Id.Id, out var standardAction)) | ||
84 | { | ||
85 | // Populate the sequence from the standard action | ||
86 | actionRow.Sequence = standardAction.Sequence; | ||
87 | } | ||
88 | else // not a supported unscheduled action. | ||
89 | { | ||
90 | throw new InvalidOperationException(WixStrings.EXP_FoundActionRowWithNoSequenceBeforeOrAfterColumnSet); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | if (overridableActionRows.TryGetValue(actionRow.Id.Id, out var collidingActionRow)) | ||
95 | { | ||
96 | this.Messaging.OnMessage(WixErrors.ActionCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); | ||
97 | if (null != collidingActionRow.SourceLineNumbers) | ||
98 | { | ||
99 | this.Messaging.OnMessage(WixErrors.ActionCollision2(collidingActionRow.SourceLineNumbers)); | ||
100 | } | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | requiredActionRows.Add(actionRow.Id.Id, actionRow); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // Add the overridable action rows that are not overridden to the required action rows. | ||
110 | foreach (var actionRow in overridableActionRows.Values) | ||
111 | { | ||
112 | if (!requiredActionRows.ContainsKey(actionRow.Id.Id)) | ||
113 | { | ||
114 | requiredActionRows.Add(actionRow.Id.Id, actionRow); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | // Suppress the required actions that are overridable. | ||
119 | foreach (var suppressActionRow in suppressActionRows) | ||
120 | { | ||
121 | var key = suppressActionRow.Id.Id; | ||
122 | |||
123 | // If there is an overridable row to suppress; suppress it. There is no warning if there | ||
124 | // is no action to suppress because the action may be suppressed from a merge module in | ||
125 | // the binder. | ||
126 | if (requiredActionRows.TryGetValue(key, out var requiredActionRow)) | ||
127 | { | ||
128 | if (requiredActionRow.Overridable) | ||
129 | { | ||
130 | this.Messaging.OnMessage(WixWarnings.SuppressAction(suppressActionRow.SourceLineNumbers, suppressActionRow.Action, suppressActionRow.SequenceTable.ToString())); | ||
131 | if (null != requiredActionRow.SourceLineNumbers) | ||
132 | { | ||
133 | this.Messaging.OnMessage(WixWarnings.SuppressAction2(requiredActionRow.SourceLineNumbers)); | ||
134 | } | ||
135 | |||
136 | requiredActionRows.Remove(key); | ||
137 | } | ||
138 | else // suppressing a non-overridable action row | ||
139 | { | ||
140 | this.Messaging.OnMessage(WixErrors.SuppressNonoverridableAction(suppressActionRow.SourceLineNumbers, suppressActionRow.SequenceTable.ToString(), suppressActionRow.Action)); | ||
141 | if (null != requiredActionRow.SourceLineNumbers) | ||
142 | { | ||
143 | this.Messaging.OnMessage(WixErrors.SuppressNonoverridableAction2(requiredActionRow.SourceLineNumbers)); | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | // Build up dependency trees of the relatively scheduled actions. | ||
150 | // Use ToList() to create a copy of the required action rows so that new tuples can | ||
151 | // be added while enumerating. | ||
152 | foreach (var actionRow in requiredActionRows.Values.ToList()) | ||
153 | { | ||
154 | if (0 == actionRow.Sequence) | ||
155 | { | ||
156 | // check for standard actions that don't have a sequence number in a merge module | ||
157 | if (SectionType.Module == this.Section.Type && WindowsInstallerStandard.IsStandardAction(actionRow.Action)) | ||
158 | { | ||
159 | this.Messaging.OnMessage(WixErrors.StandardActionRelativelyScheduledInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); | ||
160 | } | ||
161 | |||
162 | this.SequenceActionRow(actionRow, requiredActionRows); | ||
163 | } | ||
164 | else if (SectionType.Module == this.Section.Type && 0 < actionRow.Sequence && !WindowsInstallerStandard.IsStandardAction(actionRow.Action)) // check for custom actions and dialogs that have a sequence number | ||
165 | { | ||
166 | this.Messaging.OnMessage(WixErrors.CustomActionSequencedInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | // Look for standard actions with sequence restrictions that aren't necessarily scheduled based | ||
171 | // on the presence of a particular table. | ||
172 | if (requiredActionRows.ContainsKey("InstallExecuteSequence/DuplicateFiles") && !requiredActionRows.ContainsKey("InstallExecuteSequence/InstallFiles")) | ||
173 | { | ||
174 | var standardAction = this.StandardActionsById["InstallExecuteSequence/InstallFiles"]; | ||
175 | requiredActionRows.Add(standardAction.Id.Id, standardAction); | ||
176 | } | ||
177 | |||
178 | // Schedule actions. | ||
179 | List<WixActionTuple> scheduledActionRows; | ||
180 | if (SectionType.Module == this.Section.Type) | ||
181 | { | ||
182 | scheduledActionRows = requiredActionRows.Values.ToList(); | ||
183 | } | ||
184 | else | ||
185 | { | ||
186 | scheduledActionRows = ScheduleActions(requiredActionRows); | ||
187 | } | ||
188 | |||
189 | // Remove all existing WixActionTuples from the section then add the | ||
190 | // scheduled actions back to the section. Note: we add the indices in | ||
191 | // reverse order to make it easy to remove them from the list later. | ||
192 | var removeIndices = new List<int>(); | ||
193 | for (var i = this.Section.Tuples.Count - 1; i >= 0; --i) | ||
194 | { | ||
195 | var tuple = this.Section.Tuples[i]; | ||
196 | if (tuple.Definition.Type == TupleDefinitionType.WixAction) | ||
197 | { | ||
198 | removeIndices.Add(i); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | foreach (var removeIndex in removeIndices) | ||
203 | { | ||
204 | this.Section.Tuples.RemoveAt(removeIndex); | ||
205 | } | ||
206 | |||
207 | foreach (var action in scheduledActionRows) | ||
208 | { | ||
209 | this.Section.Tuples.Add(action); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | private List<WixActionTuple> ScheduleActions(Dictionary<string, WixActionTuple> requiredActionRows) | ||
214 | { | ||
215 | var scheduledActionRows = new List<WixActionTuple>(); | ||
216 | |||
217 | // Process each sequence table individually. | ||
218 | foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) | ||
219 | { | ||
220 | // Create a collection of just the action rows in this sequence | ||
221 | var sequenceActionRows = requiredActionRows.Values.Where(a => a.SequenceTable == sequenceTable).ToList(); | ||
222 | |||
223 | // Schedule the absolutely scheduled actions (by sorting them by their sequence numbers). | ||
224 | var absoluteActionRows = new List<WixActionTuple>(); | ||
225 | foreach (var actionRow in sequenceActionRows) | ||
226 | { | ||
227 | if (0 != actionRow.Sequence) | ||
228 | { | ||
229 | // Look for sequence number collisions | ||
230 | foreach (var sequenceScheduledActionRow in absoluteActionRows) | ||
231 | { | ||
232 | if (sequenceScheduledActionRow.Sequence == actionRow.Sequence) | ||
233 | { | ||
234 | this.Messaging.OnMessage(WixWarnings.ActionSequenceCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, sequenceScheduledActionRow.Action, actionRow.Sequence)); | ||
235 | if (null != sequenceScheduledActionRow.SourceLineNumbers) | ||
236 | { | ||
237 | this.Messaging.OnMessage(WixWarnings.ActionSequenceCollision2(sequenceScheduledActionRow.SourceLineNumbers)); | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | absoluteActionRows.Add(actionRow); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | absoluteActionRows.Sort((x, y) => x.Sequence.CompareTo(y.Sequence)); | ||
247 | |||
248 | // Schedule the relatively scheduled actions (by resolving the dependency trees). | ||
249 | var previousUsedSequence = 0; | ||
250 | var relativeActionRows = new List<WixActionTuple>(); | ||
251 | for (int j = 0; j < absoluteActionRows.Count; j++) | ||
252 | { | ||
253 | var absoluteActionRow = absoluteActionRows[j]; | ||
254 | |||
255 | // Get all the relatively scheduled action rows occuring before and after this absolutely scheduled action row. | ||
256 | var relativeActions = this.GetAllRelativeActionsForSequenceType(sequenceTable, absoluteActionRow); | ||
257 | |||
258 | // Check for relatively scheduled actions occuring before/after a special action | ||
259 | // (those actions with a negative sequence number). | ||
260 | if (absoluteActionRow.Sequence < 0 && (relativeActions.PreviousActions.Any() || relativeActions.NextActions.Any())) | ||
261 | { | ||
262 | // Create errors for all the before actions. | ||
263 | foreach (var actionRow in relativeActions.PreviousActions) | ||
264 | { | ||
265 | this.Messaging.OnMessage(WixErrors.ActionScheduledRelativeToTerminationAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, absoluteActionRow.Action)); | ||
266 | } | ||
267 | |||
268 | // Create errors for all the after actions. | ||
269 | foreach (var actionRow in relativeActions.NextActions) | ||
270 | { | ||
271 | this.Messaging.OnMessage(WixErrors.ActionScheduledRelativeToTerminationAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, absoluteActionRow.Action)); | ||
272 | } | ||
273 | |||
274 | // If there is source line information for the absolutely scheduled action display it | ||
275 | if (absoluteActionRow.SourceLineNumbers != null) | ||
276 | { | ||
277 | this.Messaging.OnMessage(WixErrors.ActionScheduledRelativeToTerminationAction2(absoluteActionRow.SourceLineNumbers)); | ||
278 | } | ||
279 | |||
280 | continue; | ||
281 | } | ||
282 | |||
283 | // Schedule the action rows before this one. | ||
284 | var unusedSequence = absoluteActionRow.Sequence - 1; | ||
285 | for (var i = relativeActions.PreviousActions.Count - 1; i >= 0; i--) | ||
286 | { | ||
287 | var relativeActionRow = relativeActions.PreviousActions[i]; | ||
288 | |||
289 | // look for collisions | ||
290 | if (unusedSequence == previousUsedSequence) | ||
291 | { | ||
292 | this.Messaging.OnMessage(WixErrors.NoUniqueActionSequenceNumber(relativeActionRow.SourceLineNumbers, relativeActionRow.SequenceTable.ToString(), relativeActionRow.Action, absoluteActionRow.Action)); | ||
293 | if (absoluteActionRow.SourceLineNumbers != null) | ||
294 | { | ||
295 | this.Messaging.OnMessage(WixErrors.NoUniqueActionSequenceNumber2(absoluteActionRow.SourceLineNumbers)); | ||
296 | } | ||
297 | |||
298 | unusedSequence++; | ||
299 | } | ||
300 | |||
301 | relativeActionRow.Sequence = unusedSequence; | ||
302 | relativeActionRows.Add(relativeActionRow); | ||
303 | |||
304 | unusedSequence--; | ||
305 | } | ||
306 | |||
307 | // Determine the next used action sequence number. | ||
308 | var nextUsedSequence = Int16.MaxValue + 1; | ||
309 | if (absoluteActionRows.Count > j + 1) | ||
310 | { | ||
311 | nextUsedSequence = absoluteActionRows[j + 1].Sequence; | ||
312 | } | ||
313 | |||
314 | // Schedule the action rows after this one. | ||
315 | unusedSequence = absoluteActionRow.Sequence + 1; | ||
316 | for (var i = 0; i < relativeActions.NextActions.Count; i++) | ||
317 | { | ||
318 | var relativeActionRow = relativeActions.NextActions[i]; | ||
319 | |||
320 | if (unusedSequence == nextUsedSequence) | ||
321 | { | ||
322 | this.Messaging.OnMessage(WixErrors.NoUniqueActionSequenceNumber(relativeActionRow.SourceLineNumbers, relativeActionRow.SequenceTable.ToString(), relativeActionRow.Action, absoluteActionRow.Action)); | ||
323 | if (absoluteActionRow.SourceLineNumbers != null) | ||
324 | { | ||
325 | this.Messaging.OnMessage(WixErrors.NoUniqueActionSequenceNumber2(absoluteActionRow.SourceLineNumbers)); | ||
326 | } | ||
327 | |||
328 | unusedSequence--; | ||
329 | } | ||
330 | |||
331 | relativeActionRow.Sequence = unusedSequence; | ||
332 | relativeActionRows.Add(relativeActionRow); | ||
333 | |||
334 | unusedSequence++; | ||
335 | } | ||
336 | |||
337 | // keep track of this sequence number as the previous used sequence number for the next iteration | ||
338 | previousUsedSequence = absoluteActionRow.Sequence; | ||
339 | } | ||
340 | |||
341 | // add the absolutely and relatively scheduled actions to the list of scheduled actions | ||
342 | scheduledActionRows.AddRange(absoluteActionRows); | ||
343 | scheduledActionRows.AddRange(relativeActionRows); | ||
344 | } | ||
345 | |||
346 | return scheduledActionRows; | ||
347 | } | ||
348 | |||
349 | private IEnumerable<string> GetRequiredActionIds() | ||
350 | { | ||
351 | var set = new HashSet<string>(); | ||
352 | |||
353 | // gather the required actions for the output type | ||
354 | if (SectionType.Product == this.Section.Type) | ||
355 | { | ||
356 | // AdminExecuteSequence table | ||
357 | set.Add("AdminExecuteSequence/CostFinalize"); | ||
358 | set.Add("AdminExecuteSequence/CostInitialize"); | ||
359 | set.Add("AdminExecuteSequence/FileCost"); | ||
360 | set.Add("AdminExecuteSequence/InstallAdminPackage"); | ||
361 | set.Add("AdminExecuteSequence/InstallFiles"); | ||
362 | set.Add("AdminExecuteSequence/InstallFinalize"); | ||
363 | set.Add("AdminExecuteSequence/InstallInitialize"); | ||
364 | set.Add("AdminExecuteSequence/InstallValidate"); | ||
365 | |||
366 | // AdminUISequence table | ||
367 | set.Add("AdminUISequence/CostFinalize"); | ||
368 | set.Add("AdminUISequence/CostInitialize"); | ||
369 | set.Add("AdminUISequence/ExecuteAction"); | ||
370 | set.Add("AdminUISequence/FileCost"); | ||
371 | |||
372 | // AdvtExecuteSequence table | ||
373 | set.Add("AdvtExecuteSequence/CostFinalize"); | ||
374 | set.Add("AdvtExecuteSequence/CostInitialize"); | ||
375 | set.Add("AdvtExecuteSequence/InstallFinalize"); | ||
376 | set.Add("AdvtExecuteSequence/InstallValidate"); | ||
377 | set.Add("AdvtExecuteSequence/PublishFeatures"); | ||
378 | set.Add("AdvtExecuteSequence/PublishProduct"); | ||
379 | |||
380 | // InstallExecuteSequence table | ||
381 | set.Add("InstallExecuteSequence/CostFinalize"); | ||
382 | set.Add("InstallExecuteSequence/CostInitialize"); | ||
383 | set.Add("InstallExecuteSequence/FileCost"); | ||
384 | set.Add("InstallExecuteSequence/InstallFinalize"); | ||
385 | set.Add("InstallExecuteSequence/InstallInitialize"); | ||
386 | set.Add("InstallExecuteSequence/InstallValidate"); | ||
387 | set.Add("InstallExecuteSequence/ProcessComponents"); | ||
388 | set.Add("InstallExecuteSequence/PublishFeatures"); | ||
389 | set.Add("InstallExecuteSequence/PublishProduct"); | ||
390 | set.Add("InstallExecuteSequence/RegisterProduct"); | ||
391 | set.Add("InstallExecuteSequence/RegisterUser"); | ||
392 | set.Add("InstallExecuteSequence/UnpublishFeatures"); | ||
393 | set.Add("InstallExecuteSequence/ValidateProductID"); | ||
394 | |||
395 | // InstallUISequence table | ||
396 | set.Add("InstallUISequence/CostFinalize"); | ||
397 | set.Add("InstallUISequence/CostInitialize"); | ||
398 | set.Add("InstallUISequence/ExecuteAction"); | ||
399 | set.Add("InstallUISequence/FileCost"); | ||
400 | set.Add("InstallUISequence/ValidateProductID"); | ||
401 | } | ||
402 | |||
403 | // Gather the required actions for each tuple type. | ||
404 | foreach (var tupleType in this.Section.Tuples.Select(t => t.Definition.Type).Distinct()) | ||
405 | { | ||
406 | switch (tupleType) | ||
407 | { | ||
408 | case TupleDefinitionType.AppSearch: | ||
409 | set.Add("InstallExecuteSequence/AppSearch"); | ||
410 | set.Add("InstallUISequence/AppSearch"); | ||
411 | break; | ||
412 | case TupleDefinitionType.BindImage: | ||
413 | set.Add("InstallExecuteSequence/BindImage"); | ||
414 | break; | ||
415 | case TupleDefinitionType.CCPSearch: | ||
416 | set.Add("InstallExecuteSequence/AppSearch"); | ||
417 | set.Add("InstallExecuteSequence/CCPSearch"); | ||
418 | set.Add("InstallExecuteSequence/RMCCPSearch"); | ||
419 | set.Add("InstallUISequence/AppSearch"); | ||
420 | set.Add("InstallUISequence/CCPSearch"); | ||
421 | set.Add("InstallUISequence/RMCCPSearch"); | ||
422 | break; | ||
423 | case TupleDefinitionType.Class: | ||
424 | set.Add("AdvtExecuteSequence/RegisterClassInfo"); | ||
425 | set.Add("InstallExecuteSequence/RegisterClassInfo"); | ||
426 | set.Add("InstallExecuteSequence/UnregisterClassInfo"); | ||
427 | break; | ||
428 | case TupleDefinitionType.Complus: | ||
429 | set.Add("InstallExecuteSequence/RegisterComPlus"); | ||
430 | set.Add("InstallExecuteSequence/UnregisterComPlus"); | ||
431 | break; | ||
432 | case TupleDefinitionType.CreateFolder: | ||
433 | set.Add("InstallExecuteSequence/CreateFolders"); | ||
434 | set.Add("InstallExecuteSequence/RemoveFolders"); | ||
435 | break; | ||
436 | case TupleDefinitionType.DuplicateFile: | ||
437 | set.Add("InstallExecuteSequence/DuplicateFiles"); | ||
438 | set.Add("InstallExecuteSequence/RemoveDuplicateFiles"); | ||
439 | break; | ||
440 | case TupleDefinitionType.Environment: | ||
441 | set.Add("InstallExecuteSequence/WriteEnvironmentStrings"); | ||
442 | set.Add("InstallExecuteSequence/RemoveEnvironmentStrings"); | ||
443 | break; | ||
444 | case TupleDefinitionType.Extension: | ||
445 | set.Add("AdvtExecuteSequence/RegisterExtensionInfo"); | ||
446 | set.Add("InstallExecuteSequence/RegisterExtensionInfo"); | ||
447 | set.Add("InstallExecuteSequence/UnregisterExtensionInfo"); | ||
448 | break; | ||
449 | case TupleDefinitionType.File: | ||
450 | set.Add("InstallExecuteSequence/InstallFiles"); | ||
451 | set.Add("InstallExecuteSequence/RemoveFiles"); | ||
452 | break; | ||
453 | case TupleDefinitionType.Font: | ||
454 | set.Add("InstallExecuteSequence/RegisterFonts"); | ||
455 | set.Add("InstallExecuteSequence/UnregisterFonts"); | ||
456 | break; | ||
457 | case TupleDefinitionType.IniFile: | ||
458 | case TupleDefinitionType.RemoveIniFile: | ||
459 | set.Add("InstallExecuteSequence/WriteIniValues"); | ||
460 | set.Add("InstallExecuteSequence/RemoveIniValues"); | ||
461 | break; | ||
462 | case TupleDefinitionType.IsolatedComponent: | ||
463 | set.Add("InstallExecuteSequence/IsolateComponents"); | ||
464 | break; | ||
465 | case TupleDefinitionType.LaunchCondition: | ||
466 | set.Add("InstallExecuteSequence/LaunchConditions"); | ||
467 | set.Add("InstallUISequence/LaunchConditions"); | ||
468 | break; | ||
469 | case TupleDefinitionType.MIME: | ||
470 | set.Add("AdvtExecuteSequence/RegisterMIMEInfo"); | ||
471 | set.Add("InstallExecuteSequence/RegisterMIMEInfo"); | ||
472 | set.Add("InstallExecuteSequence/UnregisterMIMEInfo"); | ||
473 | break; | ||
474 | case TupleDefinitionType.MoveFile: | ||
475 | set.Add("InstallExecuteSequence/MoveFiles"); | ||
476 | break; | ||
477 | case TupleDefinitionType.MsiAssembly: | ||
478 | set.Add("AdvtExecuteSequence/MsiPublishAssemblies"); | ||
479 | set.Add("InstallExecuteSequence/MsiPublishAssemblies"); | ||
480 | set.Add("InstallExecuteSequence/MsiUnpublishAssemblies"); | ||
481 | break; | ||
482 | case TupleDefinitionType.MsiServiceConfig: | ||
483 | case TupleDefinitionType.MsiServiceConfigFailureActions: | ||
484 | set.Add("InstallExecuteSequence/MsiConfigureServices"); | ||
485 | break; | ||
486 | case TupleDefinitionType.ODBCDataSource: | ||
487 | case TupleDefinitionType.ODBCTranslator: | ||
488 | case TupleDefinitionType.ODBCDriver: | ||
489 | set.Add("InstallExecuteSequence/SetODBCFolders"); | ||
490 | set.Add("InstallExecuteSequence/InstallODBC"); | ||
491 | set.Add("InstallExecuteSequence/RemoveODBC"); | ||
492 | break; | ||
493 | case TupleDefinitionType.ProgId: | ||
494 | set.Add("AdvtExecuteSequence/RegisterProgIdInfo"); | ||
495 | set.Add("InstallExecuteSequence/RegisterProgIdInfo"); | ||
496 | set.Add("InstallExecuteSequence/UnregisterProgIdInfo"); | ||
497 | break; | ||
498 | case TupleDefinitionType.PublishComponent: | ||
499 | set.Add("AdvtExecuteSequence/PublishComponents"); | ||
500 | set.Add("InstallExecuteSequence/PublishComponents"); | ||
501 | set.Add("InstallExecuteSequence/UnpublishComponents"); | ||
502 | break; | ||
503 | case TupleDefinitionType.Registry: | ||
504 | case TupleDefinitionType.RemoveRegistry: | ||
505 | set.Add("InstallExecuteSequence/WriteRegistryValues"); | ||
506 | set.Add("InstallExecuteSequence/RemoveRegistryValues"); | ||
507 | break; | ||
508 | case TupleDefinitionType.RemoveFile: | ||
509 | set.Add("InstallExecuteSequence/RemoveFiles"); | ||
510 | break; | ||
511 | case TupleDefinitionType.SelfReg: | ||
512 | set.Add("InstallExecuteSequence/SelfRegModules"); | ||
513 | set.Add("InstallExecuteSequence/SelfUnregModules"); | ||
514 | break; | ||
515 | case TupleDefinitionType.ServiceControl: | ||
516 | set.Add("InstallExecuteSequence/StartServices"); | ||
517 | set.Add("InstallExecuteSequence/StopServices"); | ||
518 | set.Add("InstallExecuteSequence/DeleteServices"); | ||
519 | break; | ||
520 | case TupleDefinitionType.ServiceInstall: | ||
521 | set.Add("InstallExecuteSequence/InstallServices"); | ||
522 | break; | ||
523 | case TupleDefinitionType.Shortcut: | ||
524 | set.Add("AdvtExecuteSequence/CreateShortcuts"); | ||
525 | set.Add("InstallExecuteSequence/CreateShortcuts"); | ||
526 | set.Add("InstallExecuteSequence/RemoveShortcuts"); | ||
527 | break; | ||
528 | case TupleDefinitionType.TypeLib: | ||
529 | set.Add("InstallExecuteSequence/RegisterTypeLibraries"); | ||
530 | set.Add("InstallExecuteSequence/UnregisterTypeLibraries"); | ||
531 | break; | ||
532 | case TupleDefinitionType.Upgrade: | ||
533 | set.Add("InstallExecuteSequence/FindRelatedProducts"); | ||
534 | set.Add("InstallUISequence/FindRelatedProducts"); | ||
535 | |||
536 | // Only add the MigrateFeatureStates action if MigrateFeature attribute is set on | ||
537 | // at least one UpgradeVersion element. | ||
538 | if (this.Section.Tuples.OfType<UpgradeTuple>().Any(t => (t.Attributes & MsiInterop.MsidbUpgradeAttributesMigrateFeatures) == MsiInterop.MsidbUpgradeAttributesMigrateFeatures)) | ||
539 | { | ||
540 | set.Add("InstallExecuteSequence/MigrateFeatureStates"); | ||
541 | set.Add("InstallUISequence/MigrateFeatureStates"); | ||
542 | } | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | return set; | ||
548 | } | ||
549 | |||
550 | private IEnumerable<WixActionTuple> GetActions(SequenceTable sequence, string[] actionNames) | ||
551 | { | ||
552 | foreach (var action in WindowsInstallerStandard.StandardActions()) | ||
553 | { | ||
554 | if (action.SequenceTable == sequence && actionNames.Contains(action.Action)) | ||
555 | { | ||
556 | yield return action; | ||
557 | } | ||
558 | } | ||
559 | } | ||
560 | |||
561 | /// <summary> | ||
562 | /// Sequence an action before or after a standard action. | ||
563 | /// </summary> | ||
564 | /// <param name="actionRow">The action row to be sequenced.</param> | ||
565 | /// <param name="requiredActionRows">Collection of actions which must be included.</param> | ||
566 | private void SequenceActionRow(WixActionTuple actionRow, Dictionary<string, WixActionTuple> requiredActionRows) | ||
567 | { | ||
568 | var after = false; | ||
569 | |||
570 | if (actionRow.After != null) | ||
571 | { | ||
572 | after = true; | ||
573 | } | ||
574 | else if (actionRow.Before == null) | ||
575 | { | ||
576 | throw new InvalidOperationException(WixStrings.EXP_FoundActionRowWithNoSequenceBeforeOrAfterColumnSet); | ||
577 | } | ||
578 | |||
579 | var parentActionName = (after ? actionRow.After : actionRow.Before); | ||
580 | var parentActionKey = actionRow.SequenceTable.ToString() + "/" + parentActionName; | ||
581 | |||
582 | if (!requiredActionRows.TryGetValue(parentActionKey, out var parentActionRow)) | ||
583 | { | ||
584 | // If the missing parent action is a standard action (with a suggested sequence number), add it. | ||
585 | if (this.StandardActionsById.TryGetValue(parentActionKey, out parentActionRow)) | ||
586 | { | ||
587 | // Create a clone to avoid modifying the static copy of the object. | ||
588 | // TODO: consider this: parentActionRow = parentActionRow.Clone(); | ||
589 | |||
590 | requiredActionRows.Add(parentActionRow.Id.Id, parentActionRow); | ||
591 | } | ||
592 | else | ||
593 | { | ||
594 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_FoundActionRowWinNonExistentAction, (after ? "After" : "Before"), parentActionName)); | ||
595 | } | ||
596 | } | ||
597 | else if (actionRow == parentActionRow || this.ContainsChildActionRow(actionRow, parentActionRow)) // cycle detected | ||
598 | { | ||
599 | throw new WixException(WixErrors.ActionCircularDependency(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, parentActionRow.Action)); | ||
600 | } | ||
601 | |||
602 | // Add this action to the appropriate list of dependent action rows. | ||
603 | var relativeActions = this.GetRelativeActions(parentActionRow); | ||
604 | var relatedRows = (after ? relativeActions.NextActions : relativeActions.PreviousActions); | ||
605 | relatedRows.Add(actionRow); | ||
606 | } | ||
607 | |||
608 | private bool ContainsChildActionRow(WixActionTuple childTuple, WixActionTuple parentTuple) | ||
609 | { | ||
610 | var result = false; | ||
611 | |||
612 | if (this.RelativeActionsForActions.TryGetValue(childTuple.Id.Id, out var relativeActions)) | ||
613 | { | ||
614 | result = relativeActions.NextActions.Any(a => a.SequenceTable == parentTuple.SequenceTable && a.Id.Id == parentTuple.Id.Id) || | ||
615 | relativeActions.PreviousActions.Any(a => a.SequenceTable == parentTuple.SequenceTable && a.Id.Id == parentTuple.Id.Id); | ||
616 | } | ||
617 | |||
618 | return result; | ||
619 | } | ||
620 | |||
621 | private RelativeActions GetRelativeActions(WixActionTuple action) | ||
622 | { | ||
623 | if (!this.RelativeActionsForActions.TryGetValue(action.Id.Id, out var relativeActions)) | ||
624 | { | ||
625 | relativeActions = new RelativeActions(); | ||
626 | this.RelativeActionsForActions.Add(action.Id.Id, relativeActions); | ||
627 | } | ||
628 | |||
629 | return relativeActions; | ||
630 | } | ||
631 | |||
632 | private RelativeActions GetAllRelativeActionsForSequenceType(SequenceTable sequenceType, WixActionTuple action) | ||
633 | { | ||
634 | var relativeActions = new RelativeActions(); | ||
635 | |||
636 | if (this.RelativeActionsForActions.TryGetValue(action.Id.Id, out var actionRelatives)) | ||
637 | { | ||
638 | this.RecurseRelativeActionsForSequenceType(sequenceType, actionRelatives.PreviousActions, relativeActions.PreviousActions); | ||
639 | |||
640 | this.RecurseRelativeActionsForSequenceType(sequenceType, actionRelatives.NextActions, relativeActions.NextActions); | ||
641 | } | ||
642 | |||
643 | return relativeActions; | ||
644 | } | ||
645 | |||
646 | private void RecurseRelativeActionsForSequenceType(SequenceTable sequenceType, List<WixActionTuple> actions, List<WixActionTuple> visitedActions) | ||
647 | { | ||
648 | foreach (var action in actions.Where(a => a.SequenceTable == sequenceType)) | ||
649 | { | ||
650 | if (this.RelativeActionsForActions.TryGetValue(action.Id.Id, out var actionRelatives)) | ||
651 | { | ||
652 | this.RecurseRelativeActionsForSequenceType(sequenceType, actionRelatives.PreviousActions, visitedActions); | ||
653 | } | ||
654 | |||
655 | visitedActions.Add(action); | ||
656 | |||
657 | if (actionRelatives != null) | ||
658 | { | ||
659 | this.RecurseRelativeActionsForSequenceType(sequenceType, actionRelatives.NextActions, visitedActions); | ||
660 | } | ||
661 | } | ||
662 | } | ||
663 | |||
664 | private class RelativeActions | ||
665 | { | ||
666 | public List<WixActionTuple> PreviousActions { get; } = new List<WixActionTuple>(); | ||
667 | |||
668 | public List<WixActionTuple> NextActions { get; } = new List<WixActionTuple>(); | ||
669 | } | ||
670 | } | ||
671 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateControlTextCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateControlTextCommand.cs index 7da32206..9579e0f8 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateControlTextCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateControlTextCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.IO; | 6 | using System.IO; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 20058597..030bc4cc 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs | |||
@@ -1,10 +1,9 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Databases | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Collections.Specialized; | ||
8 | using System.ComponentModel; | 7 | using System.ComponentModel; |
9 | using System.Globalization; | 8 | using System.Globalization; |
10 | using System.IO; | 9 | using System.IO; |
@@ -14,7 +13,6 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
14 | using WixToolset.Clr.Interop; | 13 | using WixToolset.Clr.Interop; |
15 | using WixToolset.Core.Bind; | 14 | using WixToolset.Core.Bind; |
16 | using WixToolset.Data; | 15 | using WixToolset.Data; |
17 | using WixToolset.Data.Rows; | ||
18 | using WixToolset.Data.Tuples; | 16 | using WixToolset.Data.Tuples; |
19 | using WixToolset.Msi; | 17 | using WixToolset.Msi; |
20 | 18 | ||
@@ -23,13 +21,16 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
23 | /// </summary> | 21 | /// </summary> |
24 | internal class UpdateFileFacadesCommand | 22 | internal class UpdateFileFacadesCommand |
25 | { | 23 | { |
26 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 24 | public UpdateFileFacadesCommand(IntermediateSection section) |
25 | { | ||
26 | this.Section = section; | ||
27 | } | ||
27 | 28 | ||
28 | public IEnumerable<FileFacade> UpdateFileFacades { private get; set; } | 29 | private IntermediateSection Section { get; } |
29 | 30 | ||
30 | public string ModularizationGuid { private get; set; } | 31 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
31 | 32 | ||
32 | public Output Output { private get; set; } | 33 | public IEnumerable<FileFacade> UpdateFileFacades { private get; set; } |
33 | 34 | ||
34 | public bool OverwriteHash { private get; set; } | 35 | public bool OverwriteHash { private get; set; } |
35 | 36 | ||
@@ -47,6 +48,12 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
47 | 48 | ||
48 | private void UpdateFileFacade(FileFacade file) | 49 | private void UpdateFileFacade(FileFacade file) |
49 | { | 50 | { |
51 | var assemblyNameTuples = new Dictionary<string, MsiAssemblyNameTuple>(); | ||
52 | foreach (var assemblyTuple in this.Section.Tuples.OfType<MsiAssemblyNameTuple>()) | ||
53 | { | ||
54 | assemblyNameTuples.Add(assemblyTuple.Component_ + "/" + assemblyTuple.Name, assemblyTuple); | ||
55 | } | ||
56 | |||
50 | FileInfo fileInfo = null; | 57 | FileInfo fileInfo = null; |
51 | try | 58 | try |
52 | { | 59 | { |
@@ -149,9 +156,8 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
149 | 156 | ||
150 | if (null == file.Hash) | 157 | if (null == file.Hash) |
151 | { | 158 | { |
152 | //Table msiFileHashTable = this.Output.EnsureTable(this.TableDefinitions["MsiFileHash"]); | 159 | file.Hash = new MsiFileHashTuple(file.File.SourceLineNumbers, file.File.Id); |
153 | //file.Hash = msiFileHashTable.CreateRow(file.File.SourceLineNumbers); | 160 | this.Section.Tuples.Add(file.Hash); |
154 | throw new NotImplementedException(); | ||
155 | } | 161 | } |
156 | 162 | ||
157 | file.Hash.File_ = file.File.File; | 163 | file.Hash.File_ = file.File.File; |
@@ -198,13 +204,13 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
198 | { | 204 | { |
199 | if (!String.IsNullOrEmpty(file.File.Version)) | 205 | if (!String.IsNullOrEmpty(file.File.Version)) |
200 | { | 206 | { |
201 | string key = String.Format(CultureInfo.InvariantCulture, "fileversion.{0}", Common.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)); | 207 | var key = String.Format(CultureInfo.InvariantCulture, "fileversion.{0}", file.File.File); |
202 | this.VariableCache[key] = file.File.Version; | 208 | this.VariableCache[key] = file.File.Version; |
203 | } | 209 | } |
204 | 210 | ||
205 | if (!String.IsNullOrEmpty(file.File.Language)) | 211 | if (!String.IsNullOrEmpty(file.File.Language)) |
206 | { | 212 | { |
207 | string key = String.Format(CultureInfo.InvariantCulture, "filelanguage.{0}", Common.Demodularize(this.Output.Type, ModularizationGuid, file.File.File)); | 213 | var key = String.Format(CultureInfo.InvariantCulture, "filelanguage.{0}", file.File.File); |
208 | this.VariableCache[key] = file.File.Language; | 214 | this.VariableCache[key] = file.File.Language; |
209 | } | 215 | } |
210 | } | 216 | } |
@@ -214,14 +220,13 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
214 | if (FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType) | 220 | if (FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType) |
215 | { | 221 | { |
216 | bool targetNetfx1 = false; | 222 | bool targetNetfx1 = false; |
217 | StringDictionary assemblyNameValues = new StringDictionary(); | 223 | var assemblyNameValues = new Dictionary<string, string>(); |
218 | 224 | ||
219 | ClrInterop.IReferenceIdentity referenceIdentity = null; | ||
220 | Guid referenceIdentityGuid = ClrInterop.ReferenceIdentityGuid; | 225 | Guid referenceIdentityGuid = ClrInterop.ReferenceIdentityGuid; |
221 | uint result = ClrInterop.GetAssemblyIdentityFromFile(fileInfo.FullName, ref referenceIdentityGuid, out referenceIdentity); | 226 | var result = ClrInterop.GetAssemblyIdentityFromFile(fileInfo.FullName, ref referenceIdentityGuid, out var referenceIdentity); |
222 | if (0 == result && null != referenceIdentity) | 227 | if (0 == result && null != referenceIdentity) |
223 | { | 228 | { |
224 | string imageRuntimeVersion = referenceIdentity.GetAttribute(null, "ImageRuntimeVersion"); | 229 | var imageRuntimeVersion = referenceIdentity.GetAttribute(null, "ImageRuntimeVersion"); |
225 | if (null != imageRuntimeVersion) | 230 | if (null != imageRuntimeVersion) |
226 | { | 231 | { |
227 | targetNetfx1 = imageRuntimeVersion.StartsWith("v1", StringComparison.OrdinalIgnoreCase); | 232 | targetNetfx1 = imageRuntimeVersion.StartsWith("v1", StringComparison.OrdinalIgnoreCase); |
@@ -269,15 +274,14 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
269 | return; | 274 | return; |
270 | } | 275 | } |
271 | 276 | ||
272 | Table assemblyNameTable = this.Output.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); | 277 | if (assemblyNameValues.TryGetValue("name", out var value)) |
273 | if (assemblyNameValues.ContainsKey("name")) | ||
274 | { | 278 | { |
275 | this.SetMsiAssemblyName(assemblyNameTable, file, "name", assemblyNameValues["name"]); | 279 | this.SetMsiAssemblyName(assemblyNameTuples, file, "name", value); |
276 | } | 280 | } |
277 | 281 | ||
278 | if (!String.IsNullOrEmpty(version)) | 282 | if (!String.IsNullOrEmpty(version)) |
279 | { | 283 | { |
280 | this.SetMsiAssemblyName(assemblyNameTable, file, "fileVersion", version); | 284 | this.SetMsiAssemblyName(assemblyNameTuples, file, "fileVersion", version); |
281 | } | 285 | } |
282 | 286 | ||
283 | if (assemblyNameValues.ContainsKey("version")) | 287 | if (assemblyNameValues.ContainsKey("version")) |
@@ -303,33 +307,33 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
303 | } | 307 | } |
304 | } | 308 | } |
305 | 309 | ||
306 | this.SetMsiAssemblyName(assemblyNameTable, file, "version", assemblyVersion); | 310 | this.SetMsiAssemblyName(assemblyNameTuples, file, "version", assemblyVersion); |
307 | } | 311 | } |
308 | 312 | ||
309 | if (assemblyNameValues.ContainsKey("culture")) | 313 | if (assemblyNameValues.ContainsKey("culture")) |
310 | { | 314 | { |
311 | this.SetMsiAssemblyName(assemblyNameTable, file, "culture", assemblyNameValues["culture"]); | 315 | this.SetMsiAssemblyName(assemblyNameTuples, file, "culture", assemblyNameValues["culture"]); |
312 | } | 316 | } |
313 | 317 | ||
314 | if (assemblyNameValues.ContainsKey("publicKeyToken")) | 318 | if (assemblyNameValues.ContainsKey("publicKeyToken")) |
315 | { | 319 | { |
316 | this.SetMsiAssemblyName(assemblyNameTable, file, "publicKeyToken", assemblyNameValues["publicKeyToken"]); | 320 | this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", assemblyNameValues["publicKeyToken"]); |
317 | } | 321 | } |
318 | 322 | ||
319 | if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) | 323 | if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) |
320 | { | 324 | { |
321 | this.SetMsiAssemblyName(assemblyNameTable, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); | 325 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); |
322 | } | 326 | } |
323 | 327 | ||
324 | if (assemblyNameValues.ContainsKey("processorArchitecture")) | 328 | if (assemblyNameValues.ContainsKey("processorArchitecture")) |
325 | { | 329 | { |
326 | this.SetMsiAssemblyName(assemblyNameTable, file, "processorArchitecture", assemblyNameValues["processorArchitecture"]); | 330 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", assemblyNameValues["processorArchitecture"]); |
327 | } | 331 | } |
328 | 332 | ||
329 | // add the assembly name to the information cache | 333 | // add the assembly name to the information cache |
330 | if (null != this.VariableCache) | 334 | if (null != this.VariableCache) |
331 | { | 335 | { |
332 | string fileId = Common.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File); | 336 | string fileId = file.File.File; |
333 | string key = String.Concat("assemblyfullname.", fileId); | 337 | string key = String.Concat("assemblyfullname.", fileId); |
334 | string assemblyName = String.Concat(assemblyNameValues["name"], ", version=", assemblyNameValues["version"], ", culture=", assemblyNameValues["culture"], ", publicKeyToken=", String.IsNullOrEmpty(assemblyNameValues["publicKeyToken"]) ? "null" : assemblyNameValues["publicKeyToken"]); | 338 | string assemblyName = String.Concat(assemblyNameValues["name"], ", version=", assemblyNameValues["version"], ", culture=", assemblyNameValues["culture"], ", publicKeyToken=", String.IsNullOrEmpty(assemblyNameValues["publicKeyToken"]) ? "null" : assemblyNameValues["publicKeyToken"]); |
335 | if (assemblyNameValues.ContainsKey("processorArchitecture")) | 339 | if (assemblyNameValues.ContainsKey("processorArchitecture")) |
@@ -437,30 +441,29 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
437 | Messaging.Instance.OnMessage(WixErrors.InvalidXml(new SourceLineNumber(fileManifest.WixFile.Source), "manifest", xe.Message)); | 441 | Messaging.Instance.OnMessage(WixErrors.InvalidXml(new SourceLineNumber(fileManifest.WixFile.Source), "manifest", xe.Message)); |
438 | } | 442 | } |
439 | 443 | ||
440 | Table assemblyNameTable = this.Output.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); | ||
441 | if (!String.IsNullOrEmpty(win32Name)) | 444 | if (!String.IsNullOrEmpty(win32Name)) |
442 | { | 445 | { |
443 | this.SetMsiAssemblyName(assemblyNameTable, file, "name", win32Name); | 446 | this.SetMsiAssemblyName(assemblyNameTuples, file, "name", win32Name); |
444 | } | 447 | } |
445 | 448 | ||
446 | if (!String.IsNullOrEmpty(win32Version)) | 449 | if (!String.IsNullOrEmpty(win32Version)) |
447 | { | 450 | { |
448 | this.SetMsiAssemblyName(assemblyNameTable, file, "version", win32Version); | 451 | this.SetMsiAssemblyName(assemblyNameTuples, file, "version", win32Version); |
449 | } | 452 | } |
450 | 453 | ||
451 | if (!String.IsNullOrEmpty(win32Type)) | 454 | if (!String.IsNullOrEmpty(win32Type)) |
452 | { | 455 | { |
453 | this.SetMsiAssemblyName(assemblyNameTable, file, "type", win32Type); | 456 | this.SetMsiAssemblyName(assemblyNameTuples, file, "type", win32Type); |
454 | } | 457 | } |
455 | 458 | ||
456 | if (!String.IsNullOrEmpty(win32ProcessorArchitecture)) | 459 | if (!String.IsNullOrEmpty(win32ProcessorArchitecture)) |
457 | { | 460 | { |
458 | this.SetMsiAssemblyName(assemblyNameTable, file, "processorArchitecture", win32ProcessorArchitecture); | 461 | this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", win32ProcessorArchitecture); |
459 | } | 462 | } |
460 | 463 | ||
461 | if (!String.IsNullOrEmpty(win32PublicKeyToken)) | 464 | if (!String.IsNullOrEmpty(win32PublicKeyToken)) |
462 | { | 465 | { |
463 | this.SetMsiAssemblyName(assemblyNameTable, file, "publicKeyToken", win32PublicKeyToken); | 466 | this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", win32PublicKeyToken); |
464 | } | 467 | } |
465 | } | 468 | } |
466 | } | 469 | } |
@@ -469,11 +472,11 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
469 | /// Set an MsiAssemblyName row. If it was directly authored, override the value, otherwise | 472 | /// Set an MsiAssemblyName row. If it was directly authored, override the value, otherwise |
470 | /// create a new row. | 473 | /// create a new row. |
471 | /// </summary> | 474 | /// </summary> |
472 | /// <param name="assemblyNameTable">MsiAssemblyName table.</param> | 475 | /// <param name="assemblyNameTuples">MsiAssemblyName table.</param> |
473 | /// <param name="file">FileFacade containing the assembly read for the MsiAssemblyName row.</param> | 476 | /// <param name="file">FileFacade containing the assembly read for the MsiAssemblyName row.</param> |
474 | /// <param name="name">MsiAssemblyName name.</param> | 477 | /// <param name="name">MsiAssemblyName name.</param> |
475 | /// <param name="value">MsiAssemblyName value.</param> | 478 | /// <param name="value">MsiAssemblyName value.</param> |
476 | private void SetMsiAssemblyName(Table assemblyNameTable, FileFacade file, string name, string value) | 479 | private void SetMsiAssemblyName(Dictionary<string, MsiAssemblyNameTuple> assemblyNameTuples, FileFacade file, string name, string value) |
477 | { | 480 | { |
478 | // check for null value (this can occur when grabbing the file version from an assembly without one) | 481 | // check for null value (this can occur when grabbing the file version from an assembly without one) |
479 | if (String.IsNullOrEmpty(value)) | 482 | if (String.IsNullOrEmpty(value)) |
@@ -482,18 +485,6 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
482 | } | 485 | } |
483 | else | 486 | else |
484 | { | 487 | { |
485 | Row assemblyNameRow = null; | ||
486 | |||
487 | // override directly authored value | ||
488 | foreach (Row row in assemblyNameTable.Rows) | ||
489 | { | ||
490 | if ((string)row[0] == file.File.Component_ && (string)row[1] == name) | ||
491 | { | ||
492 | assemblyNameRow = row; | ||
493 | break; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. | 488 | // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. |
498 | if ("name" == name && FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType && | 489 | if ("name" == name && FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType && |
499 | String.IsNullOrEmpty(file.WixFile.File_AssemblyApplication) && | 490 | String.IsNullOrEmpty(file.WixFile.File_AssemblyApplication) && |
@@ -502,17 +493,14 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
502 | Messaging.Instance.OnMessage(WixErrors.GACAssemblyIdentityWarning(file.File.SourceLineNumbers, Path.GetFileNameWithoutExtension(file.File.LongFileName), value)); | 493 | Messaging.Instance.OnMessage(WixErrors.GACAssemblyIdentityWarning(file.File.SourceLineNumbers, Path.GetFileNameWithoutExtension(file.File.LongFileName), value)); |
503 | } | 494 | } |
504 | 495 | ||
505 | if (null == assemblyNameRow) | 496 | // override directly authored value |
497 | var lookup = String.Concat(file.File.Component_, "/", name); | ||
498 | if (assemblyNameTuples.TryGetValue(lookup, out var assemblyNameRow)) | ||
506 | { | 499 | { |
507 | throw new NotImplementedException(); | 500 | assemblyNameRow = new MsiAssemblyNameTuple(file.File.SourceLineNumbers); |
508 | #if TODO | 501 | assemblyNameRow.Component_ = file.File.Component_; |
509 | assemblyNameRow = assemblyNameTable.CreateRow(file.File.SourceLineNumbers); | 502 | assemblyNameRow.Name = name; |
510 | assemblyNameRow[0] = file.File.Component_; | 503 | assemblyNameRow.Value = value; |
511 | assemblyNameRow[1] = name; | ||
512 | assemblyNameRow[2] = value; | ||
513 | |||
514 | // put the MsiAssemblyName row in the same section as the related File row | ||
515 | assemblyNameRow.SectionId = file.File.SectionId; | ||
516 | 504 | ||
517 | if (null == file.AssemblyNames) | 505 | if (null == file.AssemblyNames) |
518 | { | 506 | { |
@@ -520,17 +508,15 @@ namespace WixToolset.Core.WindowsInstaller.Databases | |||
520 | } | 508 | } |
521 | 509 | ||
522 | file.AssemblyNames.Add(assemblyNameRow); | 510 | file.AssemblyNames.Add(assemblyNameRow); |
523 | #endif | 511 | this.Section.Tuples.Add(assemblyNameRow); |
524 | } | ||
525 | else | ||
526 | { | ||
527 | assemblyNameRow[2] = value; | ||
528 | } | 512 | } |
529 | 513 | ||
514 | assemblyNameRow.Value = value; | ||
515 | |||
530 | if (this.VariableCache != null) | 516 | if (this.VariableCache != null) |
531 | { | 517 | { |
532 | string key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, Common.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)).ToLowerInvariant(); | 518 | var key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, file.File.File).ToLowerInvariant(); |
533 | this.VariableCache[key] = (string)assemblyNameRow[2]; | 519 | this.VariableCache[key] = value; |
534 | } | 520 | } |
535 | } | 521 | } |
536 | } | 522 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs new file mode 100644 index 00000000..db74eda5 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs | |||
@@ -0,0 +1,126 @@ | |||
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 | namespace WixToolset.Core.WindowsInstaller.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Linq; | ||
8 | using WixToolset.Core.Bind; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Data.Rows; | ||
11 | using WixToolset.Data.Tuples; | ||
12 | |||
13 | internal class UpdateMediaSequencesCommand | ||
14 | { | ||
15 | public UpdateMediaSequencesCommand(Output output, List<FileFacade> fileFacades, Dictionary<int, MediaTuple> assignedMediaRows) | ||
16 | { | ||
17 | this.Output = output; | ||
18 | this.FileFacades = fileFacades; | ||
19 | } | ||
20 | |||
21 | private Output Output { get; } | ||
22 | |||
23 | private List<FileFacade> FileFacades { get; } | ||
24 | |||
25 | public void Execute() | ||
26 | { | ||
27 | var fileRows = new RowDictionary<FileRow>(this.Output.Tables["File"]); | ||
28 | var mediaRows = new RowDictionary<MediaRow>(this.Output.Tables["Media"]); | ||
29 | |||
30 | // Calculate sequence numbers and media disk id layout for all file media information objects. | ||
31 | if (OutputType.Module == this.Output.Type) | ||
32 | { | ||
33 | var lastSequence = 0; | ||
34 | |||
35 | // Order by Component to group the files by directory. | ||
36 | var optimized = this.OptimizedFileFacades(); | ||
37 | foreach (var fileId in optimized.Select(f => f.File.File)) | ||
38 | { | ||
39 | var fileRow = fileRows.Get(fileId); | ||
40 | fileRow.Sequence = ++lastSequence; | ||
41 | } | ||
42 | } | ||
43 | else | ||
44 | { | ||
45 | int lastSequence = 0; | ||
46 | MediaRow mediaRow = null; | ||
47 | Dictionary<int, List<FileFacade>> patchGroups = new Dictionary<int, List<FileFacade>>(); | ||
48 | |||
49 | // sequence the non-patch-added files | ||
50 | var optimized = this.OptimizedFileFacades(); | ||
51 | foreach (FileFacade facade in optimized) | ||
52 | { | ||
53 | if (null == mediaRow) | ||
54 | { | ||
55 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
56 | if (OutputType.Patch == this.Output.Type) | ||
57 | { | ||
58 | // patch Media cannot start at zero | ||
59 | lastSequence = mediaRow.LastSequence; | ||
60 | } | ||
61 | } | ||
62 | else if (mediaRow.DiskId != facade.WixFile.DiskId) | ||
63 | { | ||
64 | mediaRow.LastSequence = lastSequence; | ||
65 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
66 | } | ||
67 | |||
68 | if (0 < facade.WixFile.PatchGroup) | ||
69 | { | ||
70 | if (patchGroups.TryGetValue(facade.WixFile.PatchGroup, out var patchGroup)) | ||
71 | { | ||
72 | patchGroup = new List<FileFacade>(); | ||
73 | patchGroups.Add(facade.WixFile.PatchGroup, patchGroup); | ||
74 | } | ||
75 | |||
76 | patchGroup.Add(facade); | ||
77 | } | ||
78 | else | ||
79 | { | ||
80 | var fileRow = fileRows.Get(facade.File.File); | ||
81 | fileRow.Sequence = ++lastSequence; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | if (null != mediaRow) | ||
86 | { | ||
87 | mediaRow.LastSequence = lastSequence; | ||
88 | mediaRow = null; | ||
89 | } | ||
90 | |||
91 | // sequence the patch-added files | ||
92 | foreach (var patchGroup in patchGroups.Values) | ||
93 | { | ||
94 | foreach (var facade in patchGroup) | ||
95 | { | ||
96 | if (null == mediaRow) | ||
97 | { | ||
98 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
99 | } | ||
100 | else if (mediaRow.DiskId != facade.WixFile.DiskId) | ||
101 | { | ||
102 | mediaRow.LastSequence = lastSequence; | ||
103 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
104 | } | ||
105 | |||
106 | var fileRow = fileRows.Get(facade.File.File); | ||
107 | fileRow.Sequence = ++lastSequence; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | if (null != mediaRow) | ||
112 | { | ||
113 | mediaRow.LastSequence = lastSequence; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | private IEnumerable<FileFacade> OptimizedFileFacades() | ||
119 | { | ||
120 | // TODO: Sort these facades even smarter by directory path and component id | ||
121 | // and maybe file size or file extension and other creative ideas to | ||
122 | // get optimal install speed out of MSI. | ||
123 | return this.FileFacades.OrderBy(f => f.File.Component_); | ||
124 | } | ||
125 | } | ||
126 | } | ||