@joebigelow / wix / commits / 8b3488c8

Use new PackagePayload symbols for the package's payload.

#4183

Sean Hall committed Feb 28, 2021 at 21:05 UTC 8b3488c8c77959f425d0e5f70d27c5b2b1c86125
16 files changed +670 -116
src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+6 -1
@@ -180,12 +180,17 @@ namespace WixToolset.Core.Burn
180
181 IDictionary<string, PackageFacade> facades;
182 {
183 - var command = new GetPackageFacadesCommand(chainPackageSymbols, section);
183 + var command = new GetPackageFacadesCommand(this.Messaging, chainPackageSymbols, section);
184 command.Execute();
185
186 facades = command.PackageFacades;
187 }
188
189 + if (this.Messaging.EncounteredError)
190 + {
191 + return;
192 + }
193 +
194 // Process each package facade. Note this is likely to add payloads and other symbols so
195 // note that any indexes created above may be out of date now.
196 foreach (var facade in facades.Values)
src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs
+4
@@ -66,12 +66,16 @@ namespace WixToolset.Core.Burn.Bind
66 case SymbolDefinitionType.WixBundleContainer:
67 case SymbolDefinitionType.WixBundleCustomDataAttribute:
68 case SymbolDefinitionType.WixBundleExePackage:
69 + case SymbolDefinitionType.WixBundleExePackagePayload:
70 case SymbolDefinitionType.WixBundleExtension:
71 case SymbolDefinitionType.WixBundleMsiFeature:
72 case SymbolDefinitionType.WixBundleMsiPackage:
73 + case SymbolDefinitionType.WixBundleMsiPackagePayload:
74 case SymbolDefinitionType.WixBundleMsiProperty:
75 case SymbolDefinitionType.WixBundleMspPackage:
76 + case SymbolDefinitionType.WixBundleMspPackagePayload:
77 case SymbolDefinitionType.WixBundleMsuPackage:
78 + case SymbolDefinitionType.WixBundleMsuPackagePayload:
79 case SymbolDefinitionType.WixBundlePackage:
80 case SymbolDefinitionType.WixBundlePackageCommandLine:
81 case SymbolDefinitionType.WixBundlePackageExitCode:
src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+3 -2
@@ -564,15 +564,16 @@ namespace WixToolset.Core.Burn.Bundles
564 }
565
566 // Write any contained Payloads with the PackagePayload being first
567 + var packagePayloadId = package.PackageSymbol.PayloadRef;
568 writer.WriteStartElement("PayloadRef");
568 - writer.WriteAttributeString("Id", package.PackageSymbol.PayloadRef);
569 + writer.WriteAttributeString("Id", packagePayloadId);
570 writer.WriteEndElement();
571
572 var packagePayloads = payloadsByPackage[package.PackageId];
573
574 foreach (var payload in packagePayloads)
575 {
575 - if (payload.Id.Id != package.PackageSymbol.PayloadRef)
576 + if (payload.Id.Id != packagePayloadId)
577 {
578 writer.WriteStartElement("PayloadRef");
579 writer.WriteAttributeString("Id", payload.Id.Id);
src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs
+110 -1
@@ -6,17 +6,21 @@ namespace WixToolset.Core.Burn.Bundles
6 using System.Linq;
7 using WixToolset.Data;
8 using WixToolset.Data.Symbols;
9 + using WixToolset.Extensibility.Services;
10
11 internal class GetPackageFacadesCommand
12 {
12 - public GetPackageFacadesCommand(IEnumerable<WixBundlePackageSymbol> chainPackageSymbols, IntermediateSection section)
13 + public GetPackageFacadesCommand(IMessaging messaging, IEnumerable<WixBundlePackageSymbol> chainPackageSymbols, IntermediateSection section)
14 {
15 + this.Messaging = messaging;
16 this.ChainPackageSymbols = chainPackageSymbols;
17 this.Section = section;
18 }
19
20 private IEnumerable<WixBundlePackageSymbol> ChainPackageSymbols { get; }
21
22 + private IMessaging Messaging { get; }
23 +
24 private IntermediateSection Section { get; }
25
26 public IDictionary<string, PackageFacade> PackageFacades { get; private set; }
@@ -27,12 +31,101 @@ namespace WixToolset.Core.Burn.Bundles
31 var msiPackages = this.Section.Symbols.OfType<WixBundleMsiPackageSymbol>().ToDictionary(t => t.Id.Id);
32 var mspPackages = this.Section.Symbols.OfType<WixBundleMspPackageSymbol>().ToDictionary(t => t.Id.Id);
33 var msuPackages = this.Section.Symbols.OfType<WixBundleMsuPackageSymbol>().ToDictionary(t => t.Id.Id);
34 + var exePackagePayloads = this.Section.Symbols.OfType<WixBundleExePackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
35 + var msiPackagePayloads = this.Section.Symbols.OfType<WixBundleMsiPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
36 + var mspPackagePayloads = this.Section.Symbols.OfType<WixBundleMspPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
37 + var msuPackagePayloads = this.Section.Symbols.OfType<WixBundleMsuPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
38
39 var facades = new Dictionary<string, PackageFacade>();
40
41 foreach (var package in this.ChainPackageSymbols)
42 {
43 var id = package.Id.Id;
44 +
45 + IntermediateSymbol packagePayload = null;
46 + foreach (var wixGroup in this.Section.Symbols.OfType<WixGroupSymbol>().Where(g => g.ParentType == ComplexReferenceParentType.Package && g.ParentId == id))
47 + {
48 + if (wixGroup.ChildType == ComplexReferenceChildType.PackagePayload)
49 + {
50 + IntermediateSymbol tempPackagePayload = null;
51 + if (exePackagePayloads.TryGetValue(wixGroup.ChildId, out var exePackagePayload))
52 + {
53 + if (package.Type == WixBundlePackageType.Exe)
54 + {
55 + tempPackagePayload = exePackagePayload;
56 + }
57 + else
58 + {
59 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(exePackagePayload.SourceLineNumbers, "Exe"));
60 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
61 + }
62 + }
63 + else if (msiPackagePayloads.TryGetValue(wixGroup.ChildId, out var msiPackagePayload))
64 + {
65 + if (package.Type == WixBundlePackageType.Msi)
66 + {
67 + tempPackagePayload = msiPackagePayload;
68 + }
69 + else
70 + {
71 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(msiPackagePayload.SourceLineNumbers, "Msi"));
72 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
73 + }
74 + }
75 + else if (mspPackagePayloads.TryGetValue(wixGroup.ChildId, out var mspPackagePayload))
76 + {
77 + if (package.Type == WixBundlePackageType.Msp)
78 + {
79 + tempPackagePayload = mspPackagePayload;
80 + }
81 + else
82 + {
83 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(mspPackagePayload.SourceLineNumbers, "Msp"));
84 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
85 + }
86 + }
87 + else if (msuPackagePayloads.TryGetValue(wixGroup.ChildId, out var msuPackagePayload))
88 + {
89 + if (package.Type == WixBundlePackageType.Msu)
90 + {
91 + tempPackagePayload = msuPackagePayload;
92 + }
93 + else
94 + {
95 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(msuPackagePayload.SourceLineNumbers, "Msu"));
96 + this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
97 + }
98 + }
99 + else
100 + {
101 + this.Messaging.Write(ErrorMessages.IdentifierNotFound(package.Type + "PackagePayload", wixGroup.ChildId));
102 + }
103 +
104 + if (tempPackagePayload != null)
105 + {
106 + if (packagePayload == null)
107 + {
108 + packagePayload = tempPackagePayload;
109 + }
110 + else
111 + {
112 + this.Messaging.Write(ErrorMessages.MultiplePackagePayloads(tempPackagePayload.SourceLineNumbers, id, packagePayload.Id.Id, tempPackagePayload.Id.Id));
113 + this.Messaging.Write(ErrorMessages.MultiplePackagePayloads2(packagePayload.SourceLineNumbers));
114 + this.Messaging.Write(ErrorMessages.MultiplePackagePayloads3(package.SourceLineNumbers));
115 + }
116 + }
117 + }
118 + }
119 +
120 + if (packagePayload == null)
121 + {
122 + this.Messaging.Write(ErrorMessages.MissingPackagePayload(package.SourceLineNumbers, id, package.Type.ToString()));
123 + }
124 + else
125 + {
126 + package.PayloadRef = packagePayload.Id.Id;
127 + }
128 +
129 switch (package.Type)
130 {
131 case WixBundlePackageType.Exe:
@@ -40,6 +133,10 @@ namespace WixToolset.Core.Burn.Bundles
133 {
134 facades.Add(id, new PackageFacade(package, exePackage));
135 }
136 + else
137 + {
138 + this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleExePackage", id));
139 + }
140 break;
141
142 case WixBundlePackageType.Msi:
@@ -47,6 +144,10 @@ namespace WixToolset.Core.Burn.Bundles
144 {
145 facades.Add(id, new PackageFacade(package, msiPackage));
146 }
147 + else
148 + {
149 + this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleMsiPackage", id));
150 + }
151 break;
152
153 case WixBundlePackageType.Msp:
@@ -54,6 +155,10 @@ namespace WixToolset.Core.Burn.Bundles
155 {
156 facades.Add(id, new PackageFacade(package, mspPackage));
157 }
158 + else
159 + {
160 + this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleMspPackage", id));
161 + }
162 break;
163
164 case WixBundlePackageType.Msu:
@@ -61,6 +166,10 @@ namespace WixToolset.Core.Burn.Bundles
166 {
167 facades.Add(id, new PackageFacade(package, msuPackage));
168 }
169 + else
170 + {
171 + this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleMsuPackage", id));
172 + }
173 break;
174 }
175 }
src/WixToolset.Core/Compile/CompilerPayload.cs
+68 -25
@@ -23,6 +23,8 @@ namespace WixToolset.Core
23
24 public Identifier Id { get; set; }
25
26 + public bool IsRemoteAllowed { get; set; }
27 +
28 public bool IsRequired { get; set; } = true;
29
30 public string Name { get; set; }
@@ -48,26 +50,17 @@ namespace WixToolset.Core
50
51 private SourceLineNumber SourceLineNumbers { get; }
52
51 - private void CalculateAndVerifyFields(CompilerPayload remotePayload = null)
53 + private void CalculateAndVerifyFields()
54 {
55 + var isRemote = this.IsRemoteAllowed && !String.IsNullOrEmpty(this.Hash);
56 +
57 if (String.IsNullOrEmpty(this.SourceFile))
58 {
55 - if (String.IsNullOrEmpty(this.Name))
56 - {
57 - if (this.IsRequired)
58 - {
59 - this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "SourceFile"));
60 - }
61 - }
62 - else if (remotePayload == null)
59 + if (!String.IsNullOrEmpty(this.Name) && !isRemote)
60 {
61 this.SourceFile = Path.Combine("SourceDir", this.Name);
62 }
63 }
67 - else if (remotePayload != null)
68 - {
69 - this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "RemotePayload", "SourceFile"));
70 - }
64 else if (this.SourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
65 {
66 if (String.IsNullOrEmpty(this.Name))
@@ -80,24 +73,67 @@ namespace WixToolset.Core
73 }
74 }
75
83 - if (remotePayload != null)
76 + if (String.IsNullOrEmpty(this.SourceFile) && !isRemote)
77 {
85 - if (this.DownloadUrl == null)
78 + if (this.IsRequired)
79 {
87 - this.Core.Write(ErrorMessages.ExpectedAttributeWithElement(this.SourceLineNumbers, this.Element.Name.LocalName, "DownloadUrl", "RemotePayload"));
80 + if (!this.IsRemoteAllowed)
81 + {
82 + this.Core.Write(ErrorMessages.ExpectedAttributes(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "SourceFile"));
83 + }
84 + else
85 + {
86 + this.Core.Write(ErrorMessages.ExpectedAttributes(this.SourceLineNumbers, this.Element.Name.LocalName, "SourceFile", "Hash"));
87 + }
88 }
89 + }
90 + else if (this.IsRemoteAllowed)
91 + {
92 + var isLocal = !String.IsNullOrEmpty(this.SourceFile);
93
90 - if (YesNoDefaultType.No != this.Compressed)
94 + if (isLocal)
95 + {
96 + if (isRemote)
97 + {
98 + this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", "SourceFile"));
99 + }
100 + }
101 + else
102 {
103 + if (String.IsNullOrEmpty(this.DownloadUrl))
104 + {
105 + this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "DownloadUrl", "Hash"));
106 + }
107 +
108 + if (String.IsNullOrEmpty(this.Name))
109 + {
110 + this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "Hash"));
111 + }
112 +
113 + if (YesNoDefaultType.Yes == this.Compressed)
114 + {
115 + this.Core.Write(WarningMessages.RemotePayloadsMustNotAlsoBeCompressed(this.SourceLineNumbers, this.Element.Name.LocalName));
116 + }
117 +
118 this.Compressed = YesNoDefaultType.No;
93 - this.Core.Write(WarningMessages.RemotePayloadsMustNotAlsoBeCompressed(this.SourceLineNumbers, this.Element.Name.LocalName));
119 }
120
96 - this.Description = remotePayload.Description;
97 - this.DisplayName = remotePayload.DisplayName;
98 - this.Hash = remotePayload.Hash;
99 - this.Size = remotePayload.Size;
100 - this.Version = remotePayload.Version;
121 + VerifyValidValue("Description", !String.IsNullOrEmpty(this.Description));
122 + VerifyValidValue("ProductName", !String.IsNullOrEmpty(this.ProductName));
123 + VerifyValidValue("Size", this.Size.HasValue);
124 + VerifyValidValue("Version", !String.IsNullOrEmpty(this.Version));
125 +
126 + void VerifyValidValue(string attributeName, bool isSpecified)
127 + {
128 + if (isLocal && isSpecified)
129 + {
130 + this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, attributeName, "SourceFile"));
131 + }
132 + else if (!isLocal && !isSpecified)
133 + {
134 + this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, attributeName, "Hash"));
135 + }
136 + }
137 }
138 }
139
@@ -143,9 +179,9 @@ namespace WixToolset.Core
179 return symbol;
180 }
181
146 - public void FinishCompilingPackage(CompilerPayload remotePayload)
182 + public void FinishCompilingPackage()
183 {
148 - this.CalculateAndVerifyFields(remotePayload);
184 + this.CalculateAndVerifyFields();
185 this.GenerateIdFromFilename();
186
187 if (this.Id == null)
@@ -155,6 +191,13 @@ namespace WixToolset.Core
191 }
192 }
193
194 + public void FinishCompilingPackagePayload()
195 + {
196 + this.CalculateAndVerifyFields();
197 + this.GenerateIdFromFilename();
198 + this.GenerateIdFromPrefix("ppy");
199 + }
200 +
201 public void FinishCompilingPayload()
202 {
203 this.CalculateAndVerifyFields();
src/WixToolset.Core/Compiler_Bundle.cs
+187 -81
@@ -1451,71 +1451,6 @@ namespace WixToolset.Core
1451 return compilerPayload.Id;
1452 }
1453
1454 - private CompilerPayload ParseRemotePayloadElement(XElement node)
1455 - {
1456 - var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1457 - var remotePayload = new CompilerPayload(this.Core, sourceLineNumbers, node);
1458 -
1459 - foreach (var attrib in node.Attributes())
1460 - {
1461 - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1462 - {
1463 - switch (attrib.Name.LocalName)
1464 - {
1465 - case "Description":
1466 - remotePayload.ParseDescription(attrib);
1467 - break;
1468 - case "Hash":
1469 - remotePayload.ParseHash(attrib);
1470 - break;
1471 - case "ProductName":
1472 - remotePayload.ParseProductName(attrib);
1473 - break;
1474 - case "Size":
1475 - remotePayload.ParseSize(attrib);
1476 - break;
1477 - case "Version":
1478 - remotePayload.ParseVersion(attrib);
1479 - break;
1480 - default:
1481 - this.Core.UnexpectedAttribute(node, attrib);
1482 - break;
1483 - }
1484 - }
1485 - else
1486 - {
1487 - this.Core.ParseExtensionAttribute(node, attrib);
1488 - }
1489 - }
1490 -
1491 - if (String.IsNullOrEmpty(remotePayload.ProductName))
1492 - {
1493 - this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProductName"));
1494 - }
1495 -
1496 - if (String.IsNullOrEmpty(remotePayload.Description))
1497 - {
1498 - this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description"));
1499 - }
1500 -
1501 - if (String.IsNullOrEmpty(remotePayload.Hash))
1502 - {
1503 - this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Hash"));
1504 - }
1505 -
1506 - if (0 == remotePayload.Size)
1507 - {
1508 - this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Size"));
1509 - }
1510 -
1511 - if (String.IsNullOrEmpty(remotePayload.Version))
1512 - {
1513 - this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
1514 - }
1515 -
1516 - return remotePayload;
1517 - }
1518 -
1454 /// <summary>
1455 /// Parse PayloadGroup element.
1456 /// </summary>
@@ -1561,8 +1496,21 @@ namespace WixToolset.Core
1496 {
1497 if (CompilerCore.WixNamespace == child.Name.Namespace)
1498 {
1499 + WixBundlePackageType? packageType = null;
1500 switch (child.Name.LocalName)
1501 {
1502 + case "ExePackagePayload":
1503 + packageType = WixBundlePackageType.Exe;
1504 + break;
1505 + case "MsiPackagePayload":
1506 + packageType = WixBundlePackageType.Msi;
1507 + break;
1508 + case "MspPackagePayload":
1509 + packageType = WixBundlePackageType.Msp;
1510 + break;
1511 + case "MsuPackagePayload":
1512 + packageType = WixBundlePackageType.Msu;
1513 + break;
1514 case "Payload":
1515 previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id, previousType, previousId);
1516 previousType = ComplexReferenceChildType.Payload;
@@ -1575,6 +1523,19 @@ namespace WixToolset.Core
1523 this.Core.UnexpectedElement(node, child);
1524 break;
1525 }
1526 +
1527 + if (packageType.HasValue)
1528 + {
1529 + var compilerPayload = this.ParsePackagePayloadElement(null, child, packageType.Value, null);
1530 + var payloadSymbol = compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.PayloadGroup, id?.Id, previousType, previousId?.Id);
1531 + if (payloadSymbol != null)
1532 + {
1533 + previousId = payloadSymbol.Id;
1534 + previousType = ComplexReferenceChildType.Payload;
1535 +
1536 + this.CreatePackagePayloadSymbol(payloadSymbol.SourceLineNumbers, packageType.Value, payloadSymbol.Id, ComplexReferenceParentType.PayloadGroup, id);
1537 + }
1538 + }
1539 }
1540 else
1541 {
@@ -1984,7 +1945,7 @@ namespace WixToolset.Core
1945 Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType);
1946 Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType);
1947
1987 - var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);;
1948 + var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1949 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node)
1950 {
1951 IsRequired = false,
@@ -2008,8 +1969,9 @@ namespace WixToolset.Core
1969 string msuKB = null;
1970 var enableFeatureSelection = YesNoType.NotSet;
1971 var forcePerMachine = YesNoType.NotSet;
2011 - CompilerPayload remotePayload = null;
1972 + CompilerPayload childPackageCompilerPayload = null;
1973 var slipstream = YesNoType.NotSet;
1974 + var hasPayloadInfo = false;
1975
1976 var expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" };
1977
@@ -2029,12 +1991,15 @@ namespace WixToolset.Core
1991 break;
1992 case "Name":
1993 compilerPayload.ParseName(attrib);
1994 + hasPayloadInfo = true;
1995 break;
1996 case "SourceFile":
1997 compilerPayload.ParseSourceFile(attrib);
1998 + hasPayloadInfo = true;
1999 break;
2000 case "DownloadUrl":
2001 compilerPayload.ParseDownloadUrl(attrib);
2002 + hasPayloadInfo = true;
2003 break;
2004 case "After":
2005 after = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -2128,6 +2093,7 @@ namespace WixToolset.Core
2093 break;
2094 case "Compressed":
2095 compilerPayload.ParseCompressed(attrib);
2096 + hasPayloadInfo = true;
2097 break;
2098 case "Slipstream":
2099 slipstream = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
@@ -2150,26 +2116,30 @@ namespace WixToolset.Core
2116 }
2117 }
2118
2153 - // We need to handle RemotePayload up front because it effects value of sourceFile which is used in Id generation. Id is needed by other child elements.
2154 - foreach (var child in node.Elements(CompilerCore.WixNamespace + "RemotePayload"))
2119 + // We need to handle the package payload up front because it affects Id generation. Id is needed by other child elements.
2120 + var packagePayloadElementName = packageType + "PackagePayload";
2121 + foreach (var child in node.Elements(CompilerCore.WixNamespace + packagePayloadElementName))
2122 {
2123 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
2124
2158 - if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage" && node.Name.LocalName != "MsuPackage")
2125 + if (childPackageCompilerPayload != null)
2126 {
2160 - this.Core.Write(ErrorMessages.RemotePayloadUnsupported(childSourceLineNumbers));
2161 - continue;
2127 + this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName));
2128 }
2163 -
2164 - if (null != remotePayload)
2129 + else if (hasPayloadInfo)
2130 {
2166 - this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName));
2131 + this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "SourceFile", "Name", "DownloadUrl", "Compressed"));
2132 }
2133
2169 - remotePayload = this.ParseRemotePayloadElement(child);
2134 + childPackageCompilerPayload = this.ParsePackagePayloadElement(childSourceLineNumbers, child, packageType, compilerPayload.Id);
2135 + }
2136 +
2137 + if (compilerPayload.Id == null && childPackageCompilerPayload != null)
2138 + {
2139 + compilerPayload.Id = childPackageCompilerPayload.Id;
2140 }
2141
2172 - compilerPayload.FinishCompilingPackage(remotePayload);
2142 + compilerPayload.FinishCompilingPackage();
2143 var id = compilerPayload.Id;
2144
2145 if (null == logPathVariable)
@@ -2279,7 +2249,11 @@ namespace WixToolset.Core
2249 this.ParseCommandLineElement(child, id.Id);
2250 }
2251 break;
2282 - case "RemotePayload":
2252 + case "ExePackagePayload":
2253 + case "MsiPackagePayload":
2254 + case "MspPackagePayload":
2255 + case "MsuPackagePayload":
2256 + allowed = packagePayloadElementName == child.Name.LocalName;
2257 // Handled previously
2258 break;
2259 default:
@@ -2301,8 +2275,13 @@ namespace WixToolset.Core
2275
2276 if (!this.Core.EncounteredError)
2277 {
2304 - // We create the package contents as a payload with this package as the parent
2305 - compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Package, id.Id);
2278 + var packageCompilerPayload = childPackageCompilerPayload ?? (hasPayloadInfo ? compilerPayload : null);
2279 + if (packageCompilerPayload != null)
2280 + {
2281 + var payload = packageCompilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Package, id.Id);
2282 +
2283 + this.CreatePackagePayloadSymbol(sourceLineNumbers, packageType, payload.Id, ComplexReferenceParentType.Package, id);
2284 + }
2285
2286 this.Core.AddSymbol(new WixChainItemSymbol(sourceLineNumbers, id));
2287
@@ -2313,7 +2292,6 @@ namespace WixToolset.Core
2292 var chainPackageSymbol = this.Core.AddSymbol(new WixBundlePackageSymbol(sourceLineNumbers, id)
2293 {
2294 Type = packageType,
2316 - PayloadRef = id.Id,
2295 Attributes = attributes,
2296 InstallCondition = installCondition,
2297 CacheId = cacheId,
@@ -2391,6 +2369,134 @@ namespace WixToolset.Core
2369 return id.Id;
2370 }
2371
2372 + private void CreatePackagePayloadSymbol(SourceLineNumber sourceLineNumbers, WixBundlePackageType packageType, Identifier payloadId, ComplexReferenceParentType parentType, Identifier parentId)
2373 + {
2374 + switch (packageType)
2375 + {
2376 + case WixBundlePackageType.Exe:
2377 + this.Core.AddSymbol(new WixBundleExePackagePayloadSymbol(sourceLineNumbers, payloadId));
2378 + break;
2379 +
2380 + case WixBundlePackageType.Msi:
2381 + this.Core.AddSymbol(new WixBundleMsiPackagePayloadSymbol(sourceLineNumbers, payloadId));
2382 + break;
2383 +
2384 + case WixBundlePackageType.Msp:
2385 + this.Core.AddSymbol(new WixBundleMspPackagePayloadSymbol(sourceLineNumbers, payloadId));
2386 + break;
2387 +
2388 + case WixBundlePackageType.Msu:
2389 + this.Core.AddSymbol(new WixBundleMsuPackagePayloadSymbol(sourceLineNumbers, payloadId));
2390 + break;
2391 + }
2392 +
2393 + this.Core.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId?.Id, ComplexReferenceChildType.PackagePayload, payloadId?.Id, ComplexReferenceChildType.Unknown, null);
2394 + }
2395 +
2396 + private CompilerPayload ParsePackagePayloadElement(SourceLineNumber sourceLineNumbers, XElement node, WixBundlePackageType packageType, Identifier defaultId)
2397 + {
2398 + sourceLineNumbers = sourceLineNumbers ?? Preprocessor.GetSourceLineNumbers(node);
2399 + var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node)
2400 + {
2401 + Id = defaultId,
2402 + IsRemoteAllowed = packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu,
2403 + };
2404 +
2405 + // This list lets us evaluate extension attributes *after* all core attributes
2406 + // have been parsed and dealt with, regardless of authoring order.
2407 + var extensionAttributes = new List<XAttribute>();
2408 +
2409 + foreach (var attrib in node.Attributes())
2410 + {
2411 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2412 + {
2413 + var allowed = true;
2414 + switch (attrib.Name.LocalName)
2415 + {
2416 + case "Id":
2417 + compilerPayload.ParseId(attrib);
2418 + break;
2419 + case "Compressed":
2420 + compilerPayload.ParseCompressed(attrib);
2421 + break;
2422 + case "Name":
2423 + compilerPayload.ParseName(attrib);
2424 + break;
2425 + case "SourceFile":
2426 + compilerPayload.ParseSourceFile(attrib);
2427 + break;
2428 + case "DownloadUrl":
2429 + compilerPayload.ParseDownloadUrl(attrib);
2430 + break;
2431 + case "Description":
2432 + allowed = compilerPayload.IsRemoteAllowed;
2433 + if (allowed)
2434 + {
2435 + compilerPayload.ParseDescription(attrib);
2436 + }
2437 + break;
2438 + case "Hash":
2439 + allowed = compilerPayload.IsRemoteAllowed;
2440 + if (allowed)
2441 + {
2442 + compilerPayload.ParseHash(attrib);
2443 + }
2444 + break;
2445 + case "ProductName":
2446 + allowed = compilerPayload.IsRemoteAllowed;
2447 + if (allowed)
2448 + {
2449 + compilerPayload.ParseProductName(attrib);
2450 + }
2451 + break;
2452 + case "Size":
2453 + allowed = compilerPayload.IsRemoteAllowed;
2454 + if (allowed)
2455 + {
2456 + compilerPayload.ParseSize(attrib);
2457 + }
2458 + break;
2459 + case "Version":
2460 + allowed = compilerPayload.IsRemoteAllowed;
2461 + if (allowed)
2462 + {
2463 + compilerPayload.ParseVersion(attrib);
2464 + }
2465 + break;
2466 + default:
2467 + allowed = false;
2468 + break;
2469 + }
2470 +
2471 + if (!allowed)
2472 + {
2473 + this.Core.UnexpectedAttribute(node, attrib);
2474 + }
2475 + }
2476 + else
2477 + {
2478 + this.Core.ParseExtensionAttribute(node, attrib);
2479 + }
2480 + }
2481 +
2482 + compilerPayload.FinishCompilingPackagePayload();
2483 +
2484 + // Now that the PayloadId is known, we can parse the extension attributes.
2485 + var context = new Dictionary<string, string>
2486 + {
2487 + ["Id"] = compilerPayload.Id.Id,
2488 + };
2489 +
2490 + foreach (var extensionAttribute in extensionAttributes)
2491 + {
2492 + this.Core.ParseExtensionAttribute(node, extensionAttribute, context);
2493 + }
2494 +
2495 + this.Core.ParseForExtensionElements(node);
2496 +
2497 + return compilerPayload;
2498 + }
2499 +
2500 /// <summary>
2501 /// Parse CommandLine element.
2502 /// </summary>
src/WixToolset.Core/Linker.cs
+1 -1
@@ -1242,7 +1242,7 @@ namespace WixToolset.Core
1242 var groups = new WixGroupingOrdering(entrySection, this.Messaging);
1243
1244 // Create UX payloads and Package payloads
1245 - groups.UseTypes(new[] { ComplexReferenceParentType.Container, ComplexReferenceParentType.Layout, ComplexReferenceParentType.PackageGroup, ComplexReferenceParentType.PayloadGroup, ComplexReferenceParentType.Package }, new[] { ComplexReferenceChildType.PackageGroup, ComplexReferenceChildType.Package, ComplexReferenceChildType.PayloadGroup, ComplexReferenceChildType.Payload });
1245 + groups.UseTypes(new[] { ComplexReferenceParentType.Container, ComplexReferenceParentType.Layout, ComplexReferenceParentType.PackageGroup, ComplexReferenceParentType.PayloadGroup, ComplexReferenceParentType.Package }, new[] { ComplexReferenceChildType.PackageGroup, ComplexReferenceChildType.Package, ComplexReferenceChildType.PackagePayload, ComplexReferenceChildType.PayloadGroup, ComplexReferenceChildType.Payload });
1246 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Package, false);
1247 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Container, false);
1248 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Layout, false);
src/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs new
+207
@@ -0,0 +1,207 @@
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 WixToolsetTest.CoreIntegration
4 +{
5 + using System.Collections.Generic;
6 + using System.IO;
7 + using System.Linq;
8 + using WixBuildTools.TestSupport;
9 + using WixToolset.Core.TestPackage;
10 + using Xunit;
11 +
12 + public class PackagePayloadFixture
13 + {
14 + [Fact]
15 + public void CanSpecifyPackagePayloadInPayloadGroup()
16 + {
17 + var folder = TestData.Get(@"TestData");
18 +
19 + using (var fs = new DisposableFileSystem())
20 + {
21 + var baseFolder = fs.GetFolder();
22 + var intermediateFolder = Path.Combine(baseFolder, "obj");
23 + var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
24 + var baFolderPath = Path.Combine(baseFolder, "ba");
25 + var extractFolderPath = Path.Combine(baseFolder, "extract");
26 +
27 + var result = WixRunner.Execute(new[]
28 + {
29 + "build",
30 + Path.Combine(folder, "PackagePayload", "PackagePayloadInPayloadGroup.wxs"),
31 + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
32 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
33 + "-bindpath", Path.Combine(folder, ".Data"),
34 + "-intermediateFolder", intermediateFolder,
35 + "-o", bundlePath,
36 + });
37 +
38 + result.AssertSuccess();
39 +
40 + Assert.True(File.Exists(bundlePath));
41 +
42 + var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
43 + extractResult.AssertSuccess();
44 +
45 + var exePackageElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:ExePackage");
46 + var ignoreAttributesByElementName = new Dictionary<string, List<string>>
47 + {
48 + { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } },
49 + };
50 + Assert.Equal(1, exePackageElements.Count);
51 + Assert.Equal("<ExePackage Id='PackagePayloadInPayloadGroup' Cache='yes' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_PackagePayloadInPayloadGroup' RollbackLogPathVariable='WixBundleRollbackLog_PackagePayloadInPayloadGroup' DetectCondition='none' InstallArguments='' UninstallArguments='' RepairArguments='' Repairable='no'><PayloadRef Id='burn.exe' /></ExePackage>", exePackageElements[0].GetTestXml(ignoreAttributesByElementName));
52 + }
53 + }
54 +
55 + [Fact]
56 + public void ErrorWhenMissingSourceFileAndHash()
57 + {
58 + var folder = TestData.Get(@"TestData", "PackagePayload");
59 +
60 + using (var fs = new DisposableFileSystem())
61 + {
62 + var baseFolder = fs.GetFolder();
63 +
64 + var result = WixRunner.Execute(false, new[]
65 + {
66 + "build",
67 + Path.Combine(folder, "MissingSourceFileAndHash.wxs"),
68 + "-o", Path.Combine(baseFolder, "test.wixlib")
69 + });
70 +
71 + Assert.Equal(44, result.ExitCode);
72 + WixAssert.CompareLineByLine(new[]
73 + {
74 + "The MsuPackagePayload element's SourceFile or Hash attribute was not found; one of these is required.",
75 + }, result.Messages.Select(m => m.ToString()).ToArray());
76 + }
77 + }
78 +
79 + [Fact]
80 + public void ErrorWhenMissingSourceFileAndName()
81 + {
82 + var folder = TestData.Get(@"TestData", "PackagePayload");
83 +
84 + using (var fs = new DisposableFileSystem())
85 + {
86 + var baseFolder = fs.GetFolder();
87 +
88 + var result = WixRunner.Execute(false, new[]
89 + {
90 + "build",
91 + Path.Combine(folder, "MissingSourceFileAndName.wxs"),
92 + "-o", Path.Combine(baseFolder, "test.wixlib")
93 + });
94 +
95 + Assert.Equal(44, result.ExitCode);
96 + WixAssert.CompareLineByLine(new[]
97 + {
98 + "The MsiPackagePayload element's Name or SourceFile attribute was not found; one of these is required.",
99 + }, result.Messages.Select(m => m.ToString()).ToArray());
100 + }
101 + }
102 +
103 + [Fact]
104 + public void ErrorWhenSpecifiedHash()
105 + {
106 + var folder = TestData.Get(@"TestData", "PackagePayload");
107 +
108 + using (var fs = new DisposableFileSystem())
109 + {
110 + var baseFolder = fs.GetFolder();
111 +
112 + var result = WixRunner.Execute(new[]
113 + {
114 + "build",
115 + Path.Combine(folder, "SpecifiedHash.wxs"),
116 + "-o", Path.Combine(baseFolder, "test.wixlib")
117 + });
118 +
119 + Assert.Equal(4, result.ExitCode);
120 + WixAssert.CompareLineByLine(new[]
121 + {
122 + "The MspPackagePayload element contains an unexpected attribute 'Hash'.",
123 + }, result.Messages.Select(m => m.ToString()).ToArray());
124 + }
125 + }
126 +
127 + [Fact]
128 + public void ErrorWhenSpecifiedHashAndMissingDownloadUrl()
129 + {
130 + var folder = TestData.Get(@"TestData", "PackagePayload");
131 +
132 + using (var fs = new DisposableFileSystem())
133 + {
134 + var baseFolder = fs.GetFolder();
135 +
136 + var result = WixRunner.Execute(new[]
137 + {
138 + "build",
139 + Path.Combine(folder, "SpecifiedHashAndMissingDownloadUrl.wxs"),
140 + "-o", Path.Combine(baseFolder, "test.wixlib")
141 + });
142 +
143 + Assert.Equal(10, result.ExitCode);
144 + WixAssert.CompareLineByLine(new[]
145 + {
146 + "The MsuPackagePayload/@DownloadUrl attribute was not found; it is required when attribute Hash is specified.",
147 + }, result.Messages.Select(m => m.ToString()).ToArray());
148 + }
149 + }
150 +
151 + [Fact]
152 + public void ErrorWhenSpecifiedSourceFileAndHash()
153 + {
154 + var folder = TestData.Get(@"TestData", "PackagePayload");
155 +
156 + using (var fs = new DisposableFileSystem())
157 + {
158 + var baseFolder = fs.GetFolder();
159 +
160 + var result = WixRunner.Execute(new[]
161 + {
162 + "build",
163 + Path.Combine(folder, "SpecifiedSourceFileAndHash.wxs"),
164 + "-o", Path.Combine(baseFolder, "test.wixlib")
165 + });
166 +
167 + Assert.Equal(35, result.ExitCode);
168 + WixAssert.CompareLineByLine(new[]
169 + {
170 + "The ExePackagePayload/@Hash attribute cannot be specified when attribute SourceFile is present.",
171 + }, result.Messages.Select(m => m.ToString()).ToArray());
172 + }
173 + }
174 +
175 + [Fact]
176 + public void ErrorWhenWrongPackagePayloadInPayloadGroup()
177 + {
178 + var folder = TestData.Get(@"TestData");
179 +
180 + using (var fs = new DisposableFileSystem())
181 + {
182 + var baseFolder = fs.GetFolder();
183 + var intermediateFolder = Path.Combine(baseFolder, "obj");
184 + var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
185 +
186 + var result = WixRunner.Execute(new[]
187 + {
188 + "build",
189 + Path.Combine(folder, "PackagePayload", "WrongPackagePayloadInPayloadGroup.wxs"),
190 + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
191 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
192 + "-bindpath", Path.Combine(folder, ".Data"),
193 + "-intermediateFolder", intermediateFolder,
194 + "-o", bundlePath,
195 + });
196 +
197 + Assert.Equal(407, result.ExitCode);
198 + WixAssert.CompareLineByLine(new[]
199 + {
200 + "The ExePackagePayload element can only be used for ExePackages.",
201 + "The location of the package related to previous error.",
202 + "There is no payload defined for package 'WrongPackagePayloadInPayloadGroup'. This is specified on the MsiPackage element or a child MsiPackagePayload element.",
203 + }, result.Messages.Select(m => m.ToString()).ToArray());
204 + }
205 + }
206 + }
207 +}
src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndHash.wxs new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <MsuPackage Id="MissingSourceFileAndHash" Permanent="yes" DetectCondition="none">
6 + <MsuPackagePayload DownloadUrl="example.com" />
7 + </MsuPackage>
8 + </PackageGroup>
9 + </Fragment>
10 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndName.wxs new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <MsiPackage Id="MissingSourceFileAndName">
6 + <MsiPackagePayload DownloadUrl="example.com" />
7 + </MsiPackage>
8 + </PackageGroup>
9 + </Fragment>
10 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/PackagePayloadInPayloadGroup.wxs new
+15
@@ -0,0 +1,15 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <ExePackage Id="PackagePayloadInPayloadGroup" Permanent="yes" DetectCondition="none">
6 + <PayloadGroupRef Id="PackagePayloadGroup" />
7 + </ExePackage>
8 + </PackageGroup>
9 + </Fragment>
10 + <Fragment>
11 + <PayloadGroup Id="PackagePayloadGroup">
12 + <ExePackagePayload SourceFile="burn.exe" />
13 + </PayloadGroup>
14 + </Fragment>
15 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHash.wxs new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <MspPackage Id="SpecifiedHash">
6 + <MspPackagePayload SourceFile="example.msp" DownloadUrl="example.com" Hash="abcd" />
7 + </MspPackage>
8 + </PackageGroup>
9 + </Fragment>
10 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndMissingDownloadUrl.wxs new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <MsuPackage Id="SpecifiedHashAndMissingDownloadUrl" Permanent="yes" DetectCondition="none">
6 + <MsuPackagePayload Name="example.msu" Hash="abcd" Size="1" Version="1.0.0.0" ProductName="KB1234567" Description="fake msu" />
7 + </MsuPackage>
8 + </PackageGroup>
9 + </Fragment>
10 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndHash.wxs new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <ExePackage Id="SpecifiedSourceFileAndHash" Permanent="yes" DetectCondition="none">
6 + <ExePackagePayload SourceFile="example.exe" Hash="abcd" />
7 + </ExePackage>
8 + </PackageGroup>
9 + </Fragment>
10 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/WrongPackagePayloadInPayloadGroup.wxs new
+15
@@ -0,0 +1,15 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <MsiPackage Id="WrongPackagePayloadInPayloadGroup">
6 + <PayloadGroupRef Id="WrongPackagePayloadGroup" />
7 + </MsiPackage>
8 + </PackageGroup>
9 + </Fragment>
10 + <Fragment>
11 + <PayloadGroup Id="WrongPackagePayloadGroup">
12 + <ExePackagePayload SourceFile="burn.exe" />
13 + </PayloadGroup>
14 + </Fragment>
15 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/SingleExeBundle/SingleExeRemotePayload.wxs
+4 -5
@@ -13,11 +13,10 @@
13 Vital="yes"
14 Permanent="yes"
15 Protocol="netfx4"
16 - DownloadUrl="C"
17 - LogPathVariable="NetFx462FullLog"
18 - Compressed="no"
19 - Name="NDP462-KB3151802-Web.exe">
20 - <RemotePayload
16 + LogPathVariable="NetFx462FullLog">
17 + <ExePackagePayload
18 + DownloadUrl="C"
19 + Name="NDP462-KB3151802-Web.exe"
20 Description="Microsoft .NET Framework 4.6.2 Setup"
21 Hash="C42E6ED280290648BBD59F664008852F4CFE4548"
22 ProductName="Microsoft .NET Framework 4.6.2"