aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs')
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs686
1 files changed, 686 insertions, 0 deletions
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
new file mode 100644
index 00000000..772265a0
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
@@ -0,0 +1,686 @@
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
3namespace WixToolset.Core.Burn.Bundles
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Globalization;
9 using System.Linq;
10 using System.Text;
11 using System.Xml;
12 using WixToolset.Data;
13 using WixToolset.Data.Rows;
14 using WixToolset.Extensibility;
15
16 internal class CreateBurnManifestCommand
17 {
18 public IEnumerable<IBurnBackendExtension> BackendExtensions { private get; set; }
19
20 public Output Output { private get; set; }
21
22 public string ExecutableName { private get; set; }
23
24 public WixBundleRow BundleInfo { private get; set; }
25
26 public WixChainRow Chain { private get; set; }
27
28 public string OutputPath { private get; set; }
29
30 public IEnumerable<WixBundleRollbackBoundaryRow> RollbackBoundaries { private get; set; }
31
32 public IEnumerable<PackageFacade> OrderedPackages { private get; set; }
33
34 public IEnumerable<WixSearchInfo> OrderedSearches { private get; set; }
35
36 public Dictionary<string, WixBundlePayloadRow> Payloads { private get; set; }
37
38 public Dictionary<string, WixBundleContainerRow> Containers { private get; set; }
39
40 public IEnumerable<WixBundlePayloadRow> UXContainerPayloads { private get; set; }
41
42 public IEnumerable<WixBundleCatalogRow> Catalogs { private get; set; }
43
44 public void Execute()
45 {
46 using (XmlTextWriter writer = new XmlTextWriter(this.OutputPath, Encoding.UTF8))
47 {
48 writer.WriteStartDocument();
49
50 writer.WriteStartElement("BurnManifest", BurnCommon.BurnNamespace);
51
52 // Write the condition, if there is one
53 if (null != this.BundleInfo.Condition)
54 {
55 writer.WriteElementString("Condition", this.BundleInfo.Condition);
56 }
57
58 // Write the log element if default logging wasn't disabled.
59 if (!String.IsNullOrEmpty(this.BundleInfo.LogPrefix))
60 {
61 writer.WriteStartElement("Log");
62 if (!String.IsNullOrEmpty(this.BundleInfo.LogPathVariable))
63 {
64 writer.WriteAttributeString("PathVariable", this.BundleInfo.LogPathVariable);
65 }
66 writer.WriteAttributeString("Prefix", this.BundleInfo.LogPrefix);
67 writer.WriteAttributeString("Extension", this.BundleInfo.LogExtension);
68 writer.WriteEndElement();
69 }
70
71
72 // Get update if specified.
73 WixBundleUpdateRow updateRow = this.Output.Tables["WixBundleUpdate"].RowsAs<WixBundleUpdateRow>().FirstOrDefault();
74
75 if (null != updateRow)
76 {
77 writer.WriteStartElement("Update");
78 writer.WriteAttributeString("Location", updateRow.Location);
79 writer.WriteEndElement(); // </Update>
80 }
81
82 // Write the RelatedBundle elements
83
84 // For the related bundles with duplicated identifiers the second instance is ignored (i.e. the Duplicates
85 // enumeration in the index row list is not used).
86 RowIndexedList<WixRelatedBundleRow> relatedBundles = new RowIndexedList<WixRelatedBundleRow>(this.Output.Tables["WixRelatedBundle"]);
87
88 foreach (WixRelatedBundleRow relatedBundle in relatedBundles)
89 {
90 writer.WriteStartElement("RelatedBundle");
91 writer.WriteAttributeString("Id", relatedBundle.Id);
92 writer.WriteAttributeString("Action", Convert.ToString(relatedBundle.Action, CultureInfo.InvariantCulture));
93 writer.WriteEndElement();
94 }
95
96 // Write the variables
97 IEnumerable<WixBundleVariableRow> variables = this.Output.Tables["WixBundleVariable"].RowsAs<WixBundleVariableRow>();
98
99 foreach (WixBundleVariableRow variable in variables)
100 {
101 writer.WriteStartElement("Variable");
102 writer.WriteAttributeString("Id", variable.Id);
103 if (null != variable.Type)
104 {
105 writer.WriteAttributeString("Value", variable.Value);
106 writer.WriteAttributeString("Type", variable.Type);
107 }
108 writer.WriteAttributeString("Hidden", variable.Hidden ? "yes" : "no");
109 writer.WriteAttributeString("Persisted", variable.Persisted ? "yes" : "no");
110 writer.WriteEndElement();
111 }
112
113 // Write the searches
114 foreach (WixSearchInfo searchinfo in this.OrderedSearches)
115 {
116 searchinfo.WriteXml(writer);
117 }
118
119 // write the UX element
120 writer.WriteStartElement("UX");
121 if (!String.IsNullOrEmpty(this.BundleInfo.SplashScreenBitmapPath))
122 {
123 writer.WriteAttributeString("SplashScreen", "yes");
124 }
125
126 // write the UX allPayloads...
127 foreach (WixBundlePayloadRow payload in this.UXContainerPayloads)
128 {
129 writer.WriteStartElement("Payload");
130 this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
131 writer.WriteEndElement();
132 }
133
134 writer.WriteEndElement(); // </UX>
135
136 // write the catalog elements
137 if (this.Catalogs.Any())
138 {
139 foreach (WixBundleCatalogRow catalog in this.Catalogs)
140 {
141 writer.WriteStartElement("Catalog");
142 writer.WriteAttributeString("Id", catalog.Id);
143 writer.WriteAttributeString("Payload", catalog.Payload);
144 writer.WriteEndElement();
145 }
146 }
147
148 foreach (WixBundleContainerRow container in this.Containers.Values)
149 {
150 if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id)
151 {
152 writer.WriteStartElement("Container");
153 this.WriteBurnManifestContainerAttributes(writer, this.ExecutableName, container);
154 writer.WriteEndElement();
155 }
156 }
157
158 foreach (WixBundlePayloadRow payload in this.Payloads.Values)
159 {
160 if (PackagingType.Embedded == payload.Packaging && Compiler.BurnUXContainerId != payload.Container)
161 {
162 writer.WriteStartElement("Payload");
163 this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
164 writer.WriteEndElement();
165 }
166 else if (PackagingType.External == payload.Packaging)
167 {
168 writer.WriteStartElement("Payload");
169 this.WriteBurnManifestPayloadAttributes(writer, payload, false, this.Payloads);
170 writer.WriteEndElement();
171 }
172 }
173
174 foreach (WixBundleRollbackBoundaryRow rollbackBoundary in this.RollbackBoundaries)
175 {
176 writer.WriteStartElement("RollbackBoundary");
177 writer.WriteAttributeString("Id", rollbackBoundary.ChainPackageId);
178 writer.WriteAttributeString("Vital", YesNoType.Yes == rollbackBoundary.Vital ? "yes" : "no");
179 writer.WriteAttributeString("Transaction", YesNoType.Yes == rollbackBoundary.Transaction ? "yes" : "no");
180 writer.WriteEndElement();
181 }
182
183 // Write the registration information...
184 writer.WriteStartElement("Registration");
185
186 writer.WriteAttributeString("Id", this.BundleInfo.BundleId.ToString("B"));
187 writer.WriteAttributeString("ExecutableName", this.ExecutableName);
188 writer.WriteAttributeString("PerMachine", this.BundleInfo.PerMachine ? "yes" : "no");
189 writer.WriteAttributeString("Tag", this.BundleInfo.Tag);
190 writer.WriteAttributeString("Version", this.BundleInfo.Version);
191 writer.WriteAttributeString("ProviderKey", this.BundleInfo.ProviderKey);
192
193 writer.WriteStartElement("Arp");
194 writer.WriteAttributeString("Register", (0 < this.BundleInfo.DisableModify && this.BundleInfo.DisableRemove) ? "no" : "yes"); // do not register if disabled modify and remove.
195 writer.WriteAttributeString("DisplayName", this.BundleInfo.Name);
196 writer.WriteAttributeString("DisplayVersion", this.BundleInfo.Version);
197
198 if (!String.IsNullOrEmpty(this.BundleInfo.Publisher))
199 {
200 writer.WriteAttributeString("Publisher", this.BundleInfo.Publisher);
201 }
202
203 if (!String.IsNullOrEmpty(this.BundleInfo.HelpLink))
204 {
205 writer.WriteAttributeString("HelpLink", this.BundleInfo.HelpLink);
206 }
207
208 if (!String.IsNullOrEmpty(this.BundleInfo.HelpTelephone))
209 {
210 writer.WriteAttributeString("HelpTelephone", this.BundleInfo.HelpTelephone);
211 }
212
213 if (!String.IsNullOrEmpty(this.BundleInfo.AboutUrl))
214 {
215 writer.WriteAttributeString("AboutUrl", this.BundleInfo.AboutUrl);
216 }
217
218 if (!String.IsNullOrEmpty(this.BundleInfo.UpdateUrl))
219 {
220 writer.WriteAttributeString("UpdateUrl", this.BundleInfo.UpdateUrl);
221 }
222
223 if (!String.IsNullOrEmpty(this.BundleInfo.ParentName))
224 {
225 writer.WriteAttributeString("ParentDisplayName", this.BundleInfo.ParentName);
226 }
227
228 if (1 == this.BundleInfo.DisableModify)
229 {
230 writer.WriteAttributeString("DisableModify", "yes");
231 }
232 else if (2 == this.BundleInfo.DisableModify)
233 {
234 writer.WriteAttributeString("DisableModify", "button");
235 }
236
237 if (this.BundleInfo.DisableRemove)
238 {
239 writer.WriteAttributeString("DisableRemove", "yes");
240 }
241 writer.WriteEndElement(); // </Arp>
242
243 // Get update registration if specified.
244 WixUpdateRegistrationRow updateRegistrationInfo = this.Output.Tables["WixUpdateRegistration"].RowsAs<WixUpdateRegistrationRow>().FirstOrDefault();
245
246 if (null != updateRegistrationInfo)
247 {
248 writer.WriteStartElement("Update"); // <Update>
249 writer.WriteAttributeString("Manufacturer", updateRegistrationInfo.Manufacturer);
250
251 if (!String.IsNullOrEmpty(updateRegistrationInfo.Department))
252 {
253 writer.WriteAttributeString("Department", updateRegistrationInfo.Department);
254 }
255
256 if (!String.IsNullOrEmpty(updateRegistrationInfo.ProductFamily))
257 {
258 writer.WriteAttributeString("ProductFamily", updateRegistrationInfo.ProductFamily);
259 }
260
261 writer.WriteAttributeString("Name", updateRegistrationInfo.Name);
262 writer.WriteAttributeString("Classification", updateRegistrationInfo.Classification);
263 writer.WriteEndElement(); // </Update>
264 }
265
266 IEnumerable<Row> bundleTags = this.Output.Tables["WixBundleTag"].RowsAs<Row>();
267
268 foreach (Row row in bundleTags)
269 {
270 writer.WriteStartElement("SoftwareTag");
271 writer.WriteAttributeString("Filename", (string)row[0]);
272 writer.WriteAttributeString("Regid", (string)row[1]);
273 writer.WriteCData((string)row[4]);
274 writer.WriteEndElement();
275 }
276
277 writer.WriteEndElement(); // </Register>
278
279 // write the Chain...
280 writer.WriteStartElement("Chain");
281 if (this.Chain.DisableRollback)
282 {
283 writer.WriteAttributeString("DisableRollback", "yes");
284 }
285
286 if (this.Chain.DisableSystemRestore)
287 {
288 writer.WriteAttributeString("DisableSystemRestore", "yes");
289 }
290
291 if (this.Chain.ParallelCache)
292 {
293 writer.WriteAttributeString("ParallelCache", "yes");
294 }
295
296 // Index a few tables by package.
297 ILookup<string, WixBundlePatchTargetCodeRow> targetCodesByPatch = this.Output.Tables["WixBundlePatchTargetCode"].RowsAs<WixBundlePatchTargetCodeRow>().ToLookup(r => r.MspPackageId);
298 ILookup<string, WixBundleMsiFeatureRow> msiFeaturesByPackage = this.Output.Tables["WixBundleMsiFeature"].RowsAs<WixBundleMsiFeatureRow>().ToLookup(r => r.ChainPackageId);
299 ILookup<string, WixBundleMsiPropertyRow> msiPropertiesByPackage = this.Output.Tables["WixBundleMsiProperty"].RowsAs<WixBundleMsiPropertyRow>().ToLookup(r => r.ChainPackageId);
300 ILookup<string, WixBundlePayloadRow> payloadsByPackage = this.Payloads.Values.ToLookup(p => p.Package);
301 ILookup<string, WixBundleRelatedPackageRow> relatedPackagesByPackage = this.Output.Tables["WixBundleRelatedPackage"].RowsAs<WixBundleRelatedPackageRow>().ToLookup(r => r.ChainPackageId);
302 ILookup<string, WixBundleSlipstreamMspRow> slipstreamMspsByPackage = this.Output.Tables["WixBundleSlipstreamMsp"].RowsAs<WixBundleSlipstreamMspRow>().ToLookup(r => r.ChainPackageId);
303 ILookup<string, WixBundlePackageExitCodeRow> exitCodesByPackage = this.Output.Tables["WixBundlePackageExitCode"].RowsAs<WixBundlePackageExitCodeRow>().ToLookup(r => r.ChainPackageId);
304 ILookup<string, WixBundlePackageCommandLineRow> commandLinesByPackage = this.Output.Tables["WixBundlePackageCommandLine"].RowsAs<WixBundlePackageCommandLineRow>().ToLookup(r => r.ChainPackageId);
305
306 // Build up the list of target codes from all the MSPs in the chain.
307 List<WixBundlePatchTargetCodeRow> targetCodes = new List<WixBundlePatchTargetCodeRow>();
308
309 foreach (PackageFacade package in this.OrderedPackages)
310 {
311 writer.WriteStartElement(String.Format(CultureInfo.InvariantCulture, "{0}Package", package.Package.Type));
312
313 writer.WriteAttributeString("Id", package.Package.WixChainItemId);
314
315 switch (package.Package.Cache)
316 {
317 case YesNoAlwaysType.No:
318 writer.WriteAttributeString("Cache", "no");
319 break;
320 case YesNoAlwaysType.Yes:
321 writer.WriteAttributeString("Cache", "yes");
322 break;
323 case YesNoAlwaysType.Always:
324 writer.WriteAttributeString("Cache", "always");
325 break;
326 }
327
328 writer.WriteAttributeString("CacheId", package.Package.CacheId);
329 writer.WriteAttributeString("InstallSize", Convert.ToString(package.Package.InstallSize));
330 writer.WriteAttributeString("Size", Convert.ToString(package.Package.Size));
331 writer.WriteAttributeString("PerMachine", YesNoDefaultType.Yes == package.Package.PerMachine ? "yes" : "no");
332 writer.WriteAttributeString("Permanent", package.Package.Permanent ? "yes" : "no");
333 writer.WriteAttributeString("Vital", (YesNoType.Yes == package.Package.Vital) ? "yes" : "no");
334
335 if (null != package.Package.RollbackBoundary)
336 {
337 writer.WriteAttributeString("RollbackBoundaryForward", package.Package.RollbackBoundary);
338 }
339
340 if (!String.IsNullOrEmpty(package.Package.RollbackBoundaryBackward))
341 {
342 writer.WriteAttributeString("RollbackBoundaryBackward", package.Package.RollbackBoundaryBackward);
343 }
344
345 if (!String.IsNullOrEmpty(package.Package.LogPathVariable))
346 {
347 writer.WriteAttributeString("LogPathVariable", package.Package.LogPathVariable);
348 }
349
350 if (!String.IsNullOrEmpty(package.Package.RollbackLogPathVariable))
351 {
352 writer.WriteAttributeString("RollbackLogPathVariable", package.Package.RollbackLogPathVariable);
353 }
354
355 if (!String.IsNullOrEmpty(package.Package.InstallCondition))
356 {
357 writer.WriteAttributeString("InstallCondition", package.Package.InstallCondition);
358 }
359
360 if (WixBundlePackageType.Exe == package.Package.Type)
361 {
362 writer.WriteAttributeString("DetectCondition", package.ExePackage.DetectCondition);
363 writer.WriteAttributeString("InstallArguments", package.ExePackage.InstallCommand);
364 writer.WriteAttributeString("UninstallArguments", package.ExePackage.UninstallCommand);
365 writer.WriteAttributeString("RepairArguments", package.ExePackage.RepairCommand);
366 writer.WriteAttributeString("Repairable", package.ExePackage.Repairable ? "yes" : "no");
367 if (!String.IsNullOrEmpty(package.ExePackage.ExeProtocol))
368 {
369 writer.WriteAttributeString("Protocol", package.ExePackage.ExeProtocol);
370 }
371 }
372 else if (WixBundlePackageType.Msi == package.Package.Type)
373 {
374 writer.WriteAttributeString("ProductCode", package.MsiPackage.ProductCode);
375 writer.WriteAttributeString("Language", package.MsiPackage.ProductLanguage.ToString(CultureInfo.InvariantCulture));
376 writer.WriteAttributeString("Version", package.MsiPackage.ProductVersion);
377 writer.WriteAttributeString("DisplayInternalUI", package.MsiPackage.DisplayInternalUI ? "yes" : "no");
378 if (!String.IsNullOrEmpty(package.MsiPackage.UpgradeCode))
379 {
380 writer.WriteAttributeString("UpgradeCode", package.MsiPackage.UpgradeCode);
381 }
382 }
383 else if (WixBundlePackageType.Msp == package.Package.Type)
384 {
385 writer.WriteAttributeString("PatchCode", package.MspPackage.PatchCode);
386 writer.WriteAttributeString("PatchXml", package.MspPackage.PatchXml);
387 writer.WriteAttributeString("DisplayInternalUI", package.MspPackage.DisplayInternalUI ? "yes" : "no");
388
389 // If there is still a chance that all of our patches will target a narrow set of
390 // product codes, add the patch list to the overall list.
391 if (null != targetCodes)
392 {
393 if (!package.MspPackage.TargetUnspecified)
394 {
395 IEnumerable<WixBundlePatchTargetCodeRow> patchTargetCodes = targetCodesByPatch[package.MspPackage.ChainPackageId];
396
397 targetCodes.AddRange(patchTargetCodes);
398 }
399 else // we have a patch that targets the world, so throw the whole list away.
400 {
401 targetCodes = null;
402 }
403 }
404 }
405 else if (WixBundlePackageType.Msu == package.Package.Type)
406 {
407 writer.WriteAttributeString("DetectCondition", package.MsuPackage.DetectCondition);
408 writer.WriteAttributeString("KB", package.MsuPackage.MsuKB);
409 }
410
411 IEnumerable<WixBundleMsiFeatureRow> packageMsiFeatures = msiFeaturesByPackage[package.Package.WixChainItemId];
412
413 foreach (WixBundleMsiFeatureRow feature in packageMsiFeatures)
414 {
415 writer.WriteStartElement("MsiFeature");
416 writer.WriteAttributeString("Id", feature.Name);
417 writer.WriteEndElement();
418 }
419
420 IEnumerable<WixBundleMsiPropertyRow> packageMsiProperties = msiPropertiesByPackage[package.Package.WixChainItemId];
421
422 foreach (WixBundleMsiPropertyRow msiProperty in packageMsiProperties)
423 {
424 writer.WriteStartElement("MsiProperty");
425 writer.WriteAttributeString("Id", msiProperty.Name);
426 writer.WriteAttributeString("Value", msiProperty.Value);
427 if (!String.IsNullOrEmpty(msiProperty.Condition))
428 {
429 writer.WriteAttributeString("Condition", msiProperty.Condition);
430 }
431 writer.WriteEndElement();
432 }
433
434 IEnumerable<WixBundleSlipstreamMspRow> packageSlipstreamMsps = slipstreamMspsByPackage[package.Package.WixChainItemId];
435
436 foreach (WixBundleSlipstreamMspRow slipstreamMsp in packageSlipstreamMsps)
437 {
438 writer.WriteStartElement("SlipstreamMsp");
439 writer.WriteAttributeString("Id", slipstreamMsp.MspPackageId);
440 writer.WriteEndElement();
441 }
442
443 IEnumerable<WixBundlePackageExitCodeRow> packageExitCodes = exitCodesByPackage[package.Package.WixChainItemId];
444
445 foreach (WixBundlePackageExitCodeRow exitCode in packageExitCodes)
446 {
447 writer.WriteStartElement("ExitCode");
448
449 if (exitCode.Code.HasValue)
450 {
451 writer.WriteAttributeString("Code", unchecked((uint)exitCode.Code).ToString(CultureInfo.InvariantCulture));
452 }
453 else
454 {
455 writer.WriteAttributeString("Code", "*");
456 }
457
458 writer.WriteAttributeString("Type", ((int)exitCode.Behavior).ToString(CultureInfo.InvariantCulture));
459 writer.WriteEndElement();
460 }
461
462 IEnumerable<WixBundlePackageCommandLineRow> packageCommandLines = commandLinesByPackage[package.Package.WixChainItemId];
463
464 foreach (WixBundlePackageCommandLineRow commandLine in packageCommandLines)
465 {
466 writer.WriteStartElement("CommandLine");
467 writer.WriteAttributeString("InstallArgument", commandLine.InstallArgument);
468 writer.WriteAttributeString("UninstallArgument", commandLine.UninstallArgument);
469 writer.WriteAttributeString("RepairArgument", commandLine.RepairArgument);
470 writer.WriteAttributeString("Condition", commandLine.Condition);
471 writer.WriteEndElement();
472 }
473
474 // Output the dependency information.
475 foreach (ProvidesDependency dependency in package.Provides)
476 {
477 // TODO: Add to wixpdb as an imported table, or link package wixpdbs to bundle wixpdbs.
478 dependency.WriteXml(writer);
479 }
480
481 IEnumerable<WixBundleRelatedPackageRow> packageRelatedPackages = relatedPackagesByPackage[package.Package.WixChainItemId];
482
483 foreach (WixBundleRelatedPackageRow related in packageRelatedPackages)
484 {
485 writer.WriteStartElement("RelatedPackage");
486 writer.WriteAttributeString("Id", related.Id);
487 if (!String.IsNullOrEmpty(related.MinVersion))
488 {
489 writer.WriteAttributeString("MinVersion", related.MinVersion);
490 writer.WriteAttributeString("MinInclusive", related.MinInclusive ? "yes" : "no");
491 }
492 if (!String.IsNullOrEmpty(related.MaxVersion))
493 {
494 writer.WriteAttributeString("MaxVersion", related.MaxVersion);
495 writer.WriteAttributeString("MaxInclusive", related.MaxInclusive ? "yes" : "no");
496 }
497 writer.WriteAttributeString("OnlyDetect", related.OnlyDetect ? "yes" : "no");
498
499 string[] relatedLanguages = related.Languages.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
500
501 if (0 < relatedLanguages.Length)
502 {
503 writer.WriteAttributeString("LangInclusive", related.LangInclusive ? "yes" : "no");
504 foreach (string language in relatedLanguages)
505 {
506 writer.WriteStartElement("Language");
507 writer.WriteAttributeString("Id", language);
508 writer.WriteEndElement();
509 }
510 }
511 writer.WriteEndElement();
512 }
513
514 // Write any contained Payloads with the PackagePayload being first
515 writer.WriteStartElement("PayloadRef");
516 writer.WriteAttributeString("Id", package.Package.PackagePayload);
517 writer.WriteEndElement();
518
519 IEnumerable<WixBundlePayloadRow> packagePayloads = payloadsByPackage[package.Package.WixChainItemId];
520
521 foreach (WixBundlePayloadRow payload in packagePayloads)
522 {
523 if (payload.Id != package.Package.PackagePayload)
524 {
525 writer.WriteStartElement("PayloadRef");
526 writer.WriteAttributeString("Id", payload.Id);
527 writer.WriteEndElement();
528 }
529 }
530
531 writer.WriteEndElement(); // </XxxPackage>
532 }
533 writer.WriteEndElement(); // </Chain>
534
535 if (null != targetCodes)
536 {
537 foreach (WixBundlePatchTargetCodeRow targetCode in targetCodes)
538 {
539 writer.WriteStartElement("PatchTargetCode");
540 writer.WriteAttributeString("TargetCode", targetCode.TargetCode);
541 writer.WriteAttributeString("Product", targetCode.TargetsProductCode ? "yes" : "no");
542 writer.WriteEndElement();
543 }
544 }
545
546 // Write the ApprovedExeForElevation elements.
547 IEnumerable<WixApprovedExeForElevationRow> approvedExesForElevation = this.Output.Tables["WixApprovedExeForElevation"].RowsAs<WixApprovedExeForElevationRow>();
548
549 foreach (WixApprovedExeForElevationRow approvedExeForElevation in approvedExesForElevation)
550 {
551 writer.WriteStartElement("ApprovedExeForElevation");
552 writer.WriteAttributeString("Id", approvedExeForElevation.Id);
553 writer.WriteAttributeString("Key", approvedExeForElevation.Key);
554
555 if (!String.IsNullOrEmpty(approvedExeForElevation.ValueName))
556 {
557 writer.WriteAttributeString("ValueName", approvedExeForElevation.ValueName);
558 }
559
560 if (approvedExeForElevation.Win64)
561 {
562 writer.WriteAttributeString("Win64", "yes");
563 }
564
565 writer.WriteEndElement();
566 }
567
568 writer.WriteEndDocument(); // </BurnManifest>
569 }
570 }
571
572 private void WriteBurnManifestContainerAttributes(XmlTextWriter writer, string executableName, WixBundleContainerRow container)
573 {
574 writer.WriteAttributeString("Id", container.Id);
575 writer.WriteAttributeString("FileSize", container.Size.ToString(CultureInfo.InvariantCulture));
576 writer.WriteAttributeString("Hash", container.Hash);
577
578 if (ContainerType.Detached == container.Type)
579 {
580 string resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id, container.Name);
581 if (!String.IsNullOrEmpty(resolvedUrl))
582 {
583 writer.WriteAttributeString("DownloadUrl", resolvedUrl);
584 }
585 else if (!String.IsNullOrEmpty(container.DownloadUrl))
586 {
587 writer.WriteAttributeString("DownloadUrl", container.DownloadUrl);
588 }
589
590 writer.WriteAttributeString("FilePath", container.Name);
591 }
592 else if (ContainerType.Attached == container.Type)
593 {
594 if (!String.IsNullOrEmpty(container.DownloadUrl))
595 {
596 Messaging.Instance.OnMessage(WixWarnings.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id));
597 }
598
599 writer.WriteAttributeString("FilePath", executableName); // attached containers use the name of the bundle since they are attached to the executable.
600 writer.WriteAttributeString("AttachedIndex", container.AttachedContainerIndex.ToString(CultureInfo.InvariantCulture));
601 writer.WriteAttributeString("Attached", "yes");
602 writer.WriteAttributeString("Primary", "yes");
603 }
604 }
605
606 private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadRow payload, bool embeddedOnly, Dictionary<string, WixBundlePayloadRow> allPayloads)
607 {
608 Debug.Assert(!embeddedOnly || PackagingType.Embedded == payload.Packaging);
609
610 writer.WriteAttributeString("Id", payload.Id);
611 writer.WriteAttributeString("FilePath", payload.Name);
612 writer.WriteAttributeString("FileSize", payload.FileSize.ToString(CultureInfo.InvariantCulture));
613 writer.WriteAttributeString("Hash", payload.Hash);
614
615 if (payload.LayoutOnly)
616 {
617 writer.WriteAttributeString("LayoutOnly", "yes");
618 }
619
620 if (!String.IsNullOrEmpty(payload.PublicKey))
621 {
622 writer.WriteAttributeString("CertificateRootPublicKeyIdentifier", payload.PublicKey);
623 }
624
625 if (!String.IsNullOrEmpty(payload.Thumbprint))
626 {
627 writer.WriteAttributeString("CertificateRootThumbprint", payload.Thumbprint);
628 }
629
630 switch (payload.Packaging)
631 {
632 case PackagingType.Embedded: // this means it's in a container.
633 if (!String.IsNullOrEmpty(payload.DownloadUrl))
634 {
635 Messaging.Instance.OnMessage(WixWarnings.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id));
636 }
637
638 writer.WriteAttributeString("Packaging", "embedded");
639 writer.WriteAttributeString("SourcePath", payload.EmbeddedId);
640
641 if (Compiler.BurnUXContainerId != payload.Container)
642 {
643 writer.WriteAttributeString("Container", payload.Container);
644 }
645 break;
646
647 case PackagingType.External:
648 string packageId = payload.ParentPackagePayload;
649 string parentUrl = payload.ParentPackagePayload == null ? null : allPayloads[payload.ParentPackagePayload].DownloadUrl;
650 string resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id, payload.Name);
651 if (!String.IsNullOrEmpty(resolvedUrl))
652 {
653 writer.WriteAttributeString("DownloadUrl", resolvedUrl);
654 }
655 else if (!String.IsNullOrEmpty(payload.DownloadUrl))
656 {
657 writer.WriteAttributeString("DownloadUrl", payload.DownloadUrl);
658 }
659
660 writer.WriteAttributeString("Packaging", "external");
661 writer.WriteAttributeString("SourcePath", payload.Name);
662 break;
663 }
664
665 if (!String.IsNullOrEmpty(payload.Catalog))
666 {
667 writer.WriteAttributeString("Catalog", payload.Catalog);
668 }
669 }
670
671 private string ResolveUrl(string url, string fallbackUrl, string packageId, string payloadId, string fileName)
672 {
673 string resolved = null;
674 foreach (var extension in this.BackendExtensions)
675 {
676 resolved = extension.ResolveUrl(url, fallbackUrl, packageId, payloadId, fileName);
677 if (!String.IsNullOrEmpty(resolved))
678 {
679 break;
680 }
681 }
682
683 return resolved;
684 }
685 }
686}