Add support for remote BundlePackagePayload.
Sean Hall committed
Apr 13, 2022 at 12:16 UTC
faa9777b7720a935b28c33c3fa1088cd7bcc2f86
9 files changed
+407
-10
src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs
+2
-1
@@ -422,7 +422,8 @@ namespace WixToolset.Extensibility.Services
422
/// <param name="intermediate">Parent intermediate.</param>
423
/// <param name="section">Parent section.</param>
424
/// <param name="element">Element to parse children.</param>
425
- void ParseForExtensionElements(IEnumerable<ICompilerExtension> extensions, Intermediate intermediate, IntermediateSection section, XElement element);
425
+ /// <param name="context">Extra information about the context in which this element is being parsed.</param>
426
+ void ParseForExtensionElements(IEnumerable<ICompilerExtension> extensions, Intermediate intermediate, IntermediateSection section, XElement element, IDictionary<string, string> context = null);
427
428
/// <summary>
429
/// Schedules an action symbol.
src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs
+1
-1
@@ -57,7 +57,7 @@ namespace WixToolset.Core.Burn.Bundles
57
public void Execute()
58
{
59
var harvestedBundlePackage = this.Section.Symbols.OfType<WixBundleHarvestedBundlePackageSymbol>()
60
- .Where(h => h.Id == this.PackagePayload.Id)
60
+ .Where(h => h.Id.Id == this.PackagePayload.Id.Id)
61
.SingleOrDefault();
62
63
if (harvestedBundlePackage == null)
src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+1
-1
@@ -65,7 +65,7 @@ namespace WixToolset.Core.Burn.Bundles
65
public void Execute()
66
{
67
var harvestedMsiPackage = this.Section.Symbols.OfType<WixBundleHarvestedMsiPackageSymbol>()
68
- .Where(h => h.Id == this.PackagePayload.Id)
68
+ .Where(h => h.Id.Id == this.PackagePayload.Id.Id)
69
.SingleOrDefault();
70
71
if (harvestedMsiPackage == null)
src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs
+1
-1
@@ -53,7 +53,7 @@ namespace WixToolset.Core.Burn.Bundles
53
public void Execute()
54
{
55
var harvestedMspPackage = this.Section.Symbols.OfType<WixBundleHarvestedMspPackageSymbol>()
56
- .Where(h => h.Id == this.PackagePayload.Id)
56
+ .Where(h => h.Id.Id == this.PackagePayload.Id.Id)
57
.SingleOrDefault();
58
59
if (harvestedMspPackage == null)
src/wix/WixToolset.Core/CompilerCore.cs
+3
-2
@@ -849,9 +849,10 @@ namespace WixToolset.Core
849
/// Process all children of the element looking for extensions and erroring on the unexpected.
850
/// </summary>
851
/// <param name="element">Element to parse children.</param>
852
- public void ParseForExtensionElements(XElement element)
852
+ /// <param name="context">Extra information about the context in which this element is being parsed.</param>
853
+ public void ParseForExtensionElements(XElement element, IDictionary<string, string> context = null)
854
{
854
- this.parseHelper.ParseForExtensionElements(this.extensions.Values, this.intermediate, this.ActiveSection, element);
855
+ this.parseHelper.ParseForExtensionElements(this.extensions.Values, this.intermediate, this.ActiveSection, element, context);
856
}
857
858
/// <summary>
src/wix/WixToolset.Core/Compiler_Bundle.cs
+282
-2
@@ -2552,7 +2552,7 @@ namespace WixToolset.Core
2552
var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node)
2553
{
2554
Id = defaultId,
2555
- IsRemoteAllowed = packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu,
2555
+ IsRemoteAllowed = packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu,
2556
};
2557
2558
// This list lets us evaluate extension attributes *after* all core attributes
@@ -2659,11 +2659,291 @@ namespace WixToolset.Core
2659
this.Core.ParseExtensionAttribute(node, extensionAttribute, context);
2660
}
2661
2662
- this.Core.ParseForExtensionElements(node);
2662
+ foreach (var child in node.Elements())
2663
+ {
2664
+ if (CompilerCore.WixNamespace == child.Name.Namespace)
2665
+ {
2666
+ bool allowed;
2667
+ switch (child.Name.LocalName)
2668
+ {
2669
+ case "RemoteBundle":
2670
+ allowed = packageType == WixBundlePackageType.Bundle;
2671
+
2672
+ if (allowed)
2673
+ {
2674
+ this.ParseRemoteBundleElement(child, compilerPayload.Id.Id);
2675
+ }
2676
+
2677
+ break;
2678
+ default:
2679
+ allowed = false;
2680
+ break;
2681
+ }
2682
+
2683
+ if (!allowed)
2684
+ {
2685
+ this.Core.UnexpectedElement(node, child);
2686
+ }
2687
+ }
2688
+ else
2689
+ {
2690
+ this.Core.ParseExtensionElement(node, child, context);
2691
+ }
2692
+ }
2693
2694
return compilerPayload;
2695
}
2696
2697
+ private void ParseRemoteBundleElement(XElement node, string packagePayloadId)
2698
+ {
2699
+ var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2700
+ string bundleId = null;
2701
+ string displayName = null;
2702
+ string engineVersion = null;
2703
+ long? installSize = null;
2704
+ string manifestNamespace = null;
2705
+ var perMachine = YesNoType.NotSet;
2706
+ var protocolVersion = -1;
2707
+ string providerKey = null;
2708
+ string upgradeCode = null;
2709
+ string version = null;
2710
+ var win64 = YesNoType.NotSet;
2711
+
2712
+ foreach (var attrib in node.Attributes())
2713
+ {
2714
+ if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2715
+ {
2716
+ switch (attrib.Name.LocalName)
2717
+ {
2718
+ case "BundleId":
2719
+ bundleId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib);
2720
+ break;
2721
+ case "DisplayName":
2722
+ displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2723
+ break;
2724
+ case "EngineVersion":
2725
+ engineVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
2726
+ break;
2727
+ case "InstallSize":
2728
+ installSize = this.Core.GetAttributeLongValue(sourceLineNumbers, attrib, 0, Int64.MaxValue);
2729
+ break;
2730
+ case "ManifestNamespace":
2731
+ manifestNamespace = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2732
+ break;
2733
+ case "PerMachine":
2734
+ perMachine = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2735
+ break;
2736
+ case "ProtocolVersion":
2737
+ protocolVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
2738
+ break;
2739
+ case "ProviderKey":
2740
+ providerKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2741
+ break;
2742
+ case "UpgradeCode":
2743
+ upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib);
2744
+ break;
2745
+ case "Version":
2746
+ version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
2747
+ break;
2748
+ case "Win64":
2749
+ win64 = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2750
+ break;
2751
+ default:
2752
+ this.Core.UnexpectedAttribute(node, attrib);
2753
+ break;
2754
+ }
2755
+ }
2756
+ else
2757
+ {
2758
+ this.Core.ParseExtensionAttribute(node, attrib);
2759
+ }
2760
+ }
2761
+
2762
+ if (String.IsNullOrEmpty(bundleId))
2763
+ {
2764
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "BundleId"));
2765
+ }
2766
+
2767
+ if (String.IsNullOrEmpty(manifestNamespace))
2768
+ {
2769
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ManifestNamespace"));
2770
+ }
2771
+
2772
+ if (perMachine == YesNoType.NotSet)
2773
+ {
2774
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PerMachine"));
2775
+ }
2776
+
2777
+ if (protocolVersion == -1)
2778
+ {
2779
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProtocolVersion"));
2780
+ }
2781
+
2782
+ if (String.IsNullOrEmpty(providerKey))
2783
+ {
2784
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProviderKey"));
2785
+ }
2786
+
2787
+ if (String.IsNullOrEmpty(upgradeCode))
2788
+ {
2789
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UpgradeCode"));
2790
+ }
2791
+
2792
+ if (String.IsNullOrEmpty(version))
2793
+ {
2794
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
2795
+ }
2796
+
2797
+ if (win64 == YesNoType.NotSet)
2798
+ {
2799
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Win64"));
2800
+ }
2801
+
2802
+ if (!this.Messaging.EncounteredError)
2803
+ {
2804
+ WixBundleHarvestedBundlePackageAttributes bundleAttributes = 0;
2805
+ bundleAttributes |= (YesNoType.Yes == perMachine) ? WixBundleHarvestedBundlePackageAttributes.PerMachine : 0;
2806
+ bundleAttributes |= (YesNoType.Yes == win64) ? WixBundleHarvestedBundlePackageAttributes.Win64 : 0;
2807
+
2808
+ var symbol = this.Core.AddSymbol(new WixBundleHarvestedBundlePackageSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, packagePayloadId))
2809
+ {
2810
+ Attributes = bundleAttributes,
2811
+ BundleId = bundleId,
2812
+ DisplayName = displayName,
2813
+ EngineVersion = engineVersion,
2814
+ ManifestNamespace = manifestNamespace,
2815
+ ProtocolVersion = protocolVersion,
2816
+ Version = version,
2817
+ });
2818
+
2819
+ if (installSize.HasValue)
2820
+ {
2821
+ symbol.InstallSize = installSize.Value;
2822
+ }
2823
+
2824
+ this.Core.AddSymbol(new WixBundlePackageRelatedBundleSymbol(sourceLineNumbers)
2825
+ {
2826
+ PackagePayloadRef = packagePayloadId,
2827
+ BundleId = upgradeCode,
2828
+ Action = RelatedBundleActionType.Upgrade,
2829
+ });
2830
+
2831
+ var depId = new Identifier(AccessModifier.Section, this.Core.CreateIdentifier("dep", packagePayloadId, providerKey));
2832
+ this.Core.AddSymbol(new WixBundleHarvestedDependencyProviderSymbol(sourceLineNumbers, depId)
2833
+ {
2834
+ PackagePayloadRef = packagePayloadId,
2835
+ ProviderKey = providerKey,
2836
+ Version = version,
2837
+ });
2838
+ }
2839
+
2840
+ var context = new Dictionary<string, string>
2841
+ {
2842
+ ["Id"] = packagePayloadId,
2843
+ };
2844
+
2845
+ foreach (var child in node.Elements())
2846
+ {
2847
+ if (CompilerCore.WixNamespace == child.Name.Namespace)
2848
+ {
2849
+ switch (child.Name.LocalName)
2850
+ {
2851
+ case "RemoteRelatedBundle":
2852
+ this.ParseRemoteRelatedBundleElement(child, packagePayloadId);
2853
+ break;
2854
+ default:
2855
+ this.Core.UnexpectedElement(node, child);
2856
+ break;
2857
+ }
2858
+ }
2859
+ else
2860
+ {
2861
+ this.Core.ParseExtensionElement(node, child, context);
2862
+ }
2863
+ }
2864
+ }
2865
+
2866
+ private void ParseRemoteRelatedBundleElement(XElement node, string payloadId)
2867
+ {
2868
+ var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2869
+ string id = null;
2870
+ RelatedBundleActionType? actionType = null;
2871
+
2872
+ foreach (var attrib in node.Attributes())
2873
+ {
2874
+ if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2875
+ {
2876
+ switch (attrib.Name.LocalName)
2877
+ {
2878
+ case "Id":
2879
+ id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
2880
+ break;
2881
+ case "Action":
2882
+ var action = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2883
+ switch (action)
2884
+ {
2885
+ case "Detect":
2886
+ case "detect":
2887
+ actionType = RelatedBundleActionType.Detect;
2888
+ break;
2889
+ case "Upgrade":
2890
+ case "upgrade":
2891
+ actionType = RelatedBundleActionType.Upgrade;
2892
+ break;
2893
+ case "Addon":
2894
+ case "addon":
2895
+ actionType = RelatedBundleActionType.Addon;
2896
+ break;
2897
+ case "Patch":
2898
+ case "patch":
2899
+ actionType = RelatedBundleActionType.Patch;
2900
+ break;
2901
+ case "":
2902
+ break;
2903
+ default:
2904
+ this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", action, "Detect", "Upgrade", "Addon", "Patch"));
2905
+ break;
2906
+ }
2907
+ break;
2908
+ default:
2909
+ this.Core.UnexpectedAttribute(node, attrib);
2910
+ break;
2911
+ }
2912
+ }
2913
+ else
2914
+ {
2915
+ this.Core.ParseExtensionAttribute(node, attrib);
2916
+ }
2917
+ }
2918
+
2919
+ if (null == id)
2920
+ {
2921
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
2922
+ }
2923
+
2924
+ if (!actionType.HasValue)
2925
+ {
2926
+ this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action"));
2927
+ }
2928
+
2929
+ var context = new Dictionary<string, string>
2930
+ {
2931
+ ["PayloadId"] = payloadId,
2932
+ };
2933
+
2934
+ this.Core.ParseForExtensionElements(node, context);
2935
+
2936
+ if (!this.Core.EncounteredError)
2937
+ {
2938
+ this.Core.AddSymbol(new WixBundlePackageRelatedBundleSymbol(sourceLineNumbers)
2939
+ {
2940
+ PackagePayloadRef = payloadId,
2941
+ BundleId = id,
2942
+ Action = actionType.Value,
2943
+ });
2944
+ }
2945
+ }
2946
+
2947
/// <summary>
2948
/// Parse CommandLine element.
2949
/// </summary>
src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
+2
-2
@@ -714,7 +714,7 @@ namespace WixToolset.Core.ExtensibilityServices
714
return keyPath;
715
}
716
717
- public void ParseForExtensionElements(IEnumerable<ICompilerExtension> extensions, Intermediate intermediate, IntermediateSection section, XElement element)
717
+ public void ParseForExtensionElements(IEnumerable<ICompilerExtension> extensions, Intermediate intermediate, IntermediateSection section, XElement element, IDictionary<string, string> context = null)
718
{
719
var checkInnerText = false;
720
@@ -728,7 +728,7 @@ namespace WixToolset.Core.ExtensibilityServices
728
}
729
else
730
{
731
- this.ParseExtensionElement(extensions, intermediate, section, element, childElement);
731
+ this.ParseExtensionElement(extensions, intermediate, section, element, childElement, context);
732
}
733
}
734
else
src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
+87
@@ -204,6 +204,93 @@ namespace WixToolsetTest.CoreIntegration
204
}
205
}
206
207
+ [Fact]
208
+ public void CanBuildBundleWithRemoteBundlePackage()
209
+ {
210
+ var folder = TestData.Get(@"TestData");
211
+
212
+ using (var fs = new DisposableFileSystem())
213
+ {
214
+ var baseFolder = fs.GetFolder();
215
+ var parentIntermediateFolder = Path.Combine(baseFolder, "obj", "Parent");
216
+ var binFolder = Path.Combine(baseFolder, "bin");
217
+ var parentBundlePath = Path.Combine(binFolder, "parent.exe");
218
+ var parentPdbPath = Path.Combine(binFolder, "parent.wixpdb");
219
+ var parentBaFolderPath = Path.Combine(baseFolder, "parentba");
220
+ var extractFolderPath = Path.Combine(baseFolder, "extract");
221
+
222
+ var result = WixRunner.Execute(new[]
223
+ {
224
+ "build",
225
+ Path.Combine(folder, "BundlePackage", "RemoteBundlePackage.wxs"),
226
+ "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
227
+ "-bindpath", binFolder,
228
+ "-intermediateFolder", parentIntermediateFolder,
229
+ "-o", parentBundlePath,
230
+ });
231
+
232
+ result.AssertSuccess();
233
+
234
+ Assert.True(File.Exists(parentBundlePath));
235
+
236
+ var chainBundleId = "{216BDA7F-74BD-45E8-957B-500552F05629}";
237
+ string parentBundleId;
238
+ using (var wixOutput = WixOutput.Read(parentPdbPath))
239
+ {
240
+
241
+ var intermediate = Intermediate.Load(wixOutput);
242
+ var section = intermediate.Sections.Single();
243
+
244
+ var bundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
245
+ parentBundleId = bundleSymbol.BundleId;
246
+ }
247
+
248
+ var extractResult = BundleExtractor.ExtractBAContainer(null, parentBundlePath, parentBaFolderPath, extractFolderPath);
249
+ extractResult.AssertSuccess();
250
+
251
+ var ignoreAttributesByElementName = new Dictionary<string, List<string>>
252
+ {
253
+ { "BundlePackage", new List<string> { "Size" } },
254
+ };
255
+ var bundlePackages = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:BundlePackage")
256
+ .Cast<XmlElement>()
257
+ .Select(e => e.GetTestXml(ignoreAttributesByElementName))
258
+ .ToArray();
259
+ WixAssert.CompareLineByLine(new string[]
260
+ {
261
+ $"<BundlePackage Id='chain.exe' Cache='keep' CacheId='{chainBundleId}v1.0.0.0' InstallSize='34' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' BundleId='{chainBundleId}' Version='1.0.0.0' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no'>" +
262
+ "<Provides Key='MyProviderKey,v1.0' Version='1.0.0.0' DisplayName='BurnBundle' Imported='yes' />" +
263
+ "<RelatedBundle Id='{B94478B1-E1F3-4700-9CE8-6AA090854AEC}' Action='Upgrade' />" +
264
+ "<PayloadRef Id='chain.exe' />" +
265
+ "</BundlePackage>",
266
+ }, bundlePackages);
267
+
268
+ var registrations = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration")
269
+ .Cast<XmlElement>()
270
+ .Select(e => e.GetTestXml())
271
+ .ToArray();
272
+ WixAssert.CompareLineByLine(new string[]
273
+ {
274
+ $"<Registration Id='{parentBundleId}' ExecutableName='parent.exe' PerMachine='yes' Tag='' Version='1.0.1.0' ProviderKey='{parentBundleId}'>" +
275
+ "<Arp DisplayName='RemoteBundlePackageBundle' DisplayVersion='1.0.1.0' Publisher='Example Corporation' />" +
276
+ "</Registration>"
277
+ }, registrations);
278
+
279
+ ignoreAttributesByElementName = new Dictionary<string, List<string>>
280
+ {
281
+ { "WixPackageProperties", new List<string> { "DownloadSize", "PackageSize" } },
282
+ };
283
+ var packageElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixPackageProperties")
284
+ .Cast<XmlElement>()
285
+ .Select(e => e.GetTestXml(ignoreAttributesByElementName))
286
+ .ToArray();
287
+ WixAssert.CompareLineByLine(new string[]
288
+ {
289
+ "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundleDescription' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='yes' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='no' Version='1.0.0.0' Cache='keep' />",
290
+ }, packageElements);
291
+ }
292
+ }
293
+
294
[Fact]
295
public void CanBuildBundleWithV3BundlePackage()
296
{
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/RemoteBundlePackage.wxs
new
+28
@@ -0,0 +1,28 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Bundle Name="RemoteBundlePackageBundle" Version="1.0.1.0" Manufacturer="Example Corporation" UpgradeCode="{9BE68A41-FD0E-4E25-B607-D636E42AFEF6}">
3
+ <BootstrapperApplication>
4
+ <BootstrapperApplicationDll SourceFile="fakeba.dll" />
5
+ </BootstrapperApplication>
6
+ <Chain>
7
+ <BundlePackage Permanent="yes">
8
+ <BundlePackagePayload Name="chain.exe"
9
+ DownloadUrl="http://example.com/chain.exe"
10
+ Description="BurnBundleDescription"
11
+ Size="123456789"
12
+ Hash="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA">
13
+ <RemoteBundle BundleId="{216BDA7F-74BD-45E8-957B-500552F05629}"
14
+ DisplayName="BurnBundle"
15
+ InstallSize="34"
16
+ ManifestNamespace="http://wixtoolset.org/schemas/v4/2008/Burn"
17
+ PerMachine="yes"
18
+ ProtocolVersion="1"
19
+ ProviderKey="MyProviderKey,v1.0"
20
+ UpgradeCode="{B94478B1-E1F3-4700-9CE8-6AA090854AEC}"
21
+ Version="1.0.0.0"
22
+ Win64="no"
23
+ />
24
+ </BundlePackagePayload>
25
+ </BundlePackage>
26
+ </Chain>
27
+ </Bundle>
28
+</Wix>