diff options
Diffstat (limited to 'src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs')
-rw-r--r-- | src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs | 686 |
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 | |||
3 | namespace 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 | } | ||