diff options
author | Rob Mensching <rob@firegiant.com> | 2017-10-14 16:12:07 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2017-10-14 16:12:07 -0700 |
commit | dbde9e7104b907bbbaea17e21247d8cafc8b3a4c (patch) | |
tree | 0f5fbbb6fe12c6b2e5e622a0e18ce4c5b4eb2b96 /src/WixToolset.Core/Bind/BindDatabaseCommand.cs | |
parent | fbf986eb97f68396797a89fc7d40dec07b775440 (diff) | |
download | wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.tar.gz wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.tar.bz2 wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.zip |
Massive refactoring to introduce the concept of IBackend
Diffstat (limited to 'src/WixToolset.Core/Bind/BindDatabaseCommand.cs')
-rw-r--r-- | src/WixToolset.Core/Bind/BindDatabaseCommand.cs | 1311 |
1 files changed, 0 insertions, 1311 deletions
diff --git a/src/WixToolset.Core/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core/Bind/BindDatabaseCommand.cs deleted file mode 100644 index 93af2e9a..00000000 --- a/src/WixToolset.Core/Bind/BindDatabaseCommand.cs +++ /dev/null | |||
@@ -1,1311 +0,0 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | namespace WixToolset.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Diagnostics; | ||
9 | using System.Globalization; | ||
10 | using System.IO; | ||
11 | using System.Linq; | ||
12 | using WixToolset.Bind.Databases; | ||
13 | using WixToolset.Data; | ||
14 | using WixToolset.Data.Rows; | ||
15 | using WixToolset.Extensibility; | ||
16 | using WixToolset.Msi; | ||
17 | |||
18 | /// <summary> | ||
19 | /// Binds a databse. | ||
20 | /// </summary> | ||
21 | internal class BindDatabaseCommand : ICommand | ||
22 | { | ||
23 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. | ||
24 | private static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); | ||
25 | |||
26 | public int Codepage { private get; set; } | ||
27 | |||
28 | public int CabbingThreadCount { private get; set; } | ||
29 | |||
30 | public CompressionLevel DefaultCompressionLevel { private get; set; } | ||
31 | |||
32 | public bool DeltaBinaryPatch { get; set; } | ||
33 | |||
34 | public IEnumerable<IBinderExtension> Extensions { private get; set; } | ||
35 | |||
36 | public BinderFileManagerCore FileManagerCore { private get; set; } | ||
37 | |||
38 | public IEnumerable<IBinderFileManager> FileManagers { private get; set; } | ||
39 | |||
40 | public IEnumerable<InspectorExtension> InspectorExtensions { private get; set; } | ||
41 | |||
42 | public Localizer Localizer { private get; set; } | ||
43 | |||
44 | public string PdbFile { private get; set; } | ||
45 | |||
46 | public Output Output { private get; set; } | ||
47 | |||
48 | public string OutputPath { private get; set; } | ||
49 | |||
50 | public bool SuppressAddingValidationRows { private get; set; } | ||
51 | |||
52 | public bool SuppressLayout { private get; set; } | ||
53 | |||
54 | public TableDefinitionCollection TableDefinitions { private get; set; } | ||
55 | |||
56 | public string TempFilesLocation { private get; set; } | ||
57 | |||
58 | public Validator Validator { private get; set; } | ||
59 | |||
60 | public WixVariableResolver WixVariableResolver { private get; set; } | ||
61 | |||
62 | public IEnumerable<FileTransfer> FileTransfers { get; private set; } | ||
63 | |||
64 | public IEnumerable<string> ContentFilePaths { get; private set; } | ||
65 | |||
66 | public void Execute() | ||
67 | { | ||
68 | List<FileTransfer> fileTransfers = new List<FileTransfer>(); | ||
69 | |||
70 | HashSet<string> suppressedTableNames = new HashSet<string>(); | ||
71 | |||
72 | // Localize fields, resolve wix variables, and resolve file paths. | ||
73 | ExtractEmbeddedFiles filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); | ||
74 | |||
75 | IEnumerable<DelayedField> delayedFields; | ||
76 | { | ||
77 | ResolveFieldsCommand command = new ResolveFieldsCommand(); | ||
78 | command.Tables = this.Output.Tables; | ||
79 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
80 | command.FileManagerCore = this.FileManagerCore; | ||
81 | command.FileManagers = this.FileManagers; | ||
82 | command.SupportDelayedResolution = true; | ||
83 | command.TempFilesLocation = this.TempFilesLocation; | ||
84 | command.WixVariableResolver = this.WixVariableResolver; | ||
85 | command.Execute(); | ||
86 | |||
87 | delayedFields = command.DelayedFields; | ||
88 | } | ||
89 | |||
90 | if (OutputType.Patch == this.Output.Type) | ||
91 | { | ||
92 | foreach (SubStorage transform in this.Output.SubStorages) | ||
93 | { | ||
94 | ResolveFieldsCommand command = new ResolveFieldsCommand(); | ||
95 | command.Tables = transform.Data.Tables; | ||
96 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
97 | command.FileManagerCore = this.FileManagerCore; | ||
98 | command.FileManagers = this.FileManagers; | ||
99 | command.SupportDelayedResolution = false; | ||
100 | command.TempFilesLocation = this.TempFilesLocation; | ||
101 | command.WixVariableResolver = this.WixVariableResolver; | ||
102 | command.Execute(); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | // If there are any fields to resolve later, create the cache to populate during bind. | ||
107 | IDictionary<string, string> variableCache = null; | ||
108 | if (delayedFields.Any()) | ||
109 | { | ||
110 | variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); | ||
111 | } | ||
112 | |||
113 | this.LocalizeUI(this.Output.Tables); | ||
114 | |||
115 | // Process the summary information table before the other tables. | ||
116 | bool compressed; | ||
117 | bool longNames; | ||
118 | int installerVersion; | ||
119 | string modularizationGuid; | ||
120 | { | ||
121 | BindSummaryInfoCommand command = new BindSummaryInfoCommand(); | ||
122 | command.Output = this.Output; | ||
123 | command.Execute(); | ||
124 | |||
125 | compressed = command.Compressed; | ||
126 | longNames = command.LongNames; | ||
127 | installerVersion = command.InstallerVersion; | ||
128 | modularizationGuid = command.ModularizationGuid; | ||
129 | } | ||
130 | |||
131 | // Stop processing if an error previously occurred. | ||
132 | if (Messaging.Instance.EncounteredError) | ||
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 | { | ||
140 | // Gather all the suppress modularization identifiers | ||
141 | HashSet<string> suppressModularizationIdentifiers = null; | ||
142 | Table wixSuppressModularizationTable = this.Output.Tables["WixSuppressModularization"]; | ||
143 | if (null != wixSuppressModularizationTable) | ||
144 | { | ||
145 | suppressModularizationIdentifiers = new HashSet<string>(wixSuppressModularizationTable.Rows.Select(row => (string)row[0])); | ||
146 | } | ||
147 | |||
148 | foreach (Table table in this.Output.Tables) | ||
149 | { | ||
150 | table.Modularize(modularizationGuid, suppressModularizationIdentifiers); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | // This must occur after all variables and source paths have been resolved and after modularization. | ||
155 | List<FileFacade> fileFacades; | ||
156 | { | ||
157 | GetFileFacadesCommand command = new GetFileFacadesCommand(); | ||
158 | command.FileTable = this.Output.Tables["File"]; | ||
159 | command.WixFileTable = this.Output.Tables["WixFile"]; | ||
160 | command.WixDeltaPatchFileTable = this.Output.Tables["WixDeltaPatchFile"]; | ||
161 | command.WixDeltaPatchSymbolPathsTable = this.Output.Tables["WixDeltaPatchSymbolPaths"]; | ||
162 | command.Execute(); | ||
163 | |||
164 | fileFacades = command.FileFacades; | ||
165 | } | ||
166 | |||
167 | ////if (OutputType.Patch == this.Output.Type) | ||
168 | ////{ | ||
169 | //// foreach (SubStorage substorage in this.Output.SubStorages) | ||
170 | //// { | ||
171 | //// Output transform = substorage.Data; | ||
172 | |||
173 | //// ResolveFieldsCommand command = new ResolveFieldsCommand(); | ||
174 | //// command.Tables = transform.Tables; | ||
175 | //// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
176 | //// command.FileManagerCore = this.FileManagerCore; | ||
177 | //// command.FileManagers = this.FileManagers; | ||
178 | //// command.SupportDelayedResolution = false; | ||
179 | //// command.TempFilesLocation = this.TempFilesLocation; | ||
180 | //// command.WixVariableResolver = this.WixVariableResolver; | ||
181 | //// command.Execute(); | ||
182 | |||
183 | //// this.MergeUnrealTables(transform.Tables); | ||
184 | //// } | ||
185 | ////} | ||
186 | |||
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 | |||
194 | if (Messaging.Instance.EncounteredError) | ||
195 | { | ||
196 | return; | ||
197 | } | ||
198 | |||
199 | // Add binder variables for all properties. | ||
200 | Table propertyTable = this.Output.Tables["Property"]; | ||
201 | if (null != propertyTable) | ||
202 | { | ||
203 | foreach (PropertyRow propertyRow in propertyTable.Rows) | ||
204 | { | ||
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 | |||
210 | // Update the target ProductCode in any instance transforms. | ||
211 | foreach (SubStorage subStorage in this.Output.SubStorages) | ||
212 | { | ||
213 | Output subStorageOutput = subStorage.Data; | ||
214 | if (OutputType.Transform != subStorageOutput.Type) | ||
215 | { | ||
216 | continue; | ||
217 | } | ||
218 | |||
219 | Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; | ||
220 | foreach (Row row in instanceSummaryInformationTable.Rows) | ||
221 | { | ||
222 | if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0)) | ||
223 | { | ||
224 | row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value); | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | // Add the property name and value to the variableCache. | ||
232 | if (null != variableCache) | ||
233 | { | ||
234 | string key = String.Concat("property.", Demodularize(this.Output.Type, modularizationGuid, propertyRow.Property)); | ||
235 | variableCache[key] = propertyRow.Value; | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | // Extract files that come from cabinet files (this does not extract files from merge modules). | ||
241 | { | ||
242 | ExtractEmbeddedFilesCommand command = new ExtractEmbeddedFilesCommand(); | ||
243 | command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; | ||
244 | command.Execute(); | ||
245 | } | ||
246 | |||
247 | if (OutputType.Product == this.Output.Type) | ||
248 | { | ||
249 | // Retrieve files and their information from merge modules. | ||
250 | Table wixMergeTable = this.Output.Tables["WixMerge"]; | ||
251 | |||
252 | if (null != wixMergeTable) | ||
253 | { | ||
254 | ExtractMergeModuleFilesCommand command = new ExtractMergeModuleFilesCommand(); | ||
255 | 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; | ||
260 | command.SuppressLayout = this.SuppressLayout; | ||
261 | command.TempFilesLocation = this.TempFilesLocation; | ||
262 | command.Execute(); | ||
263 | |||
264 | fileFacades.AddRange(command.MergeModulesFileFacades); | ||
265 | } | ||
266 | } | ||
267 | else if (OutputType.Patch == this.Output.Type) | ||
268 | { | ||
269 | // Merge transform data into the output object. | ||
270 | IEnumerable<FileFacade> filesFromTransform = this.CopyFromTransformData(this.Output); | ||
271 | |||
272 | fileFacades.AddRange(filesFromTransform); | ||
273 | } | ||
274 | |||
275 | // stop processing if an error previously occurred | ||
276 | if (Messaging.Instance.EncounteredError) | ||
277 | { | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | Messaging.Instance.OnMessage(WixVerboses.UpdatingFileInformation()); | ||
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. | ||
300 | this.CreateInstanceTransforms(this.Output); | ||
301 | |||
302 | this.ValidateComponentGuids(this.Output); | ||
303 | |||
304 | this.UpdateControlText(this.Output); | ||
305 | |||
306 | if (delayedFields.Any()) | ||
307 | { | ||
308 | ResolveDelayedFieldsCommand command = new ResolveDelayedFieldsCommand(); | ||
309 | command.OutputType = this.Output.Type; | ||
310 | command.DelayedFields = delayedFields; | ||
311 | command.ModularizationGuid = null; | ||
312 | command.VariableCache = variableCache; | ||
313 | command.Execute(); | ||
314 | } | ||
315 | |||
316 | // Assign files to media. | ||
317 | RowDictionary<MediaRow> assignedMediaRows; | ||
318 | Dictionary<MediaRow, IEnumerable<FileFacade>> filesByCabinetMedia; | ||
319 | IEnumerable<FileFacade> uncompressedFiles; | ||
320 | { | ||
321 | AssignMediaCommand command = new AssignMediaCommand(); | ||
322 | command.FilesCompressed = compressed; | ||
323 | command.FileFacades = fileFacades; | ||
324 | command.Output = this.Output; | ||
325 | command.TableDefinitions = this.TableDefinitions; | ||
326 | command.Execute(); | ||
327 | |||
328 | assignedMediaRows = command.MediaRows; | ||
329 | filesByCabinetMedia = command.FileFacadesByCabinetMedia; | ||
330 | uncompressedFiles = command.UncompressedFileFacades; | ||
331 | } | ||
332 | |||
333 | // Update file sequence. | ||
334 | this.UpdateMediaSequences(this.Output.Type, fileFacades, assignedMediaRows); | ||
335 | |||
336 | // stop processing if an error previously occurred | ||
337 | if (Messaging.Instance.EncounteredError) | ||
338 | { | ||
339 | return; | ||
340 | } | ||
341 | |||
342 | // Extended binder extensions can be called now that fields are resolved. | ||
343 | { | ||
344 | Table updatedFiles = this.Output.EnsureTable(this.TableDefinitions["WixBindUpdatedFiles"]); | ||
345 | |||
346 | foreach (BinderExtension extension in this.Extensions) | ||
347 | { | ||
348 | extension.AfterResolvedFields(this.Output); | ||
349 | } | ||
350 | |||
351 | List<FileFacade> updatedFileFacades = new List<FileFacade>(); | ||
352 | |||
353 | foreach (Row updatedFile in updatedFiles.Rows) | ||
354 | { | ||
355 | string updatedId = updatedFile.FieldAsString(0); | ||
356 | |||
357 | FileFacade updatedFacade = fileFacades.First(f => f.File.File.Equals(updatedId)); | ||
358 | |||
359 | updatedFileFacades.Add(updatedFacade); | ||
360 | } | ||
361 | |||
362 | if (updatedFileFacades.Any()) | ||
363 | { | ||
364 | UpdateFileFacadesCommand command = new UpdateFileFacadesCommand(); | ||
365 | command.FileFacades = fileFacades; | ||
366 | command.UpdateFileFacades = updatedFileFacades; | ||
367 | command.ModularizationGuid = modularizationGuid; | ||
368 | command.Output = this.Output; | ||
369 | command.OverwriteHash = true; | ||
370 | command.TableDefinitions = this.TableDefinitions; | ||
371 | command.VariableCache = variableCache; | ||
372 | command.Execute(); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | // stop processing if an error previously occurred | ||
377 | if (Messaging.Instance.EncounteredError) | ||
378 | { | ||
379 | return; | ||
380 | } | ||
381 | |||
382 | Directory.CreateDirectory(this.TempFilesLocation); | ||
383 | |||
384 | if (OutputType.Patch == this.Output.Type && this.DeltaBinaryPatch) | ||
385 | { | ||
386 | CreateDeltaPatchesCommand command = new CreateDeltaPatchesCommand(); | ||
387 | command.FileFacades = fileFacades; | ||
388 | command.WixPatchIdTable = this.Output.Tables["WixPatchId"]; | ||
389 | command.TempFilesLocation = this.TempFilesLocation; | ||
390 | command.Execute(); | ||
391 | } | ||
392 | |||
393 | // create cabinet files and process uncompressed files | ||
394 | string layoutDirectory = Path.GetDirectoryName(this.OutputPath); | ||
395 | if (!this.SuppressLayout || OutputType.Module == this.Output.Type) | ||
396 | { | ||
397 | Messaging.Instance.OnMessage(WixVerboses.CreatingCabinetFiles()); | ||
398 | |||
399 | CreateCabinetsCommand command = new CreateCabinetsCommand(); | ||
400 | command.CabbingThreadCount = this.CabbingThreadCount; | ||
401 | command.DefaultCompressionLevel = this.DefaultCompressionLevel; | ||
402 | command.Output = this.Output; | ||
403 | command.FileManagers = this.FileManagers; | ||
404 | command.LayoutDirectory = layoutDirectory; | ||
405 | command.Compressed = compressed; | ||
406 | command.FileRowsByCabinet = filesByCabinetMedia; | ||
407 | command.ResolveMedia = this.ResolveMedia; | ||
408 | command.TableDefinitions = this.TableDefinitions; | ||
409 | command.TempFilesLocation = this.TempFilesLocation; | ||
410 | command.WixMediaTable = this.Output.Tables["WixMedia"]; | ||
411 | command.Execute(); | ||
412 | |||
413 | fileTransfers.AddRange(command.FileTransfers); | ||
414 | } | ||
415 | |||
416 | if (OutputType.Patch == this.Output.Type) | ||
417 | { | ||
418 | // copy output data back into the transforms | ||
419 | this.CopyToTransformData(this.Output); | ||
420 | } | ||
421 | |||
422 | // stop processing if an error previously occurred | ||
423 | if (Messaging.Instance.EncounteredError) | ||
424 | { | ||
425 | return; | ||
426 | } | ||
427 | |||
428 | // add back suppressed tables which must be present prior to merging in modules | ||
429 | if (OutputType.Product == this.Output.Type) | ||
430 | { | ||
431 | Table wixMergeTable = this.Output.Tables["WixMerge"]; | ||
432 | |||
433 | if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count) | ||
434 | { | ||
435 | foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) | ||
436 | { | ||
437 | string sequenceTableName = sequence.ToString(); | ||
438 | Table sequenceTable = this.Output.Tables[sequenceTableName]; | ||
439 | |||
440 | if (null == sequenceTable) | ||
441 | { | ||
442 | sequenceTable = this.Output.EnsureTable(this.TableDefinitions[sequenceTableName]); | ||
443 | } | ||
444 | |||
445 | if (0 == sequenceTable.Rows.Count) | ||
446 | { | ||
447 | suppressedTableNames.Add(sequenceTableName); | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | |||
453 | foreach (BinderExtension extension in this.Extensions) | ||
454 | { | ||
455 | extension.Finish(this.Output); | ||
456 | } | ||
457 | |||
458 | // generate database file | ||
459 | Messaging.Instance.OnMessage(WixVerboses.GeneratingDatabase()); | ||
460 | string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(this.OutputPath)); | ||
461 | this.GenerateDatabase(this.Output, tempDatabaseFile, false, false); | ||
462 | |||
463 | FileTransfer transfer; | ||
464 | if (FileTransfer.TryCreate(tempDatabaseFile, this.OutputPath, true, this.Output.Type.ToString(), null, out transfer)) // note where this database needs to move in the future | ||
465 | { | ||
466 | transfer.Built = true; | ||
467 | fileTransfers.Add(transfer); | ||
468 | } | ||
469 | |||
470 | // stop processing if an error previously occurred | ||
471 | if (Messaging.Instance.EncounteredError) | ||
472 | { | ||
473 | return; | ||
474 | } | ||
475 | |||
476 | // Output the output to a file | ||
477 | Pdb pdb = new Pdb(); | ||
478 | pdb.Output = this.Output; | ||
479 | if (!String.IsNullOrEmpty(this.PdbFile)) | ||
480 | { | ||
481 | pdb.Save(this.PdbFile); | ||
482 | } | ||
483 | |||
484 | // Merge modules. | ||
485 | if (OutputType.Product == this.Output.Type) | ||
486 | { | ||
487 | Messaging.Instance.OnMessage(WixVerboses.MergingModules()); | ||
488 | |||
489 | MergeModulesCommand command = new MergeModulesCommand(); | ||
490 | command.FileFacades = fileFacades; | ||
491 | command.Output = this.Output; | ||
492 | command.OutputPath = tempDatabaseFile; | ||
493 | command.SuppressedTableNames = suppressedTableNames; | ||
494 | command.Execute(); | ||
495 | |||
496 | // stop processing if an error previously occurred | ||
497 | if (Messaging.Instance.EncounteredError) | ||
498 | { | ||
499 | return; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | // inspect the MSI prior to running ICEs | ||
504 | InspectorCore inspectorCore = new InspectorCore(); | ||
505 | foreach (InspectorExtension inspectorExtension in this.InspectorExtensions) | ||
506 | { | ||
507 | inspectorExtension.Core = inspectorCore; | ||
508 | inspectorExtension.InspectDatabase(tempDatabaseFile, pdb); | ||
509 | |||
510 | inspectorExtension.Core = null; // reset. | ||
511 | } | ||
512 | |||
513 | if (Messaging.Instance.EncounteredError) | ||
514 | { | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | // validate the output if there is an MSI validator | ||
519 | if (null != this.Validator) | ||
520 | { | ||
521 | Stopwatch stopwatch = Stopwatch.StartNew(); | ||
522 | |||
523 | // set the output file for source line information | ||
524 | this.Validator.Output = this.Output; | ||
525 | |||
526 | Messaging.Instance.OnMessage(WixVerboses.ValidatingDatabase()); | ||
527 | |||
528 | this.Validator.Validate(tempDatabaseFile); | ||
529 | |||
530 | stopwatch.Stop(); | ||
531 | Messaging.Instance.OnMessage(WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); | ||
532 | |||
533 | // Stop processing if an error occurred. | ||
534 | if (Messaging.Instance.EncounteredError) | ||
535 | { | ||
536 | return; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | // Process uncompressed files. | ||
541 | if (!Messaging.Instance.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any()) | ||
542 | { | ||
543 | ProcessUncompressedFilesCommand command = new ProcessUncompressedFilesCommand(); | ||
544 | command.Compressed = compressed; | ||
545 | command.FileFacades = uncompressedFiles; | ||
546 | command.LayoutDirectory = layoutDirectory; | ||
547 | command.LongNamesInImage = longNames; | ||
548 | command.MediaRows = assignedMediaRows; | ||
549 | command.ResolveMedia = this.ResolveMedia; | ||
550 | command.DatabasePath = tempDatabaseFile; | ||
551 | command.WixMediaTable = this.Output.Tables["WixMedia"]; | ||
552 | command.Execute(); | ||
553 | |||
554 | fileTransfers.AddRange(command.FileTransfers); | ||
555 | } | ||
556 | |||
557 | this.FileTransfers = fileTransfers; | ||
558 | this.ContentFilePaths = fileFacades.Select(r => r.WixFile.Source).ToList(); | ||
559 | } | ||
560 | |||
561 | /// <summary> | ||
562 | /// Localize dialogs and controls. | ||
563 | /// </summary> | ||
564 | /// <param name="tables">The tables to localize.</param> | ||
565 | private void LocalizeUI(TableIndexedCollection tables) | ||
566 | { | ||
567 | Table dialogTable = tables["Dialog"]; | ||
568 | if (null != dialogTable) | ||
569 | { | ||
570 | foreach (Row row in dialogTable.Rows) | ||
571 | { | ||
572 | string dialog = (string)row[0]; | ||
573 | LocalizedControl localizedControl = this.Localizer.GetLocalizedControl(dialog, null); | ||
574 | if (null != localizedControl) | ||
575 | { | ||
576 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | ||
577 | { | ||
578 | row[1] = localizedControl.X; | ||
579 | } | ||
580 | |||
581 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) | ||
582 | { | ||
583 | row[2] = localizedControl.Y; | ||
584 | } | ||
585 | |||
586 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) | ||
587 | { | ||
588 | row[3] = localizedControl.Width; | ||
589 | } | ||
590 | |||
591 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) | ||
592 | { | ||
593 | row[4] = localizedControl.Height; | ||
594 | } | ||
595 | |||
596 | row[5] = (int)row[5] | localizedControl.Attributes; | ||
597 | |||
598 | if (!String.IsNullOrEmpty(localizedControl.Text)) | ||
599 | { | ||
600 | row[6] = localizedControl.Text; | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | |||
606 | Table controlTable = tables["Control"]; | ||
607 | if (null != controlTable) | ||
608 | { | ||
609 | foreach (Row row in controlTable.Rows) | ||
610 | { | ||
611 | string dialog = (string)row[0]; | ||
612 | string control = (string)row[1]; | ||
613 | LocalizedControl localizedControl = this.Localizer.GetLocalizedControl(dialog, control); | ||
614 | if (null != localizedControl) | ||
615 | { | ||
616 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | ||
617 | { | ||
618 | row[3] = localizedControl.X.ToString(); | ||
619 | } | ||
620 | |||
621 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) | ||
622 | { | ||
623 | row[4] = localizedControl.Y.ToString(); | ||
624 | } | ||
625 | |||
626 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) | ||
627 | { | ||
628 | row[5] = localizedControl.Width.ToString(); | ||
629 | } | ||
630 | |||
631 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) | ||
632 | { | ||
633 | row[6] = localizedControl.Height.ToString(); | ||
634 | } | ||
635 | |||
636 | row[7] = (int)row[7] | localizedControl.Attributes; | ||
637 | |||
638 | if (!String.IsNullOrEmpty(localizedControl.Text)) | ||
639 | { | ||
640 | row[9] = localizedControl.Text; | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | |||
647 | /// <summary> | ||
648 | /// Copy file data between transform substorages and the patch output object | ||
649 | /// </summary> | ||
650 | /// <param name="output">The output to bind.</param> | ||
651 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> | ||
652 | private IEnumerable<FileFacade> CopyFromTransformData(Output output) | ||
653 | { | ||
654 | CopyTransformDataCommand command = new CopyTransformDataCommand(); | ||
655 | command.CopyOutFileRows = true; | ||
656 | command.FileManagerCore = this.FileManagerCore; | ||
657 | command.FileManagers = this.FileManagers; | ||
658 | command.Output = output; | ||
659 | command.TableDefinitions = this.TableDefinitions; | ||
660 | command.Execute(); | ||
661 | |||
662 | return command.FileFacades; | ||
663 | } | ||
664 | |||
665 | /// <summary> | ||
666 | /// Copy file data between transform substorages and the patch output object | ||
667 | /// </summary> | ||
668 | /// <param name="output">The output to bind.</param> | ||
669 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> | ||
670 | private void CopyToTransformData(Output output) | ||
671 | { | ||
672 | CopyTransformDataCommand command = new CopyTransformDataCommand(); | ||
673 | command.CopyOutFileRows = false; | ||
674 | command.FileManagerCore = this.FileManagerCore; | ||
675 | command.FileManagers = this.FileManagers; | ||
676 | command.Output = output; | ||
677 | command.TableDefinitions = this.TableDefinitions; | ||
678 | command.Execute(); | ||
679 | } | ||
680 | |||
681 | /// <summary> | ||
682 | /// Takes an id, and demodularizes it (if possible). | ||
683 | /// </summary> | ||
684 | /// <remarks> | ||
685 | /// If the output type is a module, returns a demodularized version of an id. Otherwise, returns the id. | ||
686 | /// </remarks> | ||
687 | /// <param name="outputType">The type of the output to bind.</param> | ||
688 | /// <param name="modularizationGuid">The modularization GUID.</param> | ||
689 | /// <param name="id">The id to demodularize.</param> | ||
690 | /// <returns>The demodularized id.</returns> | ||
691 | internal static string Demodularize(OutputType outputType, string modularizationGuid, string id) | ||
692 | { | ||
693 | if (OutputType.Module == outputType && id.EndsWith(String.Concat(".", modularizationGuid), StringComparison.Ordinal)) | ||
694 | { | ||
695 | id = id.Substring(0, id.Length - 37); | ||
696 | } | ||
697 | |||
698 | return id; | ||
699 | } | ||
700 | |||
701 | private void UpdateMediaSequences(OutputType outputType, IEnumerable<FileFacade> fileFacades, RowDictionary<MediaRow> mediaRows) | ||
702 | { | ||
703 | // Calculate sequence numbers and media disk id layout for all file media information objects. | ||
704 | if (OutputType.Module == outputType) | ||
705 | { | ||
706 | int lastSequence = 0; | ||
707 | 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. | ||
708 | { | ||
709 | facade.File.Sequence = ++lastSequence; | ||
710 | } | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | int lastSequence = 0; | ||
715 | MediaRow mediaRow = null; | ||
716 | Dictionary<int, List<FileFacade>> patchGroups = new Dictionary<int, List<FileFacade>>(); | ||
717 | |||
718 | // sequence the non-patch-added files | ||
719 | 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. | ||
720 | { | ||
721 | if (null == mediaRow) | ||
722 | { | ||
723 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
724 | if (OutputType.Patch == outputType) | ||
725 | { | ||
726 | // patch Media cannot start at zero | ||
727 | lastSequence = mediaRow.LastSequence; | ||
728 | } | ||
729 | } | ||
730 | else if (mediaRow.DiskId != facade.WixFile.DiskId) | ||
731 | { | ||
732 | mediaRow.LastSequence = lastSequence; | ||
733 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
734 | } | ||
735 | |||
736 | if (0 < facade.WixFile.PatchGroup) | ||
737 | { | ||
738 | List<FileFacade> patchGroup = patchGroups[facade.WixFile.PatchGroup]; | ||
739 | |||
740 | if (null == patchGroup) | ||
741 | { | ||
742 | patchGroup = new List<FileFacade>(); | ||
743 | patchGroups.Add(facade.WixFile.PatchGroup, patchGroup); | ||
744 | } | ||
745 | |||
746 | patchGroup.Add(facade); | ||
747 | } | ||
748 | else | ||
749 | { | ||
750 | facade.File.Sequence = ++lastSequence; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | if (null != mediaRow) | ||
755 | { | ||
756 | mediaRow.LastSequence = lastSequence; | ||
757 | mediaRow = null; | ||
758 | } | ||
759 | |||
760 | // sequence the patch-added files | ||
761 | foreach (List<FileFacade> patchGroup in patchGroups.Values) | ||
762 | { | ||
763 | foreach (FileFacade facade in patchGroup) | ||
764 | { | ||
765 | if (null == mediaRow) | ||
766 | { | ||
767 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
768 | } | ||
769 | else if (mediaRow.DiskId != facade.WixFile.DiskId) | ||
770 | { | ||
771 | mediaRow.LastSequence = lastSequence; | ||
772 | mediaRow = mediaRows.Get(facade.WixFile.DiskId); | ||
773 | } | ||
774 | |||
775 | facade.File.Sequence = ++lastSequence; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | if (null != mediaRow) | ||
780 | { | ||
781 | mediaRow.LastSequence = lastSequence; | ||
782 | } | ||
783 | } | ||
784 | } | ||
785 | |||
786 | /// <summary> | ||
787 | /// Set the guids for components with generatable guids. | ||
788 | /// </summary> | ||
789 | /// <param name="output">Internal representation of the database to operate on.</param> | ||
790 | private void SetComponentGuids(Output output) | ||
791 | { | ||
792 | Table componentTable = output.Tables["Component"]; | ||
793 | if (null != componentTable) | ||
794 | { | ||
795 | Hashtable registryKeyRows = null; | ||
796 | Hashtable directories = null; | ||
797 | Hashtable componentIdGenSeeds = null; | ||
798 | Dictionary<string, List<FileRow>> fileRows = null; | ||
799 | |||
800 | // find components with generatable guids | ||
801 | foreach (ComponentRow componentRow in componentTable.Rows) | ||
802 | { | ||
803 | // component guid will be generated | ||
804 | if ("*" == componentRow.Guid) | ||
805 | { | ||
806 | if (null == componentRow.KeyPath || componentRow.IsOdbcDataSourceKeyPath) | ||
807 | { | ||
808 | Messaging.Instance.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(componentRow.SourceLineNumbers)); | ||
809 | } | ||
810 | else if (componentRow.IsRegistryKeyPath) | ||
811 | { | ||
812 | if (null == registryKeyRows) | ||
813 | { | ||
814 | Table registryTable = output.Tables["Registry"]; | ||
815 | |||
816 | registryKeyRows = new Hashtable(registryTable.Rows.Count); | ||
817 | |||
818 | foreach (Row registryRow in registryTable.Rows) | ||
819 | { | ||
820 | registryKeyRows.Add((string)registryRow[0], registryRow); | ||
821 | } | ||
822 | } | ||
823 | |||
824 | Row foundRow = registryKeyRows[componentRow.KeyPath] as Row; | ||
825 | |||
826 | string bitness = componentRow.Is64Bit ? "64" : String.Empty; | ||
827 | if (null != foundRow) | ||
828 | { | ||
829 | string regkey = String.Concat(bitness, foundRow[1], "\\", foundRow[2], "\\", foundRow[3]); | ||
830 | componentRow.Guid = Uuid.NewUuid(BindDatabaseCommand.WixComponentGuidNamespace, regkey.ToLowerInvariant()).ToString("B").ToUpperInvariant(); | ||
831 | } | ||
832 | } | ||
833 | else // must be a File KeyPath | ||
834 | { | ||
835 | // if the directory table hasn't been loaded into an indexed hash | ||
836 | // of directory ids to target names do that now. | ||
837 | if (null == directories) | ||
838 | { | ||
839 | Table directoryTable = output.Tables["Directory"]; | ||
840 | |||
841 | int numDirectoryTableRows = (null != directoryTable) ? directoryTable.Rows.Count : 0; | ||
842 | |||
843 | directories = new Hashtable(numDirectoryTableRows); | ||
844 | |||
845 | // get the target paths for all directories | ||
846 | if (null != directoryTable) | ||
847 | { | ||
848 | foreach (Row row in directoryTable.Rows) | ||
849 | { | ||
850 | // if the directory Id already exists, we will skip it here since | ||
851 | // checking for duplicate primary keys is done later when importing tables | ||
852 | // into database | ||
853 | if (directories.ContainsKey(row[0])) | ||
854 | { | ||
855 | continue; | ||
856 | } | ||
857 | |||
858 | string targetName = Installer.GetName((string)row[2], false, true); | ||
859 | directories.Add(row[0], new ResolvedDirectory((string)row[1], targetName)); | ||
860 | } | ||
861 | } | ||
862 | } | ||
863 | |||
864 | // if the component id generation seeds have not been indexed | ||
865 | // from the WixDirectory table do that now. | ||
866 | if (null == componentIdGenSeeds) | ||
867 | { | ||
868 | Table wixDirectoryTable = output.Tables["WixDirectory"]; | ||
869 | |||
870 | int numWixDirectoryRows = (null != wixDirectoryTable) ? wixDirectoryTable.Rows.Count : 0; | ||
871 | |||
872 | componentIdGenSeeds = new Hashtable(numWixDirectoryRows); | ||
873 | |||
874 | // if there are any WixDirectory rows, build up the Component Guid | ||
875 | // generation seeds indexed by Directory/@Id. | ||
876 | if (null != wixDirectoryTable) | ||
877 | { | ||
878 | foreach (Row row in wixDirectoryTable.Rows) | ||
879 | { | ||
880 | componentIdGenSeeds.Add(row[0], (string)row[1]); | ||
881 | } | ||
882 | } | ||
883 | } | ||
884 | |||
885 | // if the file rows have not been indexed by File.Component yet | ||
886 | // then do that now | ||
887 | if (null == fileRows) | ||
888 | { | ||
889 | Table fileTable = output.Tables["File"]; | ||
890 | |||
891 | int numFileRows = (null != fileTable) ? fileTable.Rows.Count : 0; | ||
892 | |||
893 | fileRows = new Dictionary<string, List<FileRow>>(numFileRows); | ||
894 | |||
895 | if (null != fileTable) | ||
896 | { | ||
897 | foreach (FileRow file in fileTable.Rows) | ||
898 | { | ||
899 | List<FileRow> files; | ||
900 | if (!fileRows.TryGetValue(file.Component, out files)) | ||
901 | { | ||
902 | files = new List<FileRow>(); | ||
903 | fileRows.Add(file.Component, files); | ||
904 | } | ||
905 | |||
906 | files.Add(file); | ||
907 | } | ||
908 | } | ||
909 | } | ||
910 | |||
911 | // validate component meets all the conditions to have a generated guid | ||
912 | List<FileRow> currentComponentFiles = fileRows[componentRow.Component]; | ||
913 | int numFilesInComponent = currentComponentFiles.Count; | ||
914 | string path = null; | ||
915 | |||
916 | foreach (FileRow fileRow in currentComponentFiles) | ||
917 | { | ||
918 | if (fileRow.File == componentRow.KeyPath) | ||
919 | { | ||
920 | // calculate the key file's canonical target path | ||
921 | string directoryPath = Binder.GetDirectoryPath(directories, componentIdGenSeeds, componentRow.Directory, true); | ||
922 | string fileName = Installer.GetName(fileRow.FileName, false, true).ToLower(CultureInfo.InvariantCulture); | ||
923 | path = Path.Combine(directoryPath, fileName); | ||
924 | |||
925 | // find paths that are not canonicalized | ||
926 | if (path.StartsWith(@"PersonalFolder\my pictures", StringComparison.Ordinal) || | ||
927 | path.StartsWith(@"ProgramFilesFolder\common files", StringComparison.Ordinal) || | ||
928 | path.StartsWith(@"ProgramMenuFolder\startup", StringComparison.Ordinal) || | ||
929 | path.StartsWith("TARGETDIR", StringComparison.Ordinal) || | ||
930 | path.StartsWith(@"StartMenuFolder\programs", StringComparison.Ordinal) || | ||
931 | path.StartsWith(@"WindowsFolder\fonts", StringComparison.Ordinal)) | ||
932 | { | ||
933 | Messaging.Instance.OnMessage(WixErrors.IllegalPathForGeneratedComponentGuid(componentRow.SourceLineNumbers, fileRow.Component, path)); | ||
934 | } | ||
935 | |||
936 | // if component has more than one file, the key path must be versioned | ||
937 | if (1 < numFilesInComponent && String.IsNullOrEmpty(fileRow.Version)) | ||
938 | { | ||
939 | Messaging.Instance.OnMessage(WixErrors.IllegalGeneratedGuidComponentUnversionedKeypath(componentRow.SourceLineNumbers)); | ||
940 | } | ||
941 | } | ||
942 | else | ||
943 | { | ||
944 | // not a key path, so it must be an unversioned file if component has more than one file | ||
945 | if (1 < numFilesInComponent && !String.IsNullOrEmpty(fileRow.Version)) | ||
946 | { | ||
947 | Messaging.Instance.OnMessage(WixErrors.IllegalGeneratedGuidComponentVersionedNonkeypath(componentRow.SourceLineNumbers)); | ||
948 | } | ||
949 | } | ||
950 | } | ||
951 | |||
952 | // if the rules were followed, reward with a generated guid | ||
953 | if (!Messaging.Instance.EncounteredError) | ||
954 | { | ||
955 | componentRow.Guid = Uuid.NewUuid(BindDatabaseCommand.WixComponentGuidNamespace, path).ToString("B").ToUpperInvariant(); | ||
956 | } | ||
957 | } | ||
958 | } | ||
959 | } | ||
960 | } | ||
961 | } | ||
962 | |||
963 | /// <summary> | ||
964 | /// Creates instance transform substorages in the output. | ||
965 | /// </summary> | ||
966 | /// <param name="output">Output containing instance transform definitions.</param> | ||
967 | private void CreateInstanceTransforms(Output output) | ||
968 | { | ||
969 | // Create and add substorages for instance transforms. | ||
970 | Table wixInstanceTransformsTable = output.Tables["WixInstanceTransforms"]; | ||
971 | if (null != wixInstanceTransformsTable && 0 <= wixInstanceTransformsTable.Rows.Count) | ||
972 | { | ||
973 | string targetProductCode = null; | ||
974 | string targetUpgradeCode = null; | ||
975 | string targetProductVersion = null; | ||
976 | |||
977 | Table targetSummaryInformationTable = output.Tables["_SummaryInformation"]; | ||
978 | Table targetPropertyTable = output.Tables["Property"]; | ||
979 | |||
980 | // Get the data from target database | ||
981 | foreach (Row propertyRow in targetPropertyTable.Rows) | ||
982 | { | ||
983 | if ("ProductCode" == (string)propertyRow[0]) | ||
984 | { | ||
985 | targetProductCode = (string)propertyRow[1]; | ||
986 | } | ||
987 | else if ("ProductVersion" == (string)propertyRow[0]) | ||
988 | { | ||
989 | targetProductVersion = (string)propertyRow[1]; | ||
990 | } | ||
991 | else if ("UpgradeCode" == (string)propertyRow[0]) | ||
992 | { | ||
993 | targetUpgradeCode = (string)propertyRow[1]; | ||
994 | } | ||
995 | } | ||
996 | |||
997 | // Index the Instance Component Rows. | ||
998 | Dictionary<string, ComponentRow> instanceComponentGuids = new Dictionary<string, ComponentRow>(); | ||
999 | Table targetInstanceComponentTable = output.Tables["WixInstanceComponent"]; | ||
1000 | if (null != targetInstanceComponentTable && 0 < targetInstanceComponentTable.Rows.Count) | ||
1001 | { | ||
1002 | foreach (Row row in targetInstanceComponentTable.Rows) | ||
1003 | { | ||
1004 | // Build up all the instances, we'll get the Components rows from the real Component table. | ||
1005 | instanceComponentGuids.Add((string)row[0], null); | ||
1006 | } | ||
1007 | |||
1008 | Table targetComponentTable = output.Tables["Component"]; | ||
1009 | foreach (ComponentRow componentRow in targetComponentTable.Rows) | ||
1010 | { | ||
1011 | string component = (string)componentRow[0]; | ||
1012 | if (instanceComponentGuids.ContainsKey(component)) | ||
1013 | { | ||
1014 | instanceComponentGuids[component] = componentRow; | ||
1015 | } | ||
1016 | } | ||
1017 | } | ||
1018 | |||
1019 | // Generate the instance transforms | ||
1020 | foreach (Row instanceRow in wixInstanceTransformsTable.Rows) | ||
1021 | { | ||
1022 | string instanceId = (string)instanceRow[0]; | ||
1023 | |||
1024 | Output instanceTransform = new Output(instanceRow.SourceLineNumbers); | ||
1025 | instanceTransform.Type = OutputType.Transform; | ||
1026 | instanceTransform.Codepage = output.Codepage; | ||
1027 | |||
1028 | Table instanceSummaryInformationTable = instanceTransform.EnsureTable(this.TableDefinitions["_SummaryInformation"]); | ||
1029 | string targetPlatformAndLanguage = null; | ||
1030 | |||
1031 | foreach (Row summaryInformationRow in targetSummaryInformationTable.Rows) | ||
1032 | { | ||
1033 | if (7 == (int)summaryInformationRow[0]) // PID_TEMPLATE | ||
1034 | { | ||
1035 | targetPlatformAndLanguage = (string)summaryInformationRow[1]; | ||
1036 | } | ||
1037 | |||
1038 | // Copy the row's data to the transform. | ||
1039 | Row copyOfSummaryRow = instanceSummaryInformationTable.CreateRow(null); | ||
1040 | copyOfSummaryRow[0] = summaryInformationRow[0]; | ||
1041 | copyOfSummaryRow[1] = summaryInformationRow[1]; | ||
1042 | } | ||
1043 | |||
1044 | // Modify the appropriate properties. | ||
1045 | Table propertyTable = instanceTransform.EnsureTable(this.TableDefinitions["Property"]); | ||
1046 | |||
1047 | // Change the ProductCode property | ||
1048 | string productCode = (string)instanceRow[2]; | ||
1049 | if ("*" == productCode) | ||
1050 | { | ||
1051 | productCode = Common.GenerateGuid(); | ||
1052 | } | ||
1053 | |||
1054 | Row productCodeRow = propertyTable.CreateRow(instanceRow.SourceLineNumbers); | ||
1055 | productCodeRow.Operation = RowOperation.Modify; | ||
1056 | productCodeRow.Fields[1].Modified = true; | ||
1057 | productCodeRow[0] = "ProductCode"; | ||
1058 | productCodeRow[1] = productCode; | ||
1059 | |||
1060 | // Change the instance property | ||
1061 | Row instanceIdRow = propertyTable.CreateRow(instanceRow.SourceLineNumbers); | ||
1062 | instanceIdRow.Operation = RowOperation.Modify; | ||
1063 | instanceIdRow.Fields[1].Modified = true; | ||
1064 | instanceIdRow[0] = (string)instanceRow[1]; | ||
1065 | instanceIdRow[1] = instanceId; | ||
1066 | |||
1067 | if (null != instanceRow[3]) | ||
1068 | { | ||
1069 | // Change the ProductName property | ||
1070 | Row productNameRow = propertyTable.CreateRow(instanceRow.SourceLineNumbers); | ||
1071 | productNameRow.Operation = RowOperation.Modify; | ||
1072 | productNameRow.Fields[1].Modified = true; | ||
1073 | productNameRow[0] = "ProductName"; | ||
1074 | productNameRow[1] = (string)instanceRow[3]; | ||
1075 | } | ||
1076 | |||
1077 | if (null != instanceRow[4]) | ||
1078 | { | ||
1079 | // Change the UpgradeCode property | ||
1080 | Row upgradeCodeRow = propertyTable.CreateRow(instanceRow.SourceLineNumbers); | ||
1081 | upgradeCodeRow.Operation = RowOperation.Modify; | ||
1082 | upgradeCodeRow.Fields[1].Modified = true; | ||
1083 | upgradeCodeRow[0] = "UpgradeCode"; | ||
1084 | upgradeCodeRow[1] = instanceRow[4]; | ||
1085 | |||
1086 | // Change the Upgrade table | ||
1087 | Table targetUpgradeTable = output.Tables["Upgrade"]; | ||
1088 | if (null != targetUpgradeTable && 0 <= targetUpgradeTable.Rows.Count) | ||
1089 | { | ||
1090 | string upgradeId = (string)instanceRow[4]; | ||
1091 | Table upgradeTable = instanceTransform.EnsureTable(this.TableDefinitions["Upgrade"]); | ||
1092 | foreach (Row row in targetUpgradeTable.Rows) | ||
1093 | { | ||
1094 | // In case they are upgrading other codes to this new product, leave the ones that don't match the | ||
1095 | // Product.UpgradeCode intact. | ||
1096 | if (targetUpgradeCode == (string)row[0]) | ||
1097 | { | ||
1098 | Row upgradeRow = upgradeTable.CreateRow(null); | ||
1099 | upgradeRow.Operation = RowOperation.Add; | ||
1100 | upgradeRow.Fields[0].Modified = true; | ||
1101 | // I was hoping to be able to RowOperation.Modify, but that didn't appear to function. | ||
1102 | // upgradeRow.Fields[0].PreviousData = (string)row[0]; | ||
1103 | |||
1104 | // Inserting a new Upgrade record with the updated UpgradeCode | ||
1105 | upgradeRow[0] = upgradeId; | ||
1106 | upgradeRow[1] = row[1]; | ||
1107 | upgradeRow[2] = row[2]; | ||
1108 | upgradeRow[3] = row[3]; | ||
1109 | upgradeRow[4] = row[4]; | ||
1110 | upgradeRow[5] = row[5]; | ||
1111 | upgradeRow[6] = row[6]; | ||
1112 | |||
1113 | // Delete the old row | ||
1114 | Row upgradeRemoveRow = upgradeTable.CreateRow(null); | ||
1115 | upgradeRemoveRow.Operation = RowOperation.Delete; | ||
1116 | upgradeRemoveRow[0] = row[0]; | ||
1117 | upgradeRemoveRow[1] = row[1]; | ||
1118 | upgradeRemoveRow[2] = row[2]; | ||
1119 | upgradeRemoveRow[3] = row[3]; | ||
1120 | upgradeRemoveRow[4] = row[4]; | ||
1121 | upgradeRemoveRow[5] = row[5]; | ||
1122 | upgradeRemoveRow[6] = row[6]; | ||
1123 | } | ||
1124 | } | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | // If there are instance Components generate new GUIDs for them. | ||
1129 | if (0 < instanceComponentGuids.Count) | ||
1130 | { | ||
1131 | Table componentTable = instanceTransform.EnsureTable(this.TableDefinitions["Component"]); | ||
1132 | foreach (ComponentRow targetComponentRow in instanceComponentGuids.Values) | ||
1133 | { | ||
1134 | string guid = targetComponentRow.Guid; | ||
1135 | if (!String.IsNullOrEmpty(guid)) | ||
1136 | { | ||
1137 | Row instanceComponentRow = componentTable.CreateRow(targetComponentRow.SourceLineNumbers); | ||
1138 | instanceComponentRow.Operation = RowOperation.Modify; | ||
1139 | instanceComponentRow.Fields[1].Modified = true; | ||
1140 | instanceComponentRow[0] = targetComponentRow[0]; | ||
1141 | instanceComponentRow[1] = Uuid.NewUuid(BindDatabaseCommand.WixComponentGuidNamespace, String.Concat(guid, instanceId)).ToString("B").ToUpper(CultureInfo.InvariantCulture); | ||
1142 | instanceComponentRow[2] = targetComponentRow[2]; | ||
1143 | instanceComponentRow[3] = targetComponentRow[3]; | ||
1144 | instanceComponentRow[4] = targetComponentRow[4]; | ||
1145 | instanceComponentRow[5] = targetComponentRow[5]; | ||
1146 | } | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | // Update the summary information | ||
1151 | Hashtable summaryRows = new Hashtable(instanceSummaryInformationTable.Rows.Count); | ||
1152 | foreach (Row row in instanceSummaryInformationTable.Rows) | ||
1153 | { | ||
1154 | summaryRows[row[0]] = row; | ||
1155 | |||
1156 | if ((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage == (int)row[0]) | ||
1157 | { | ||
1158 | row[1] = targetPlatformAndLanguage; | ||
1159 | } | ||
1160 | else if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0]) | ||
1161 | { | ||
1162 | row[1] = String.Concat(targetProductCode, targetProductVersion, ';', productCode, targetProductVersion, ';', targetUpgradeCode); | ||
1163 | } | ||
1164 | else if ((int)SummaryInformation.Transform.ValidationFlags == (int)row[0]) | ||
1165 | { | ||
1166 | row[1] = 0; | ||
1167 | } | ||
1168 | else if ((int)SummaryInformation.Transform.Security == (int)row[0]) | ||
1169 | { | ||
1170 | row[1] = "4"; | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | if (!summaryRows.Contains((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage)) | ||
1175 | { | ||
1176 | Row summaryRow = instanceSummaryInformationTable.CreateRow(null); | ||
1177 | summaryRow[0] = (int)SummaryInformation.Transform.UpdatedPlatformAndLanguage; | ||
1178 | summaryRow[1] = targetPlatformAndLanguage; | ||
1179 | } | ||
1180 | else if (!summaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags)) | ||
1181 | { | ||
1182 | Row summaryRow = instanceSummaryInformationTable.CreateRow(null); | ||
1183 | summaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags; | ||
1184 | summaryRow[1] = "0"; | ||
1185 | } | ||
1186 | else if (!summaryRows.Contains((int)SummaryInformation.Transform.Security)) | ||
1187 | { | ||
1188 | Row summaryRow = instanceSummaryInformationTable.CreateRow(null); | ||
1189 | summaryRow[0] = (int)SummaryInformation.Transform.Security; | ||
1190 | summaryRow[1] = "4"; | ||
1191 | } | ||
1192 | |||
1193 | output.SubStorages.Add(new SubStorage(instanceId, instanceTransform)); | ||
1194 | } | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /// <summary> | ||
1199 | /// Validate that there are no duplicate GUIDs in the output. | ||
1200 | /// </summary> | ||
1201 | /// <remarks> | ||
1202 | /// Duplicate GUIDs without conditions are an error condition; with conditions, it's a | ||
1203 | /// warning, as the conditions might be mutually exclusive. | ||
1204 | /// </remarks> | ||
1205 | private void ValidateComponentGuids(Output output) | ||
1206 | { | ||
1207 | Table componentTable = output.Tables["Component"]; | ||
1208 | if (null != componentTable) | ||
1209 | { | ||
1210 | Dictionary<string, bool> componentGuidConditions = new Dictionary<string, bool>(componentTable.Rows.Count); | ||
1211 | |||
1212 | foreach (ComponentRow row in componentTable.Rows) | ||
1213 | { | ||
1214 | // we don't care about unmanaged components and if there's a * GUID remaining, | ||
1215 | // there's already an error that prevented it from being replaced with a real GUID. | ||
1216 | if (!String.IsNullOrEmpty(row.Guid) && "*" != row.Guid) | ||
1217 | { | ||
1218 | bool thisComponentHasCondition = !String.IsNullOrEmpty(row.Condition); | ||
1219 | bool allComponentsHaveConditions = thisComponentHasCondition; | ||
1220 | |||
1221 | if (componentGuidConditions.ContainsKey(row.Guid)) | ||
1222 | { | ||
1223 | allComponentsHaveConditions = componentGuidConditions[row.Guid] && thisComponentHasCondition; | ||
1224 | |||
1225 | if (allComponentsHaveConditions) | ||
1226 | { | ||
1227 | Messaging.Instance.OnMessage(WixWarnings.DuplicateComponentGuidsMustHaveMutuallyExclusiveConditions(row.SourceLineNumbers, row.Component, row.Guid)); | ||
1228 | } | ||
1229 | else | ||
1230 | { | ||
1231 | Messaging.Instance.OnMessage(WixErrors.DuplicateComponentGuids(row.SourceLineNumbers, row.Component, row.Guid)); | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | componentGuidConditions[row.Guid] = allComponentsHaveConditions; | ||
1236 | } | ||
1237 | } | ||
1238 | } | ||
1239 | } | ||
1240 | |||
1241 | /// <summary> | ||
1242 | /// Update Control and BBControl text by reading from files when necessary. | ||
1243 | /// </summary> | ||
1244 | /// <param name="output">Internal representation of the msi database to operate upon.</param> | ||
1245 | private void UpdateControlText(Output output) | ||
1246 | { | ||
1247 | UpdateControlTextCommand command = new UpdateControlTextCommand(); | ||
1248 | command.BBControlTable = output.Tables["BBControl"]; | ||
1249 | command.WixBBControlTable = output.Tables["WixBBControl"]; | ||
1250 | command.ControlTable = output.Tables["Control"]; | ||
1251 | command.WixControlTable = output.Tables["WixControl"]; | ||
1252 | command.Execute(); | ||
1253 | } | ||
1254 | |||
1255 | private string ResolveMedia(MediaRow mediaRow, string mediaLayoutDirectory, string layoutDirectory) | ||
1256 | { | ||
1257 | string layout = null; | ||
1258 | |||
1259 | foreach (IBinderFileManager fileManager in this.FileManagers) | ||
1260 | { | ||
1261 | layout = fileManager.ResolveMedia(mediaRow, mediaLayoutDirectory, layoutDirectory); | ||
1262 | if (!String.IsNullOrEmpty(layout)) | ||
1263 | { | ||
1264 | break; | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | // If no binder file manager resolved the layout, do the default behavior. | ||
1269 | if (String.IsNullOrEmpty(layout)) | ||
1270 | { | ||
1271 | if (String.IsNullOrEmpty(mediaLayoutDirectory)) | ||
1272 | { | ||
1273 | layout = layoutDirectory; | ||
1274 | } | ||
1275 | else if (Path.IsPathRooted(mediaLayoutDirectory)) | ||
1276 | { | ||
1277 | layout = mediaLayoutDirectory; | ||
1278 | } | ||
1279 | else | ||
1280 | { | ||
1281 | layout = Path.Combine(layoutDirectory, mediaLayoutDirectory); | ||
1282 | } | ||
1283 | } | ||
1284 | |||
1285 | return layout; | ||
1286 | } | ||
1287 | |||
1288 | /// <summary> | ||
1289 | /// Creates the MSI/MSM/PCP database. | ||
1290 | /// </summary> | ||
1291 | /// <param name="output">Output to create database for.</param> | ||
1292 | /// <param name="databaseFile">The database file to create.</param> | ||
1293 | /// <param name="keepAddedColumns">Whether to keep columns added in a transform.</param> | ||
1294 | /// <param name="useSubdirectory">Whether to use a subdirectory based on the <paramref name="databaseFile"/> file name for intermediate files.</param> | ||
1295 | private void GenerateDatabase(Output output, string databaseFile, bool keepAddedColumns, bool useSubdirectory) | ||
1296 | { | ||
1297 | GenerateDatabaseCommand command = new GenerateDatabaseCommand(); | ||
1298 | command.Extensions = this.Extensions; | ||
1299 | command.FileManagers = this.FileManagers; | ||
1300 | command.Output = output; | ||
1301 | command.OutputPath = databaseFile; | ||
1302 | command.KeepAddedColumns = keepAddedColumns; | ||
1303 | command.UseSubDirectory = useSubdirectory; | ||
1304 | command.SuppressAddingValidationRows = this.SuppressAddingValidationRows; | ||
1305 | command.TableDefinitions = this.TableDefinitions; | ||
1306 | command.TempFilesLocation = this.TempFilesLocation; | ||
1307 | command.Codepage = this.Codepage; | ||
1308 | command.Execute(); | ||
1309 | } | ||
1310 | } | ||
1311 | } | ||