aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/wix/WixToolset.Data/ErrorMessages.cs29
-rw-r--r--src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs51
-rw-r--r--src/api/wix/WixToolset.Data/WarningMessages.cs20
-rw-r--r--src/burn/engine/approvedexe.cpp8
-rw-r--r--src/burn/engine/approvedexe.h2
-rw-r--r--src/burn/engine/bundlepackageengine.cpp6
-rw-r--r--src/burn/engine/elevation.cpp2
-rw-r--r--src/burn/engine/engine.mc7
-rw-r--r--src/burn/engine/exeengine.cpp295
-rw-r--r--src/burn/engine/package.h13
-rw-r--r--src/burn/engine/plan.cpp3
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj1
-rw-r--r--src/burn/test/BurnUnitTest/PlanTest.cpp261
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml2
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/ExePackage_PerUserArpEntry_manifest.xml1
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml2
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml2
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_modified_manifest.xml2
-rw-r--r--src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs2
-rw-r--r--src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wixproj17
-rw-r--r--src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wxs18
-rw-r--r--src/test/burn/TestData/ExePackageTests/PackageFail/PackageFail.wixproj12
-rw-r--r--src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wixproj19
-rw-r--r--src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wxs18
-rw-r--r--src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wixproj18
-rw-r--r--src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wxs19
-rw-r--r--src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wixproj17
-rw-r--r--src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wxs18
-rw-r--r--src/test/burn/WixTestTools/ArpEntryInstaller.cs43
-rw-r--r--src/test/burn/WixTestTools/ArpEntryVerifier.cs24
-rw-r--r--src/test/burn/WixTestTools/BundleRegistration.cs121
-rw-r--r--src/test/burn/WixTestTools/BundleVerifier.cs23
-rw-r--r--src/test/burn/WixTestTools/GenericArpRegistration.cs143
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs17
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs4
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs99
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/Utilities/IWebServer.cs (renamed from src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs)0
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs (renamed from src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs)0
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestExeTool.cs17
-rw-r--r--src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs30
-rw-r--r--src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs12
-rw-r--r--src/wix/WixToolset.Core/Compiler_Bundle.cs308
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs4
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs389
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs2
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntry.wxs12
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithDetectCondition.wxs12
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithUninstallArguments.wxs12
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryId.wxs11
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryVersion.wxs11
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyDetectCondition.wxs10
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyUninstallArguments.wxs10
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs (renamed from src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/MissingDetectCondition.wxs)0
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithEmptyDetectCondition.wxs11
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs10
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectCondition.wxs12
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs11
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/UninstallArgumentsWithoutDetectCondition.wxs (renamed from src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RequireDetectCondition.wxs)1
58 files changed, 1957 insertions, 267 deletions
diff --git a/src/api/wix/WixToolset.Data/ErrorMessages.cs b/src/api/wix/WixToolset.Data/ErrorMessages.cs
index d3d2932d..31888d1f 100644
--- a/src/api/wix/WixToolset.Data/ErrorMessages.cs
+++ b/src/api/wix/WixToolset.Data/ErrorMessages.cs
@@ -388,7 +388,7 @@ namespace WixToolset.Data
388 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required.", elementName, attributeName); 388 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required.", elementName, attributeName);
389 } 389 }
390 390
391 public static Message ExpectedAttribute(SourceLineNumber sourceLineNumbers, string elementName, string attribute1Name, string attribute2Name, Boolean eitherOr) 391 public static Message ExpectedAttribute(SourceLineNumber sourceLineNumbers, string elementName, string attribute1Name, string attribute2Name, bool eitherOr)
392 { 392 {
393 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0} element must have a value for exactly one of the {1} or {2} attributes.", elementName, attribute1Name, attribute2Name, eitherOr); 393 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0} element must have a value for exactly one of the {1} or {2} attributes.", elementName, attribute1Name, attribute2Name, eitherOr);
394 } 394 }
@@ -403,7 +403,7 @@ namespace WixToolset.Data
403 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required when attribute {2} has a value of '{3}'.", elementName, attributeName, otherAttributeName, otherAttributeValue); 403 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required when attribute {2} has a value of '{3}'.", elementName, attributeName, otherAttributeName, otherAttributeValue);
404 } 404 }
405 405
406 public static Message ExpectedAttribute(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName, string otherAttributeValue, Boolean otherAttributeValueUnless) 406 public static Message ExpectedAttribute(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName, string otherAttributeValue, bool otherAttributeValueUnless)
407 { 407 {
408 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required unless the attribute {2} has a value of '{3}'.", elementName, attributeName, otherAttributeName, otherAttributeValue, otherAttributeValueUnless); 408 return Message(sourceLineNumbers, Ids.ExpectedAttribute, "The {0}/@{1} attribute was not found; it is required unless the attribute {2} has a value of '{3}'.", elementName, attributeName, otherAttributeName, otherAttributeValue, otherAttributeValueUnless);
409 } 409 }
@@ -428,6 +428,21 @@ namespace WixToolset.Data
428 return Message(sourceLineNumbers, Ids.ExpectedAttributeOrElement, "Element '{0}' missing attribute '{1}' or child element '{2}'. Exactly one of those is required.", parentElement, attribute, childElement); 428 return Message(sourceLineNumbers, Ids.ExpectedAttributeOrElement, "Element '{0}' missing attribute '{1}' or child element '{2}'. Exactly one of those is required.", parentElement, attribute, childElement);
429 } 429 }
430 430
431 public static Message ExpectedAttributeOrElementWithOtherAttribute(SourceLineNumber sourceLineNumbers, string parentElement, string attribute, string childElement, string otherAttribute)
432 {
433 return Message(sourceLineNumbers, Ids.ExpectedAttributeOrElementWithOtherAttribute, "Element '{0}' missing attribute '{1}' or child element '{2}'. Exactly one of those is required when attribute '{3}' is specified.", parentElement, attribute, childElement, otherAttribute);
434 }
435
436 public static Message ExpectedAttributeOrElementWithOtherAttribute(SourceLineNumber sourceLineNumbers, string parentElement, string attribute, string childElement, string otherAttribute, string otherAttributeValue)
437 {
438 return Message(sourceLineNumbers, Ids.ExpectedAttributeOrElementWithOtherAttribute, "Element '{0}' missing attribute '{1}' or child element '{2}'. Exactly one of those is required when attribute '{3}' is specified with value '{4}'.", parentElement, attribute, childElement, otherAttribute, otherAttributeValue);
439 }
440
441 public static Message ExpectedAttributeOrElementWithoutOtherAttribute(SourceLineNumber sourceLineNumbers, string parentElement, string attribute, string childElement, string otherAttribute)
442 {
443 return Message(sourceLineNumbers, Ids.ExpectedAttributeOrElementWithoutOtherAttribute, "Element '{0}' missing attribute '{1}' or child element '{2}'. Exactly one of those is required when attribute '{3}' is not specified.", parentElement, attribute, childElement, otherAttribute);
444 }
445
431 public static Message ExpectedAttributes(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2) 446 public static Message ExpectedAttributes(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2)
432 { 447 {
433 return Message(sourceLineNumbers, Ids.ExpectedAttributes, "The {0} element's {1} or {2} attribute was not found; one of these is required.", elementName, attributeName1, attributeName2); 448 return Message(sourceLineNumbers, Ids.ExpectedAttributes, "The {0} element's {1} or {2} attribute was not found; one of these is required.", elementName, attributeName1, attributeName2);
@@ -839,7 +854,7 @@ namespace WixToolset.Data
839 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutOtherAttributes, "The {0}/@{1} attribute can only be specified with one of the following attributes: {2} or {3} present.", elementName, attributeName, otherAttributeName1, otherAttributeName2); 854 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutOtherAttributes, "The {0}/@{1} attribute can only be specified with one of the following attributes: {2} or {3} present.", elementName, attributeName, otherAttributeName1, otherAttributeName2);
840 } 855 }
841 856
842 public static Message IllegalAttributeWithoutOtherAttributes(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName1, string otherAttributeName2, string otherAttributeValue, Boolean uniquifier) 857 public static Message IllegalAttributeWithoutOtherAttributes(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName1, string otherAttributeName2, string otherAttributeValue, bool uniquifier)
843 { 858 {
844 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutOtherAttributes, "The {0}/@{1} attribute can only be specified with one of the following attributes: {2} or {3} present with value '{4}'.", elementName, attributeName, otherAttributeName1, otherAttributeName2, otherAttributeValue, uniquifier); 859 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutOtherAttributes, "The {0}/@{1} attribute can only be specified with one of the following attributes: {2} or {3} present with value '{4}'.", elementName, attributeName, otherAttributeName1, otherAttributeName2, otherAttributeValue, uniquifier);
845 } 860 }
@@ -899,7 +914,7 @@ namespace WixToolset.Data
899 return Message(sourceLineNumbers, Ids.IllegalComponentWithAutoGeneratedGuid, "The Component/@Guid attribute's value '*' is not valid for this component because it does not meet the criteria for having an automatically generated guid. Components using a Directory as a KeyPath or containing ODBCDataSource child elements cannot use an automatically generated guid. Make sure your component doesn't have a Directory as the KeyPath and move any ODBCDataSource child elements to components with explicit component guids."); 914 return Message(sourceLineNumbers, Ids.IllegalComponentWithAutoGeneratedGuid, "The Component/@Guid attribute's value '*' is not valid for this component because it does not meet the criteria for having an automatically generated guid. Components using a Directory as a KeyPath or containing ODBCDataSource child elements cannot use an automatically generated guid. Make sure your component doesn't have a Directory as the KeyPath and move any ODBCDataSource child elements to components with explicit component guids.");
900 } 915 }
901 916
902 public static Message IllegalComponentWithAutoGeneratedGuid(SourceLineNumber sourceLineNumbers, Boolean registryKeyPath) 917 public static Message IllegalComponentWithAutoGeneratedGuid(SourceLineNumber sourceLineNumbers, bool registryKeyPath)
903 { 918 {
904 return Message(sourceLineNumbers, Ids.IllegalComponentWithAutoGeneratedGuid, "The Component/@Guid attribute's value '*' is not valid for this component because it does not meet the criteria for having an automatically generated guid. Components with registry keypaths and files cannot use an automatically generated guid. Create multiple components, each with one file and/or one registry value keypath, to use automatically generated guids.", registryKeyPath); 919 return Message(sourceLineNumbers, Ids.IllegalComponentWithAutoGeneratedGuid, "The Component/@Guid attribute's value '*' is not valid for this component because it does not meet the criteria for having an automatically generated guid. Components with registry keypaths and files cannot use an automatically generated guid. Create multiple components, each with one file and/or one registry value keypath, to use automatically generated guids.", registryKeyPath);
905 } 920 }
@@ -1414,12 +1429,12 @@ namespace WixToolset.Data
1414 return Message(sourceLineNumbers, Ids.MergeFeatureRequired, "The {0} table contains a row with primary key(s) '{1}' which requires a feature to properly merge from the merge module '{2}'. Nest a MergeRef element with an Id attribute set to the value '{3}' under a Feature element to fix this error.", tableName, primaryKeys, mergeModuleFile, mergeId); 1429 return Message(sourceLineNumbers, Ids.MergeFeatureRequired, "The {0} table contains a row with primary key(s) '{1}' which requires a feature to properly merge from the merge module '{2}'. Nest a MergeRef element with an Id attribute set to the value '{3}' under a Feature element to fix this error.", tableName, primaryKeys, mergeModuleFile, mergeId);
1415 } 1430 }
1416 1431
1417 public static Message MergeLanguageFailed(SourceLineNumber sourceLineNumbers, Int16 language, string mergeModuleFile) 1432 public static Message MergeLanguageFailed(SourceLineNumber sourceLineNumbers, short language, string mergeModuleFile)
1418 { 1433 {
1419 return Message(sourceLineNumbers, Ids.MergeLanguageFailed, "The language '{0}' is supported but uses an invalid language transform in the merge module '{1}'.", language, mergeModuleFile); 1434 return Message(sourceLineNumbers, Ids.MergeLanguageFailed, "The language '{0}' is supported but uses an invalid language transform in the merge module '{1}'.", language, mergeModuleFile);
1420 } 1435 }
1421 1436
1422 public static Message MergeLanguageUnsupported(SourceLineNumber sourceLineNumbers, Int16 language, string mergeModuleFile) 1437 public static Message MergeLanguageUnsupported(SourceLineNumber sourceLineNumbers, short language, string mergeModuleFile)
1423 { 1438 {
1424 return Message(sourceLineNumbers, Ids.MergeLanguageUnsupported, "Could not locate language '{0}' (or a transform for this language) in the merge module '{1}'. This is likely due to an incorrectly authored Merge/@Language attribute.", language, mergeModuleFile); 1439 return Message(sourceLineNumbers, Ids.MergeLanguageUnsupported, "Could not locate language '{0}' (or a transform for this language) in the merge module '{1}'. This is likely due to an incorrectly authored Merge/@Language attribute.", language, mergeModuleFile);
1425 } 1440 }
@@ -2710,6 +2725,8 @@ namespace WixToolset.Data
2710 MsiTransactionX86BeforeX64Package2 = 410, 2725 MsiTransactionX86BeforeX64Package2 = 410,
2711 MsiTransactionInvalidPackage = 411, 2726 MsiTransactionInvalidPackage = 411,
2712 MsiTransactionInvalidPackage2 = 412, 2727 MsiTransactionInvalidPackage2 = 412,
2728 ExpectedAttributeOrElementWithOtherAttribute = 413,
2729 ExpectedAttributeOrElementWithoutOtherAttribute = 414,
2713 } 2730 }
2714 } 2731 }
2715} 2732}
diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs
index 6cf200c2..74146716 100644
--- a/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs
+++ b/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs
@@ -16,6 +16,9 @@ namespace WixToolset.Data
16 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.RepairCommand), IntermediateFieldType.String), 16 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.RepairCommand), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.UninstallCommand), IntermediateFieldType.String), 17 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.UninstallCommand), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.ExeProtocol), IntermediateFieldType.String), 18 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.ExeProtocol), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.DetectionType), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.ArpId), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(WixBundleExePackageSymbolFields.ArpDisplayVersion), IntermediateFieldType.String),
19 }, 22 },
20 typeof(WixBundleExePackageSymbol)); 23 typeof(WixBundleExePackageSymbol));
21 } 24 }
@@ -33,6 +36,19 @@ namespace WixToolset.Data.Symbols
33 RepairCommand, 36 RepairCommand,
34 UninstallCommand, 37 UninstallCommand,
35 ExeProtocol, 38 ExeProtocol,
39 DetectionType,
40 ArpId,
41 ArpDisplayVersion,
42 }
43
44 /// <summary>
45 /// How Burn will detect the ExePackage.
46 /// </summary>
47 public enum WixBundleExePackageDetectionType
48 {
49 None,
50 Condition,
51 Arp,
36 } 52 }
37 53
38 [Flags] 54 [Flags]
@@ -40,6 +56,7 @@ namespace WixToolset.Data.Symbols
40 { 56 {
41 None = 0, 57 None = 0,
42 Bundle = 1, 58 Bundle = 1,
59 ArpWin64 = 2,
43 } 60 }
44 61
45 public class WixBundleExePackageSymbol : IntermediateSymbol 62 public class WixBundleExePackageSymbol : IntermediateSymbol
@@ -90,6 +107,24 @@ namespace WixToolset.Data.Symbols
90 set => this.Set((int)WixBundleExePackageSymbolFields.ExeProtocol, value); 107 set => this.Set((int)WixBundleExePackageSymbolFields.ExeProtocol, value);
91 } 108 }
92 109
110 public WixBundleExePackageDetectionType DetectionType
111 {
112 get => (WixBundleExePackageDetectionType)this.Fields[(int)WixBundleExePackageSymbolFields.DetectionType].AsNumber();
113 set => this.Set((int)WixBundleExePackageSymbolFields.DetectionType, (int)value);
114 }
115
116 public string ArpId
117 {
118 get => (string)this.Fields[(int)WixBundleExePackageSymbolFields.ArpId];
119 set => this.Set((int)WixBundleExePackageSymbolFields.ArpId, value);
120 }
121
122 public string ArpDisplayVersion
123 {
124 get => (string)this.Fields[(int)WixBundleExePackageSymbolFields.ArpDisplayVersion];
125 set => this.Set((int)WixBundleExePackageSymbolFields.ArpDisplayVersion, value);
126 }
127
93 public bool IsBundle 128 public bool IsBundle
94 { 129 {
95 get { return this.Attributes.HasFlag(WixBundleExePackageAttributes.Bundle); } 130 get { return this.Attributes.HasFlag(WixBundleExePackageAttributes.Bundle); }
@@ -106,6 +141,22 @@ namespace WixToolset.Data.Symbols
106 } 141 }
107 } 142 }
108 143
144 public bool ArpWin64
145 {
146 get { return this.Attributes.HasFlag(WixBundleExePackageAttributes.ArpWin64); }
147 set
148 {
149 if (value)
150 {
151 this.Attributes |= WixBundleExePackageAttributes.ArpWin64;
152 }
153 else
154 {
155 this.Attributes &= ~WixBundleExePackageAttributes.ArpWin64;
156 }
157 }
158 }
159
109 public bool Repairable => this.RepairCommand != null; 160 public bool Repairable => this.RepairCommand != null;
110 161
111 public bool Uninstallable => this.UninstallCommand != null; 162 public bool Uninstallable => this.UninstallCommand != null;
diff --git a/src/api/wix/WixToolset.Data/WarningMessages.cs b/src/api/wix/WixToolset.Data/WarningMessages.cs
index 5a5d1e79..5d3f06f8 100644
--- a/src/api/wix/WixToolset.Data/WarningMessages.cs
+++ b/src/api/wix/WixToolset.Data/WarningMessages.cs
@@ -237,6 +237,11 @@ namespace WixToolset.Data
237 return Message(sourceLineNumbers, Ids.DetectConditionRecommended, "The {0}/@DetectCondition attribute is recommended so the package is only installed when absent.", elementName); 237 return Message(sourceLineNumbers, Ids.DetectConditionRecommended, "The {0}/@DetectCondition attribute is recommended so the package is only installed when absent.", elementName);
238 } 238 }
239 239
240 public static Message ExePackageDetectInformationRecommended(SourceLineNumber sourceLineNumbers)
241 {
242 return Message(sourceLineNumbers, Ids.ExePackageDetectInformationRecommended, "The ExePackage/@DetectCondition attribute or child element ArpEntry is recommended so the package is only installed when absent.");
243 }
244
240 public static Message DownloadUrlNotSupportedForAttachedContainers(SourceLineNumber sourceLineNumbers, string containerId) 245 public static Message DownloadUrlNotSupportedForAttachedContainers(SourceLineNumber sourceLineNumbers, string containerId)
241 { 246 {
242 return Message(sourceLineNumbers, Ids.DownloadUrlNotSupportedForAttachedContainers, "The Container '{0}' is attached but included a @DownloadUrl attribute. Attached Containers cannot be downloaded so the download URL is being ignored.", containerId); 247 return Message(sourceLineNumbers, Ids.DownloadUrlNotSupportedForAttachedContainers, "The Container '{0}' is attached but included a @DownloadUrl attribute. Attached Containers cannot be downloaded so the download URL is being ignored.", containerId);
@@ -267,7 +272,7 @@ namespace WixToolset.Data
267 return Message(sourceLineNumbers, Ids.EmptyCabinet, "The cabinet '{0}' does not contain any files. If this installation contains no files, this warning can likely be safely ignored. Otherwise, please add files to the cabinet or remove it.", cabinetName); 272 return Message(sourceLineNumbers, Ids.EmptyCabinet, "The cabinet '{0}' does not contain any files. If this installation contains no files, this warning can likely be safely ignored. Otherwise, please add files to the cabinet or remove it.", cabinetName);
268 } 273 }
269 274
270 public static Message EmptyCabinet(SourceLineNumber sourceLineNumbers, string cabinetName, Boolean isPatch) 275 public static Message EmptyCabinet(SourceLineNumber sourceLineNumbers, string cabinetName, bool isPatch)
271 { 276 {
272 return Message(sourceLineNumbers, Ids.EmptyCabinet, "The cabinet '{0}' does not contain any files. If this patch contains no files, this warning can likely be safely ignored. Otherwise, try passing -p to torch.exe when first building the transforms, or add a ComponentRef to your PatchFamily authoring to pull changed files into the cabinet.", cabinetName, isPatch); 277 return Message(sourceLineNumbers, Ids.EmptyCabinet, "The cabinet '{0}' does not contain any files. If this patch contains no files, this warning can likely be safely ignored. Otherwise, try passing -p to torch.exe when first building the transforms, or add a ComponentRef to your PatchFamily authoring to pull changed files into the cabinet.", cabinetName, isPatch);
273 } 278 }
@@ -322,7 +327,7 @@ namespace WixToolset.Data
322 return Message(sourceLineNumbers, Ids.IllegalActionInSequence, "The {0} table contains an action '{1}' which is not allowed in this table. If this is a standard action then it is not valid for this table, if it is a custom action or dialog then this table does not accept actions of that type. This action will be left out of the decompiled output.", sequenceTableName, actionName); 327 return Message(sourceLineNumbers, Ids.IllegalActionInSequence, "The {0} table contains an action '{1}' which is not allowed in this table. If this is a standard action then it is not valid for this table, if it is a custom action or dialog then this table does not accept actions of that type. This action will be left out of the decompiled output.", sequenceTableName, actionName);
323 } 328 }
324 329
325 public static Message IllegalColumnValue(SourceLineNumber sourceLineNumbers, string tableName, string columnName, Object value) 330 public static Message IllegalColumnValue(SourceLineNumber sourceLineNumbers, string tableName, string columnName, object value)
326 { 331 {
327 return Message(sourceLineNumbers, Ids.IllegalColumnValue, "The {0}.{1} column's value, '{2}', is not a recognized legal value. This information will be left out of the decompiled output.", tableName, columnName, value); 332 return Message(sourceLineNumbers, Ids.IllegalColumnValue, "The {0}.{1} column's value, '{2}', is not a recognized legal value. This information will be left out of the decompiled output.", tableName, columnName, value);
328 } 333 }
@@ -407,7 +412,7 @@ namespace WixToolset.Data
407 return Message(sourceLineNumbers, Ids.MsiTransactionLimitations, "MSI transactions have limitations that make it hard to use them successfully in a bundle. Test the bundle thoroughly, especially in upgrade scenarios and the scenario that required them in the first place."); 412 return Message(sourceLineNumbers, Ids.MsiTransactionLimitations, "MSI transactions have limitations that make it hard to use them successfully in a bundle. Test the bundle thoroughly, especially in upgrade scenarios and the scenario that required them in the first place.");
408 } 413 }
409 414
410 public static Message NestedInstall(SourceLineNumber sourceLineNumbers, string tableName, string columnName, Object value) 415 public static Message NestedInstall(SourceLineNumber sourceLineNumbers, string tableName, string columnName, object value)
411 { 416 {
412 return Message(sourceLineNumbers, Ids.NestedInstall, "The {0}.{1} column's value, '{2}', indicates a nested install. Nested installations are not supported by the WiX team. This action will be left out of the decompiled output.", tableName, columnName, value); 417 return Message(sourceLineNumbers, Ids.NestedInstall, "The {0}.{1} column's value, '{2}', indicates a nested install. Nested installations are not supported by the WiX team. This action will be left out of the decompiled output.", tableName, columnName, value);
413 } 418 }
@@ -628,7 +633,7 @@ namespace WixToolset.Data
628 return Message(sourceLineNumbers, Ids.UnknownPermission, "The {0} table contains a row with primary key '{1}' which has an unknown permission at bit {2}.", tableName, primaryKey, bitPosition); 633 return Message(sourceLineNumbers, Ids.UnknownPermission, "The {0} table contains a row with primary key '{1}' which has an unknown permission at bit {2}.", tableName, primaryKey, bitPosition);
629 } 634 }
630 635
631 public static Message UnrepresentableColumnValue(SourceLineNumber sourceLineNumbers, string tableName, string columnName, Object value) 636 public static Message UnrepresentableColumnValue(SourceLineNumber sourceLineNumbers, string tableName, string columnName, object value)
632 { 637 {
633 return Message(sourceLineNumbers, Ids.UnrepresentableColumnValue, "The {0}.{1} column's value, '{2}', cannot currently be represented in the WiX schema.", tableName, columnName, value); 638 return Message(sourceLineNumbers, Ids.UnrepresentableColumnValue, "The {0}.{1} column's value, '{2}', cannot currently be represented in the WiX schema.", tableName, columnName, value);
634 } 639 }
@@ -688,6 +693,11 @@ namespace WixToolset.Data
688 return Message(sourceLineNumbers, Ids.WindowsInstallerFileTooLarge, "The Windows Installer does not support {0} files larger than 2GB in size. Reduce the size or number of files embedded in '{1}' or the installation will likely fail with an unexpected error.", fileDescription, path); 693 return Message(sourceLineNumbers, Ids.WindowsInstallerFileTooLarge, "The Windows Installer does not support {0} files larger than 2GB in size. Reduce the size or number of files embedded in '{1}' or the installation will likely fail with an unexpected error.", fileDescription, path);
689 } 694 }
690 695
696 public static Message InvalidWixVersion(SourceLineNumber sourceLineNumbers, string version, string elementName, string attributeName)
697 {
698 return Message(sourceLineNumbers, Ids.InvalidWixVersion, "Invalid WixVersion '{0}' in {1}/@'{2}'. Comparisons may yield unexpected results.", version, elementName, attributeName);
699 }
700
691 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) 701 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
692 { 702 {
693 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args); 703 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args);
@@ -827,6 +837,8 @@ namespace WixToolset.Data
827 WindowsInstallerFileTooLarge = 1158, 837 WindowsInstallerFileTooLarge = 1158,
828 UnavailableBundleConditionVariable = 1159, 838 UnavailableBundleConditionVariable = 1159,
829 DiscardedRollbackBoundary2 = 1160, 839 DiscardedRollbackBoundary2 = 1160,
840 ExePackageDetectInformationRecommended = 1161,
841 InvalidWixVersion = 1162,
830 } 842 }
831 } 843 }
832} 844}
diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp
index b9efd624..2a96868e 100644
--- a/src/burn/engine/approvedexe.cpp
+++ b/src/burn/engine/approvedexe.cpp
@@ -213,7 +213,7 @@ LExit:
213extern "C" HRESULT ApprovedExesVerifySecureLocation( 213extern "C" HRESULT ApprovedExesVerifySecureLocation(
214 __in BURN_CACHE* pCache, 214 __in BURN_CACHE* pCache,
215 __in BURN_VARIABLES* pVariables, 215 __in BURN_VARIABLES* pVariables,
216 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe 216 __in LPCWSTR wzExecutablePath
217 ) 217 )
218{ 218{
219 HRESULT hr = S_OK; 219 HRESULT hr = S_OK;
@@ -232,7 +232,7 @@ extern "C" HRESULT ApprovedExesVerifySecureLocation(
232 hr = VariableGetString(pVariables, wzSecureFolderVariable, &scz); 232 hr = VariableGetString(pVariables, wzSecureFolderVariable, &scz);
233 if (SUCCEEDED(hr)) 233 if (SUCCEEDED(hr))
234 { 234 {
235 hr = PathDirectoryContainsPath(scz, pLaunchApprovedExe->sczExecutablePath); 235 hr = PathDirectoryContainsPath(scz, wzExecutablePath);
236 if (S_OK == hr) 236 if (S_OK == hr)
237 { 237 {
238 ExitFunction(); 238 ExitFunction();
@@ -252,14 +252,14 @@ extern "C" HRESULT ApprovedExesVerifySecureLocation(
252 // If the package cache is redirected, hr is S_FALSE. 252 // If the package cache is redirected, hr is S_FALSE.
253 if (S_FALSE == hr) 253 if (S_FALSE == hr)
254 { 254 {
255 hr = PathDirectoryContainsPath(sczSecondary, pLaunchApprovedExe->sczExecutablePath); 255 hr = PathDirectoryContainsPath(sczSecondary, wzExecutablePath);
256 if (S_OK == hr) 256 if (S_OK == hr)
257 { 257 {
258 ExitFunction(); 258 ExitFunction();
259 } 259 }
260 } 260 }
261 261
262 hr = PathDirectoryContainsPath(scz, pLaunchApprovedExe->sczExecutablePath); 262 hr = PathDirectoryContainsPath(scz, wzExecutablePath);
263 if (S_OK == hr) 263 if (S_OK == hr)
264 { 264 {
265 ExitFunction(); 265 ExitFunction();
diff --git a/src/burn/engine/approvedexe.h b/src/burn/engine/approvedexe.h
index 8a3f6779..cbfda601 100644
--- a/src/burn/engine/approvedexe.h
+++ b/src/burn/engine/approvedexe.h
@@ -67,7 +67,7 @@ HRESULT ApprovedExesLaunch(
67HRESULT ApprovedExesVerifySecureLocation( 67HRESULT ApprovedExesVerifySecureLocation(
68 __in BURN_CACHE* pCache, 68 __in BURN_CACHE* pCache,
69 __in BURN_VARIABLES* pVariables, 69 __in BURN_VARIABLES* pVariables,
70 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe 70 __in LPCWSTR wzExecutablePath
71 ); 71 );
72 72
73 73
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp
index 6a0343bd..81279cf6 100644
--- a/src/burn/engine/bundlepackageengine.cpp
+++ b/src/burn/engine/bundlepackageengine.cpp
@@ -365,8 +365,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
365 break; 365 break;
366 366
367 default: 367 default:
368 hr = E_INVALIDARG; 368 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package current state: %d.", pPackage->currentState);
369 ExitOnRootFailure(hr, "Invalid package current state: %d.", pPackage->currentState);
370 } 369 }
371 370
372 // Calculate the rollback action if there is an execute action. 371 // Calculate the rollback action if there is an execute action.
@@ -413,8 +412,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
413 break; 412 break;
414 413
415 default: 414 default:
416 hr = E_INVALIDARG; 415 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package expected state.");
417 ExitOnRootFailure(hr, "Invalid package expected state.");
418 } 416 }
419 } 417 }
420 418
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index 75b24ec3..9c7cf89f 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -3858,7 +3858,7 @@ static HRESULT OnLaunchApprovedExe(
3858 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath); 3858 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath);
3859 ExitOnFailure(hr, "Failed to read the value for the approved exe path."); 3859 ExitOnFailure(hr, "Failed to read the value for the approved exe path.");
3860 3860
3861 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe); 3861 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe->sczExecutablePath);
3862 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath); 3862 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath);
3863 if (S_FALSE == hr) 3863 if (S_FALSE == hr)
3864 { 3864 {
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index 1c03145b..52524edb 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -331,6 +331,13 @@ Language=English
331Detected msi package with invalid version, product code: '%1!ls!', version: '%2!ls!' 331Detected msi package with invalid version, product code: '%1!ls!', version: '%2!ls!'
332. 332.
333 333
334MessageId=124
335Severity=Warning
336SymbolicName=MSG_DETECTED_EXE_PACKAGE_INVALID_VERSION
337Language=English
338Detected exe package with invalid version, arp id: '%1!ls!', version: '%2!ls!'
339.
340
334MessageId=151 341MessageId=151
335Severity=Error 342Severity=Error
336SymbolicName=MSG_FAILED_DETECT_PACKAGE 343SymbolicName=MSG_FAILED_DETECT_PACKAGE
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp
index 808577bc..3a64ecd8 100644
--- a/src/burn/engine/exeengine.cpp
+++ b/src/burn/engine/exeengine.cpp
@@ -2,6 +2,16 @@
2 2
3#include "precomp.h" 3#include "precomp.h"
4 4
5static HRESULT DetectArpEntry(
6 __in const BURN_PACKAGE* pPackage,
7 __out BOOTSTRAPPER_PACKAGE_STATE* pPackageState,
8 __out_opt LPWSTR* psczQuietUninstallString
9 );
10static HRESULT ParseArpUninstallString(
11 __in_z LPCWSTR wzArpUninstallString,
12 __inout LPWSTR* psczExecutablePath,
13 __inout LPWSTR* psczArguments
14 );
5 15
6// function definitions 16// function definitions
7 17
@@ -16,18 +26,73 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
16 IXMLDOMNode* pixnNode = NULL; 26 IXMLDOMNode* pixnNode = NULL;
17 LPWSTR scz = NULL; 27 LPWSTR scz = NULL;
18 28
19 // @DetectCondition 29 // @DetectionType
20 hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition); 30 hr = XmlGetAttributeEx(pixnExePackage, L"DetectionType", &scz);
21 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @DetectCondition."); 31 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectionType.");
32
33 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"condition", -1))
34 {
35 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_CONDITION;
36 }
37 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"arp", -1))
38 {
39 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_ARP;
40 }
41 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"none", -1))
42 {
43 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_NONE;
44 }
45 else
46 {
47 ExitWithRootFailure(hr, E_UNEXPECTED, "Invalid detection type: %ls", scz);
48 }
49
50 if (BURN_EXE_DETECTION_TYPE_CONDITION == pPackage->Exe.detectionType)
51 {
52 // @DetectCondition
53 hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition);
54 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectCondition.");
55
56 // @UninstallArguments
57 hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments);
58 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @UninstallArguments.");
59
60 // @Uninstallable
61 hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable);
62 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable.");
63 }
64 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType)
65 {
66 // @ArpId
67 hr = XmlGetAttributeEx(pixnExePackage, L"ArpId", &scz);
68 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ArpId.");
69
70 hr = PathConcatRelativeToBase(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\", scz, &pPackage->Exe.sczArpKeyPath);
71 ExitOnFailure(hr, "Failed to build full key path.");
72
73 // @ArpDisplayVersion
74 hr = XmlGetAttributeEx(pixnExePackage, L"ArpDisplayVersion", &scz);
75 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ArpDisplayVersion.");
76
77 hr = VerParseVersion(scz, 0, FALSE, &pPackage->Exe.pArpDisplayVersion);
78 ExitOnFailure(hr, "Failed to parse @ArpDisplayVersion: %ls", scz);
79
80 if (pPackage->Exe.pArpDisplayVersion->fInvalid)
81 {
82 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
83 }
84
85 // @ArpWin64
86 hr = XmlGetYesNoAttribute(pixnExePackage, L"ArpWin64", &pPackage->Exe.fArpWin64);
87 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @ArpWin64.");
88
89 pPackage->Exe.fUninstallable = TRUE;
90 }
22 91
23 // @InstallArguments 92 // @InstallArguments
24 hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments); 93 hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments);
25 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments."); 94 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments.");
26 95
27 // @UninstallArguments
28 hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments);
29 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @UninstallArguments.");
30
31 // @RepairArguments 96 // @RepairArguments
32 hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments); 97 hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments);
33 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments."); 98 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments.");
@@ -36,10 +101,6 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
36 hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable); 101 hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable);
37 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Repairable."); 102 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Repairable.");
38 103
39 // @Uninstallable
40 hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable);
41 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable.");
42
43 // @Bundle 104 // @Bundle
44 hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle); 105 hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle);
45 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle."); 106 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle.");
@@ -64,8 +125,7 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
64 } 125 }
65 else 126 else
66 { 127 {
67 hr = E_UNEXPECTED; 128 ExitWithRootFailure(hr, E_UNEXPECTED, "Invalid protocol type: %ls", scz);
68 ExitOnFailure(hr, "Invalid protocol type: %ls", scz);
69 } 129 }
70 } 130 }
71 131
@@ -91,6 +151,8 @@ extern "C" void ExeEnginePackageUninitialize(
91 ReleaseStr(pPackage->Exe.sczInstallArguments); 151 ReleaseStr(pPackage->Exe.sczInstallArguments);
92 ReleaseStr(pPackage->Exe.sczRepairArguments); 152 ReleaseStr(pPackage->Exe.sczRepairArguments);
93 ReleaseStr(pPackage->Exe.sczUninstallArguments); 153 ReleaseStr(pPackage->Exe.sczUninstallArguments);
154 ReleaseStr(pPackage->Exe.sczArpKeyPath);
155 ReleaseVerutilVersion(pPackage->Exe.pArpDisplayVersion);
94 ReleaseMem(pPackage->Exe.rgExitCodes); 156 ReleaseMem(pPackage->Exe.rgExitCodes);
95 157
96 // free command-line arguments 158 // free command-line arguments
@@ -126,15 +188,31 @@ extern "C" HRESULT ExeEngineDetectPackage(
126 HRESULT hr = S_OK; 188 HRESULT hr = S_OK;
127 BOOL fDetected = FALSE; 189 BOOL fDetected = FALSE;
128 190
129 // evaluate detect condition 191 switch (pPackage->Exe.detectionType)
130 if (pPackage->Exe.sczDetectCondition && *pPackage->Exe.sczDetectCondition)
131 { 192 {
132 hr = ConditionEvaluate(pVariables, pPackage->Exe.sczDetectCondition, &fDetected); 193 case BURN_EXE_DETECTION_TYPE_NONE:
133 ExitOnFailure(hr, "Failed to evaluate executable package detect condition."); 194 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
134 } 195 break;
196 case BURN_EXE_DETECTION_TYPE_CONDITION:
197 // evaluate detect condition
198 if (pPackage->Exe.sczDetectCondition && *pPackage->Exe.sczDetectCondition)
199 {
200 hr = ConditionEvaluate(pVariables, pPackage->Exe.sczDetectCondition, &fDetected);
201 ExitOnFailure(hr, "Failed to evaluate EXE package detect condition.");
202 }
203
204 // update detect state
205 pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
135 206
136 // update detect state 207 break;
137 pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT; 208 case BURN_EXE_DETECTION_TYPE_ARP:
209 hr = DetectArpEntry(pPackage, &pPackage->currentState, NULL);
210 ExitOnFailure(hr, "Failed to detect EXE package by ArpEntry.");
211
212 break;
213 default:
214 ExitWithRootFailure(hr, E_INVALIDARG, "Unknown EXE package detection type: %d.", pPackage->Exe.detectionType);
215 }
138 216
139 if (pPackage->fCanAffectRegistration) 217 if (pPackage->fCanAffectRegistration)
140 { 218 {
@@ -187,6 +265,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
187 } 265 }
188 break; 266 break;
189 267
268 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
190 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: 269 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
191 switch (pPackage->requested) 270 switch (pPackage->requested)
192 { 271 {
@@ -205,8 +284,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
205 break; 284 break;
206 285
207 default: 286 default:
208 hr = E_INVALIDARG; 287 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package current state: %d.", pPackage->currentState);
209 ExitOnRootFailure(hr, "Invalid package current state: %d.", pPackage->currentState);
210 } 288 }
211 289
212 // Calculate the rollback action if there is an execute action. 290 // Calculate the rollback action if there is an execute action.
@@ -232,6 +310,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
232 } 310 }
233 break; 311 break;
234 312
313 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
235 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: 314 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
236 switch (pPackage->requested) 315 switch (pPackage->requested)
237 { 316 {
@@ -251,8 +330,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
251 break; 330 break;
252 331
253 default: 332 default:
254 hr = E_INVALIDARG; 333 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package expected state.");
255 ExitOnRootFailure(hr, "Invalid package expected state.");
256 } 334 }
257 } 335 }
258 336
@@ -356,10 +434,41 @@ extern "C" HRESULT ExeEngineExecutePackage(
356 LPWSTR sczUserArgs = NULL; 434 LPWSTR sczUserArgs = NULL;
357 LPWSTR sczUserArgsObfuscated = NULL; 435 LPWSTR sczUserArgsObfuscated = NULL;
358 LPWSTR sczCommandObfuscated = NULL; 436 LPWSTR sczCommandObfuscated = NULL;
437 LPWSTR sczArpUninstallString = NULL;
438 LPWSTR sczArpArguments = NULL;
439 BOOTSTRAPPER_PACKAGE_STATE applyState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN;
359 HANDLE hExecutableFile = INVALID_HANDLE_VALUE; 440 HANDLE hExecutableFile = INVALID_HANDLE_VALUE;
360 DWORD dwExitCode = 0; 441 DWORD dwExitCode = 0;
361 BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; 442 BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage;
362 BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; 443 BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload;
444 LPCWSTR wzUninstallArguments = pPackage->Exe.sczUninstallArguments;
445
446 if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType &&
447 (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action ||
448 BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action && fRollback))
449 {
450 hr = DetectArpEntry(pPackage, &applyState, &sczArpUninstallString);
451 ExitOnFailure(hr, "Failed to query ArpEntry for uninstall.");
452
453 if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT == applyState && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action)
454 {
455 if (fRollback)
456 {
457 LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), LoggingPackageStateToString(applyState));
458 }
459 else
460 {
461 LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pPackage->sczId);
462 }
463
464 ExitFunction();
465 }
466 else if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT != applyState && BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action)
467 {
468 LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), LoggingPackageStateToString(applyState));
469 ExitFunction();
470 }
471 }
363 472
364 if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification) 473 if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification)
365 { 474 {
@@ -372,7 +481,30 @@ extern "C" HRESULT ExeEngineExecutePackage(
372 ExitOnFailure(hr, "Failed to build executable path."); 481 ExitOnFailure(hr, "Failed to build executable path.");
373 482
374 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); 483 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
375 ExitOnFailure(hr, "Failed to get cached path for pseudo-package: %ls", pPackage->sczId); 484 ExitOnFailure(hr, "Failed to get parent directory for pseudo-package: %ls", pPackage->sczId);
485 }
486 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action)
487 {
488 ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "QuietUninstallString is null.");
489
490 hr = ParseArpUninstallString(sczArpUninstallString, &sczExecutablePath, &sczArpArguments);
491 ExitOnFailure(hr, "Failed to parse QuietUninstallString: %ls.", sczArpUninstallString);
492
493 if (pPackage->fPerMachine)
494 {
495 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath);
496 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath);
497 if (S_FALSE == hr)
498 {
499 LogStringLine(REPORT_STANDARD, "The QuietUninstallString executable path is not in a secure location: %ls", sczExecutablePath);
500 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
501 }
502 }
503
504 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
505 ExitOnFailure(hr, "Failed to get parent directory for QuietUninstallString executable path: %ls", sczExecutablePath);
506
507 wzUninstallArguments = sczArpArguments;
376 } 508 }
377 else 509 else
378 { 510 {
@@ -396,7 +528,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
396 break; 528 break;
397 529
398 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: 530 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
399 wzArguments = pPackage->Exe.sczUninstallArguments; 531 wzArguments = wzUninstallArguments;
400 break; 532 break;
401 533
402 case BOOTSTRAPPER_ACTION_STATE_REPAIR: 534 case BOOTSTRAPPER_ACTION_STATE_REPAIR:
@@ -404,8 +536,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
404 break; 536 break;
405 537
406 default: 538 default:
407 hr = E_INVALIDARG; 539 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
408 ExitOnFailure(hr, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
409 } 540 }
410 541
411 // now add optional arguments 542 // now add optional arguments
@@ -443,8 +574,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
443 break; 574 break;
444 575
445 default: 576 default:
446 hr = E_INVALIDARG; 577 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
447 ExitOnFailure(hr, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
448 } 578 }
449 } 579 }
450 } 580 }
@@ -524,6 +654,8 @@ LExit:
524 StrSecureZeroFreeString(sczUserArgs); 654 StrSecureZeroFreeString(sczUserArgs);
525 ReleaseStr(sczUserArgsObfuscated); 655 ReleaseStr(sczUserArgsObfuscated);
526 ReleaseStr(sczCommandObfuscated); 656 ReleaseStr(sczCommandObfuscated);
657 ReleaseStr(sczArpUninstallString);
658 ReleaseStr(sczArpArguments);
527 659
528 ReleaseFileHandle(hExecutableFile); 660 ReleaseFileHandle(hExecutableFile);
529 661
@@ -894,3 +1026,106 @@ extern "C" HRESULT ExeEngineHandleExitCode(
894//LExit: 1026//LExit:
895 return hr; 1027 return hr;
896} 1028}
1029
1030static HRESULT DetectArpEntry(
1031 __in const BURN_PACKAGE* pPackage,
1032 __out BOOTSTRAPPER_PACKAGE_STATE* pPackageState,
1033 __out_opt LPWSTR* psczQuietUninstallString
1034 )
1035{
1036 HRESULT hr = S_OK;
1037 HKEY hKey = NULL;
1038 VERUTIL_VERSION* pVersion = NULL;
1039 int nCompareResult = 0;
1040 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1041 REG_KEY_BITNESS keyBitness = pPackage->Exe.fArpWin64 ? REG_KEY_64BIT : REG_KEY_32BIT;
1042
1043 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
1044 if (psczQuietUninstallString)
1045 {
1046 ReleaseNullStr(*psczQuietUninstallString);
1047 }
1048
1049 hr = RegOpenEx(hkRoot, pPackage->Exe.sczArpKeyPath, KEY_READ, keyBitness, &hKey);
1050 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1051 {
1052 ExitFunction1(hr = S_OK);
1053 }
1054 ExitOnFailure(hr, "Failed to open registry key: %ls.", pPackage->Exe.sczArpKeyPath);
1055
1056 hr = RegReadWixVersion(hKey, L"DisplayVersion", &pVersion);
1057 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1058 {
1059 ExitFunction1(hr = S_OK);
1060 }
1061 ExitOnFailure(hr, "Failed to read DisplayVersion.");
1062
1063 if (pVersion->fInvalid)
1064 {
1065 LogId(REPORT_WARNING, MSG_DETECTED_EXE_PACKAGE_INVALID_VERSION, pPackage->Exe.sczArpKeyPath, pVersion->sczVersion);
1066 }
1067
1068 hr = VerCompareParsedVersions(pPackage->Exe.pArpDisplayVersion, pVersion, &nCompareResult);
1069 ExitOnFailure(hr, "Failed to compare versions.");
1070
1071 if (nCompareResult < 0)
1072 {
1073 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE;
1074 }
1075 else if (nCompareResult > 0)
1076 {
1077 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
1078 }
1079 else
1080 {
1081 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT;
1082 }
1083
1084 if (psczQuietUninstallString)
1085 {
1086 hr = RegReadString(hKey, L"QuietUninstallString", psczQuietUninstallString);
1087 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1088 {
1089 hr = S_OK;
1090 }
1091 ExitOnFailure(hr, "Failed to read QuietUninstallString.");
1092 }
1093
1094LExit:
1095 ReleaseRegKey(hKey);
1096 ReleaseVerutilVersion(pVersion);
1097
1098 return hr;
1099}
1100
1101static HRESULT ParseArpUninstallString(
1102 __in_z LPCWSTR wzArpUninstallString,
1103 __inout LPWSTR* psczExecutablePath,
1104 __inout LPWSTR* psczArguments
1105 )
1106{
1107 HRESULT hr = S_OK;
1108 int argc = 0;
1109 LPWSTR* argv = NULL;
1110
1111 hr = AppParseCommandLine(wzArpUninstallString, &argc, &argv);
1112 ExitOnFailure(hr, "Failed to parse uninstall string as command line: %ls.", wzArpUninstallString);
1113 ExitOnNull(argc, hr, E_INVALIDARG, "Uninstall string must contain an executable path.");
1114
1115 hr = StrAllocString(psczExecutablePath, argv[0], 0);
1116 ExitOnFailure(hr, "Failed to copy executable path for ArpCommand.");
1117
1118 for (int i = 1; i < argc; ++i)
1119 {
1120 hr = AppAppendCommandLineArgument(psczArguments, argv[i]);
1121 ExitOnFailure(hr, "Failed to append argument for ArpCommand.");
1122 }
1123
1124LExit:
1125 if (argv)
1126 {
1127 AppFreeCommandLineArgs(argv);
1128 }
1129
1130 return hr;
1131}
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index 3ec77baf..85f34de5 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -16,6 +16,13 @@ typedef _BURN_PACKAGE BURN_PACKAGE;
16 16
17const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000; 17const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000;
18 18
19enum BURN_EXE_DETECTION_TYPE
20{
21 BURN_EXE_DETECTION_TYPE_NONE,
22 BURN_EXE_DETECTION_TYPE_CONDITION,
23 BURN_EXE_DETECTION_TYPE_ARP,
24};
25
19enum BURN_EXE_EXIT_CODE_TYPE 26enum BURN_EXE_EXIT_CODE_TYPE
20{ 27{
21 BURN_EXE_EXIT_CODE_TYPE_NONE, 28 BURN_EXE_EXIT_CODE_TYPE_NONE,
@@ -338,6 +345,12 @@ typedef struct _BURN_PACKAGE
338 } Bundle; 345 } Bundle;
339 struct 346 struct
340 { 347 {
348 BURN_EXE_DETECTION_TYPE detectionType;
349
350 BOOL fArpWin64;
351 LPWSTR sczArpKeyPath;
352 VERUTIL_VERSION* pArpDisplayVersion;
353
341 LPWSTR sczDetectCondition; 354 LPWSTR sczDetectCondition;
342 LPWSTR sczInstallArguments; 355 LPWSTR sczInstallArguments;
343 LPWSTR sczRepairArguments; 356 LPWSTR sczRepairArguments;
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index 52bf6298..419d3272 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -2798,7 +2798,8 @@ static BOOL NeedsCache(
2798{ 2798{
2799 BOOTSTRAPPER_ACTION_STATE action = fExecute ? pPackage->execute : pPackage->rollback; 2799 BOOTSTRAPPER_ACTION_STATE action = fExecute ? pPackage->execute : pPackage->rollback;
2800 // TODO: bundles could theoretically use package cache 2800 // TODO: bundles could theoretically use package cache
2801 if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || BURN_PACKAGE_TYPE_EXE == pPackage->type) // Bundle and Exe packages require the package for all operations (even uninstall). 2801 if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || // Bundle and Exe packages require the package for all operations (even uninstall).
2802 BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_DETECTION_TYPE_ARP != pPackage->Exe.detectionType)
2802 { 2803 {
2803 return BOOTSTRAPPER_ACTION_STATE_NONE != action; 2804 return BOOTSTRAPPER_ACTION_STATE_NONE != action;
2804 } 2805 }
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
index e1a28712..f07418a7 100644
--- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
@@ -81,6 +81,7 @@
81 <None Include="TestData\CacheTest\CacheSignatureTest.File" CopyToOutputDirectory="PreserveNewest" /> 81 <None Include="TestData\CacheTest\CacheSignatureTest.File" CopyToOutputDirectory="PreserveNewest" />
82 <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> 82 <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
83 <None Include="TestData\PlanTest\BundlePackage_Multiple_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> 83 <None Include="TestData\PlanTest\BundlePackage_Multiple_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
84 <None Include="TestData\PlanTest\ExePackage_PerUserArpEntry_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
84 <None Include="TestData\PlanTest\Failure_BundleD_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> 85 <None Include="TestData\PlanTest\Failure_BundleD_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
85 <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> 86 <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
86 <None Include="TestData\PlanTest\MsuPackageFixture_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> 87 <None Include="TestData\PlanTest\MsuPackageFixture_manifest.xml" CopyToOutputDirectory="PreserveNewest" />
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp
index be078c5c..2135d9f5 100644
--- a/src/burn/test/BurnUnitTest/PlanTest.cpp
+++ b/src/burn/test/BurnUnitTest/PlanTest.cpp
@@ -9,6 +9,7 @@ static HRESULT WINAPI PlanTestBAProc(
9 __in_opt LPVOID pvContext 9 __in_opt LPVOID pvContext
10 ); 10 );
11 11
12static LPCWSTR wzArpEntryExeManifestFileName = L"ExePackage_PerUserArpEntry_manifest.xml";
12static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; 13static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml";
13static LPCWSTR wzMultipleBundlePackageManifestFileName = L"BundlePackage_Multiple_manifest.xml"; 14static LPCWSTR wzMultipleBundlePackageManifestFileName = L"BundlePackage_Multiple_manifest.xml";
14static LPCWSTR wzSingleExeManifestFileName = L"Failure_BundleD_manifest.xml"; 15static LPCWSTR wzSingleExeManifestFileName = L"Failure_BundleD_manifest.xml";
@@ -48,6 +49,266 @@ namespace Bootstrapper
48 } 49 }
49 50
50 [Fact] 51 [Fact]
52 void ArpEntryExeInstallTest()
53 {
54 HRESULT hr = S_OK;
55 BURN_ENGINE_STATE engineState = { };
56 BURN_ENGINE_STATE* pEngineState = &engineState;
57 BURN_PLAN* pPlan = &engineState.plan;
58
59 InitializeEngineStateForCorePlan(wzArpEntryExeManifestFileName, pEngineState);
60 DetectAttachedContainerAsAttached(pEngineState);
61 DetectPermanentPackagesAsPresentAndCached(pEngineState);
62
63 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
64 NativeAssert::Succeeded(hr, "CorePlan failed");
65
66 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
67 NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleId);
68 NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleProviderKey);
69 Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle);
70 Assert::Equal<BOOL>(FALSE, pPlan->fPerMachine);
71 Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
72 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
73 Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
74 Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
75 Assert::Equal<DWORD>(BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY, pPlan->dwRegistrationOperations);
76
77 BOOL fRollback = FALSE;
78 DWORD dwIndex = 0;
79 ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}");
80 Assert::Equal(dwIndex, pPlan->cRegistrationActions);
81
82 fRollback = TRUE;
83 dwIndex = 0;
84 ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}");
85 Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions);
86
87 fRollback = FALSE;
88 dwIndex = 0;
89 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
90 ValidateCachePackage(pPlan, fRollback, dwIndex++, L"TestExe");
91 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
92 Assert::Equal(dwIndex, pPlan->cCacheActions);
93
94 fRollback = TRUE;
95 dwIndex = 0;
96 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
97
98 Assert::Equal(119695ull, pPlan->qwCacheSizeTotal);
99
100 fRollback = FALSE;
101 dwIndex = 0;
102 DWORD dwExecuteCheckpointId = 2;
103 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
104 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
105 ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"TestExe");
106 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
107 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_INSTALL);
108 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
109 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
110 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
111 Assert::Equal(dwIndex, pPlan->cExecuteActions);
112
113 fRollback = TRUE;
114 dwIndex = 0;
115 dwExecuteCheckpointId = 2;
116 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
117 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
118 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_UNINSTALL);
119 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
120 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
121 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
122 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
123 Assert::Equal(dwIndex, pPlan->cRollbackActions);
124
125 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
126 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
127
128 dwIndex = 0;
129 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
130
131 dwIndex = 0;
132 ValidateCleanAction(pPlan, dwIndex++, L"NetFx48Web");
133 Assert::Equal(dwIndex, pPlan->cCleanActions);
134
135 UINT uIndex = 0;
136 ValidatePlannedProvider(pPlan, uIndex++, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", NULL);
137 Assert::Equal(uIndex, pPlan->cPlannedProviders);
138
139 Assert::Equal(2ul, pEngineState->packages.cPackages);
140 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"TestExe", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
141 }
142
143 [Fact]
144 void ArpEntryExeInstallObsoleteTest()
145 {
146 HRESULT hr = S_OK;
147 BURN_ENGINE_STATE engineState = { };
148 BURN_ENGINE_STATE* pEngineState = &engineState;
149 BURN_PLAN* pPlan = &engineState.plan;
150
151 InitializeEngineStateForCorePlan(wzArpEntryExeManifestFileName, pEngineState);
152 DetectAttachedContainerAsAttached(pEngineState);
153 DetectPermanentPackagesAsPresentAndCached(pEngineState);
154
155 pEngineState->packages.rgPackages[1].currentState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE;
156
157 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
158 NativeAssert::Succeeded(hr, "CorePlan failed");
159
160 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
161 NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleId);
162 NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleProviderKey);
163 Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle);
164 Assert::Equal<BOOL>(FALSE, pPlan->fPerMachine);
165 Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
166 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
167 Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
168 Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
169 Assert::Equal<DWORD>(BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY, pPlan->dwRegistrationOperations);
170
171 BOOL fRollback = FALSE;
172 DWORD dwIndex = 0;
173 ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}");
174 Assert::Equal(dwIndex, pPlan->cRegistrationActions);
175
176 fRollback = TRUE;
177 dwIndex = 0;
178 ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}");
179 Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions);
180
181 fRollback = FALSE;
182 dwIndex = 0;
183 Assert::Equal(dwIndex, pPlan->cCacheActions);
184
185 fRollback = TRUE;
186 dwIndex = 0;
187 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
188
189 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
190
191 fRollback = FALSE;
192 dwIndex = 0;
193 DWORD dwExecuteCheckpointId = 1;
194 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
195 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
196 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
197 Assert::Equal(dwIndex, pPlan->cExecuteActions);
198
199 fRollback = TRUE;
200 dwIndex = 0;
201 dwExecuteCheckpointId = 1;
202 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
203 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
204 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
205 Assert::Equal(dwIndex, pPlan->cRollbackActions);
206
207 Assert::Equal(0ul, pPlan->cExecutePackagesTotal);
208 Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal);
209
210 dwIndex = 0;
211 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
212
213 dwIndex = 0;
214 ValidateCleanAction(pPlan, dwIndex++, L"NetFx48Web");
215 Assert::Equal(dwIndex, pPlan->cCleanActions);
216
217 UINT uIndex = 0;
218 ValidatePlannedProvider(pPlan, uIndex++, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", NULL);
219 Assert::Equal(uIndex, pPlan->cPlannedProviders);
220
221 Assert::Equal(2ul, pEngineState->packages.cPackages);
222 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"TestExe", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
223 }
224
225 [Fact]
226 void ArpEntryExeUninstallTest()
227 {
228 HRESULT hr = S_OK;
229 BURN_ENGINE_STATE engineState = { };
230 BURN_ENGINE_STATE* pEngineState = &engineState;
231 BURN_PLAN* pPlan = &engineState.plan;
232
233 InitializeEngineStateForCorePlan(wzArpEntryExeManifestFileName, pEngineState);
234 DetectPackagesAsPresentAndCached(pEngineState);
235
236 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL);
237 NativeAssert::Succeeded(hr, "CorePlan failed");
238
239 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action);
240 NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleId);
241 NativeAssert::StringEqual(L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", pPlan->wzBundleProviderKey);
242 Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle);
243 Assert::Equal<BOOL>(FALSE, pPlan->fPerMachine);
244 Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
245 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
246 Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
247 Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
248 Assert::Equal<DWORD>(BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY, pPlan->dwRegistrationOperations);
249
250 BOOL fRollback = FALSE;
251 DWORD dwIndex = 0;
252 ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}");
253 Assert::Equal(dwIndex, pPlan->cRegistrationActions);
254
255 fRollback = TRUE;
256 dwIndex = 0;
257 ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}");
258 Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions);
259
260 fRollback = FALSE;
261 dwIndex = 0;
262 Assert::Equal(dwIndex, pPlan->cCacheActions);
263
264 fRollback = TRUE;
265 dwIndex = 0;
266 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
267
268 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
269
270 fRollback = FALSE;
271 dwIndex = 0;
272 DWORD dwExecuteCheckpointId = 1;
273 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
274 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
275 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_UNINSTALL);
276 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
277 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
278 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
279 Assert::Equal(dwIndex, pPlan->cExecuteActions);
280
281 fRollback = TRUE;
282 dwIndex = 0;
283 dwExecuteCheckpointId = 1;
284 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
285 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_INSTALL);
286 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
287 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
288 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
289 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
290 Assert::Equal(dwIndex, pPlan->cRollbackActions);
291
292 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
293 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
294
295 dwIndex = 0;
296 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
297
298 dwIndex = 0;
299 ValidateCleanAction(pPlan, dwIndex++, L"TestExe");
300 ValidateCleanAction(pPlan, dwIndex++, L"NetFx48Web");
301 Assert::Equal(dwIndex, pPlan->cCleanActions);
302
303 UINT uIndex = 0;
304 ValidatePlannedProvider(pPlan, uIndex++, L"{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}", NULL);
305 Assert::Equal(uIndex, pPlan->cPlannedProviders);
306
307 Assert::Equal(2ul, pEngineState->packages.cPackages);
308 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"TestExe", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
309 }
310
311 [Fact]
51 void MsiTransactionInstallTest() 312 void MsiTransactionInstallTest()
52 { 313 {
53 HRESULT hr = S_OK; 314 HRESULT hr = S_OK;
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml
index b02c2056..862156e8 100644
--- a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~BundlePackageTests_MultipleBundlePackagesBundle" Extension=".log" /><RelatedBundle Id="{86D214FB-8D74-456C-99B3-6557ECA6159C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="BundlePackageTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="15696370" Hash="0F9966B421400E481D394DB4C4D7F0F92548E5BEB79B98880C926E817E8C1F381EC8A17053E2E66AE7132A3C9ECE441629E6A1FB3452C5C9282280C40252F141" FilePath="MultipleBundlePackagesBundle.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="BundleA.exe" FileSize="5241635" Hash="20E1AFF76DE4693CB2876DC6BCCA0152DB16BE49AEDE2CD581C03FC39AB89DEA12BC25CB435F06E4D7D2B4443CE8A8935D5E92E2E49A4981B60A273980E4B29B" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="PackageB" FilePath="BundleB_x64.exe" FileSize="10450821" Hash="43A58873D61D6E0FA83F6C5266F2F05FEA9BC85D11C195493B7FD9F0B4AA799C1EFCB78D76DCED32124D2EC62A4E7114B62CDE6F0B87E42A7E28CDBB0DA0FF8E" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}" ExecutableName="MultipleBundlePackagesBundle.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"><Arp Register="yes" DisplayName="~BundlePackageTests - MultipleBundlePackagesBundle" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><BundlePackage Id="PackageA" Cache="keep" CacheId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}v1.0.0.0" InstallSize="2169" Size="5241635" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" RepairCondition="0" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" BundleId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="no"><Provides Key="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleA" Imported="yes" /><RelatedBundle Id="{8C7E2C47-1EE7-4BBE-99A2-EAB7F3693F48}" Action="Upgrade" /><PayloadRef Id="PackageA" /></BundlePackage><BundlePackage Id="PackageB" Cache="keep" CacheId="{7506235A-7C59-4750-82C7-EB460A87ED3A}v1.0.0.0" InstallSize="1441497" Size="10450821" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageB" RollbackLogPathVariable="WixBundleRollbackLog_PackageB" BundleId="{7506235A-7C59-4750-82C7-EB460A87ED3A}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="yes"><Provides Key="{7506235A-7C59-4750-82C7-EB460A87ED3A}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleB_x64" Imported="yes" /><RelatedBundle Id="{79F45B7A-D990-46E4-819B-078D87C3321A}" Action="Upgrade" /><PayloadRef Id="PackageB" /></BundlePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~BundlePackageTests_MultipleBundlePackagesBundle" Extension=".log" /><RelatedBundle Id="{86D214FB-8D74-456C-99B3-6557ECA6159C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="BundlePackageTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="15696370" Hash="0F9966B421400E481D394DB4C4D7F0F92548E5BEB79B98880C926E817E8C1F381EC8A17053E2E66AE7132A3C9ECE441629E6A1FB3452C5C9282280C40252F141" FilePath="MultipleBundlePackagesBundle.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="BundleA.exe" FileSize="5241635" Hash="20E1AFF76DE4693CB2876DC6BCCA0152DB16BE49AEDE2CD581C03FC39AB89DEA12BC25CB435F06E4D7D2B4443CE8A8935D5E92E2E49A4981B60A273980E4B29B" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="PackageB" FilePath="BundleB_x64.exe" FileSize="10450821" Hash="43A58873D61D6E0FA83F6C5266F2F05FEA9BC85D11C195493B7FD9F0B4AA799C1EFCB78D76DCED32124D2EC62A4E7114B62CDE6F0B87E42A7E28CDBB0DA0FF8E" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}" ExecutableName="MultipleBundlePackagesBundle.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"><Arp Register="yes" DisplayName="~BundlePackageTests - MultipleBundlePackagesBundle" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4" DetectionType="condition"><PayloadRef Id="NetFx48Web" /></ExePackage><BundlePackage Id="PackageA" Cache="keep" CacheId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}v1.0.0.0" InstallSize="2169" Size="5241635" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" RepairCondition="0" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" BundleId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="no"><Provides Key="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleA" Imported="yes" /><RelatedBundle Id="{8C7E2C47-1EE7-4BBE-99A2-EAB7F3693F48}" Action="Upgrade" /><PayloadRef Id="PackageA" /></BundlePackage><BundlePackage Id="PackageB" Cache="keep" CacheId="{7506235A-7C59-4750-82C7-EB460A87ED3A}v1.0.0.0" InstallSize="1441497" Size="10450821" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageB" RollbackLogPathVariable="WixBundleRollbackLog_PackageB" BundleId="{7506235A-7C59-4750-82C7-EB460A87ED3A}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="yes"><Provides Key="{7506235A-7C59-4750-82C7-EB460A87ED3A}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleB_x64" Imported="yes" /><RelatedBundle Id="{79F45B7A-D990-46E4-819B-078D87C3321A}" Action="Upgrade" /><PayloadRef Id="PackageB" /></BundlePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest>
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/ExePackage_PerUserArpEntry_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/ExePackage_PerUserArpEntry_manifest.xml
new file mode 100644
index 00000000..59d6d50f
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/ExePackage_PerUserArpEntry_manifest.xml
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest EngineVersion="4.0.0.409" ProtocolVersion="1" Win64="no" xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~ExePackageTests_PerUserArpEntryExePackage" Extension=".log" /><RelatedBundle Id="{E4683E88-AF03-40D0-B308-5C084B0E1FA0}" Action="Upgrade" /><Variable Id="TestGroupName" Value="ExePackageTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="24029" Hash="E54459AA91F60561F8AFBBCB5AEA19DB0377DB53FC3B4944E46995C2D5F97FE23E7487148DC25C14E7888CF841664EA65540529DB5E191591A83B30075098506" FilePath="PerUserArpEntryExePackage.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="TestExe.exe" FilePath="TestExe.exe" FileSize="23552" Hash="8A3CAD62E7C15EE88B3B78A5F61EFA6D4C9AED67049075688A641EE65E1526589797B0C52398DEB520A7911E41F2A6F73C178D19C9FFBC03ECF964A822E6438E" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" FilePath="TestExe.exe.config" FileSize="387" Hash="8C819A9E835F3921FA80C5C783AB0C42DDAADF0C0F2BEF8630EA122ABCB9DC8EAF0B14E061C46B37C92F55114BB09A8D5B1B613947A76A648953F2C63C0ACA63" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}" ExecutableName="PerUserArpEntryExePackage.exe" PerMachine="no" Tag="" Version="1.0.0.0" ProviderKey="{9C459DAD-0E64-40C8-8C9F-4F68E46AB223}"><Arp DisplayName="~ExePackageTests - PerUserArpEntryExePackage" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" InstallArguments="/q /norestart /log &quot;[NetFx48WebLog].html&quot;" RepairArguments="" Repairable="no" DetectionType="condition" DetectCondition="NETFRAMEWORK45 &gt;= 528040" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><ExePackage Id="TestExe" Cache="keep" CacheId="8A3CAD62E7C15EE88B3B78A5F61EFA6D4C9AED67049075688A641EE65E1526589797B0C52398DEB520A7911E41F2A6F73C178D19C9FFBC03ECF964A822E6438E" InstallSize="23939" Size="23939" PerMachine="no" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_TestExe" RollbackLogPathVariable="WixBundleRollbackLog_TestExe" InstallArguments="/regw &quot;HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{9B5300C7-9B34-4670-9614-185B02AB87EF},DisplayVersion,String,1.0.0.0&quot; /regw &quot;HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{9B5300C7-9B34-4670-9614-185B02AB87EF},QuietUninstallString,String,\&quot;[WixBundleExecutePackageCacheFolder]testexe.exe\&quot; /regd \&quot;HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{9B5300C7-9B34-4670-9614-185B02AB87EF}\&quot;&quot;" RepairArguments="" Repairable="no" DetectionType="arp" ArpId="{9B5300C7-9B34-4670-9614-185B02AB87EF}" ArpDisplayVersion="1.0.0.0"><PayloadRef Id="TestExe.exe" /><PayloadRef Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" /></ExePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml
index 6afb0108..13223db8 100644
--- a/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~FailureTests_BundleD" Extension=".log" /><RelatedBundle Id="{3C1A4842-81AC-4C90-8B35-A5E18F034C8D}" Action="Upgrade" /><Variable Id="TestGroupName" Value="FailureTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><RegistrySearch Id="wrsQ7JTGqvaQuDYjfHJoyjxtkLlR6c" Variable="ExeA_Version" Root="HKLM" Key="Software\WiX\Tests\FailureTests\ExeA" Value="Version" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="24029" Hash="03F9C95A2ADA5563D3D937C0161F22A76E12F2F0AF2AA6BE567292D0AB122E2C42990E97CA9C1EE9A5F43A571B01C4ED7A3EA5759A6836AC8BFD959D7FFDCB18" FilePath="BundleD.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="TestExe.exe" FilePath="TestExe.exe" FileSize="23552" Hash="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" FilePath="TestExe.exe.config" FileSize="387" Hash="8C819A9E835F3921FA80C5C783AB0C42DDAADF0C0F2BEF8630EA122ABCB9DC8EAF0B14E061C46B37C92F55114BB09A8D5B1B613947A76A648953F2C63C0ACA63" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{9C184683-04FB-49AD-9D79-65101BDC3EE3}" ExecutableName="BundleD.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{9C184683-04FB-49AD-9D79-65101BDC3EE3}"><Arp Register="yes" DisplayName="~FailureTests - BundleD" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><ExePackage Id="ExeA" Cache="remove" CacheId="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" InstallSize="23939" Size="23939" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_ExeA" RollbackLogPathVariable="WixBundleRollbackLog_ExeA" DetectCondition="ExeA_Version AND ExeA_Version &gt;= v1.0.0.0" InstallArguments="/s 5000 /regw &quot;HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0&quot;" UninstallArguments="/regd &quot;HKLM\Software\WiX\Tests\FailureTests\ExeA,Version&quot;" Uninstallable="yes" RepairArguments="/regw &quot;HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0&quot;" Repairable="yes"><PayloadRef Id="TestExe.exe" /><PayloadRef Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" /></ExePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~FailureTests_BundleD" Extension=".log" /><RelatedBundle Id="{3C1A4842-81AC-4C90-8B35-A5E18F034C8D}" Action="Upgrade" /><Variable Id="TestGroupName" Value="FailureTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><RegistrySearch Id="wrsQ7JTGqvaQuDYjfHJoyjxtkLlR6c" Variable="ExeA_Version" Root="HKLM" Key="Software\WiX\Tests\FailureTests\ExeA" Value="Version" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="24029" Hash="03F9C95A2ADA5563D3D937C0161F22A76E12F2F0AF2AA6BE567292D0AB122E2C42990E97CA9C1EE9A5F43A571B01C4ED7A3EA5759A6836AC8BFD959D7FFDCB18" FilePath="BundleD.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="TestExe.exe" FilePath="TestExe.exe" FileSize="23552" Hash="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" FilePath="TestExe.exe.config" FileSize="387" Hash="8C819A9E835F3921FA80C5C783AB0C42DDAADF0C0F2BEF8630EA122ABCB9DC8EAF0B14E061C46B37C92F55114BB09A8D5B1B613947A76A648953F2C63C0ACA63" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{9C184683-04FB-49AD-9D79-65101BDC3EE3}" ExecutableName="BundleD.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{9C184683-04FB-49AD-9D79-65101BDC3EE3}"><Arp Register="yes" DisplayName="~FailureTests - BundleD" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4" DetectionType="condition"><PayloadRef Id="NetFx48Web" /></ExePackage><ExePackage Id="ExeA" Cache="remove" CacheId="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" InstallSize="23939" Size="23939" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_ExeA" RollbackLogPathVariable="WixBundleRollbackLog_ExeA" DetectCondition="ExeA_Version AND ExeA_Version &gt;= v1.0.0.0" InstallArguments="/s 5000 /regw &quot;HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0&quot;" UninstallArguments="/regd &quot;HKLM\Software\WiX\Tests\FailureTests\ExeA,Version&quot;" Uninstallable="yes" RepairArguments="/regw &quot;HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0&quot;" Repairable="yes" DetectionType="condition"><PayloadRef Id="TestExe.exe" /><PayloadRef Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" /></ExePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml
index 184bba38..5cfd8c98 100644
--- a/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~SlipstreamTests_BundleA" Extension=".log" /><RelatedBundle Id="{62C28DAF-A13E-4F55-ACA1-FB843630789C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="SlipstreamTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" FileSize="140288" Hash="4569C53566B1025E243E0C29A96C608BD4019979" Packaging="embedded" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" FileSize="783" Hash="B5BDD5E7179A94C2C817069913CA8C099DF811B9" Packaging="embedded" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" FileSize="25088" Hash="DB12DB6565CDBC4E9705204830E421ACEB710129" Packaging="embedded" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" FileSize="118272" Hash="3A7A20D97B0546A23A025EE5774BE237C14D2957" Packaging="embedded" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" FileSize="114688" Hash="56BA3EA94BEBF8EB562C914495E1594E74F05DBE" Packaging="embedded" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" FileSize="3599" Hash="8D9797C1E1A50AECB8B85FFCEA6A2A2EF611BD7F" Packaging="embedded" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" FileSize="797" Hash="75AE41181581FD6376CA9CA88147011E48BF9A30" Packaging="embedded" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" FileSize="2237" Hash="068B3C5E27AECE7987EABAA2802C9EB07B39EAF8" Packaging="embedded" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" FileSize="1998" Hash="A989D9B892F497215D81F903591ECB6CD50CFFFC" Packaging="embedded" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" FileSize="2428" Hash="E6B8E4B1AA89430EB6A5A1E997CA3D1D2F968285" Packaging="embedded" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" FileSize="2256" Hash="612CD2FD0CF3800639385C0BF4D805B24507D356" Packaging="embedded" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" FileSize="2409" Hash="E59A8F11D95AC17FC70BD718706EE36BFA50EF02" Packaging="embedded" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" FileSize="3368" Hash="154E0A658BA7EE59889224A231423634A9725547" Packaging="embedded" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" FileSize="2205" Hash="6AAE55269E42F99A5D88ADD18C433384DEB9E956" Packaging="embedded" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" FileSize="2276" Hash="7DC74874357F50AE8C4871D8F4DC06B337CF6352" Packaging="embedded" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" FileSize="2362" Hash="B60C34DE38E6E48BA0841E8A962C17179FC1B69A" Packaging="embedded" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" FileSize="2273" Hash="902D231AD6306087F215DEABB7F2AB2F8072C401" Packaging="embedded" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" FileSize="2518" Hash="4095A1AFCF18C01F7DA51A1A389C2FBBB1A82A12" Packaging="embedded" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" FileSize="2209" Hash="99CE8B42300EF656E6BD44F01766DC638CB0496F" Packaging="embedded" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" FileSize="2282" Hash="87117EE32E0004E25DDCEB1A7D417F3A02856A50" Packaging="embedded" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" FileSize="2141" Hash="5AED841C6A870C3A8BAF8A10D00F887A781D0CF0" Packaging="embedded" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" FileSize="2338" Hash="07E37CBC59298F24A5C8C3B8FEB7A45DADF8CD07" Packaging="embedded" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" FileSize="2118" Hash="AEC0CE51E8E335E9B86F1AC7E39CCD172B896582" Packaging="embedded" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" FileSize="2851" Hash="9628BADB173B171ED85D902634D9AA5D91FE9721" Packaging="embedded" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" FileSize="2304" Hash="B584E8C0D7F9B7A1BB70BC00E42BFD35BED5D81D" Packaging="embedded" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" FileSize="2102" Hash="67E93F555DBFEF8508E79F7CA8CE76B881308760" Packaging="embedded" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" FileSize="2273" Hash="AEB8C90D66942A5CD73EA52A6F2ADD4F7D518A0D" Packaging="embedded" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" FileSize="2170" Hash="B1D4B71907B8BD82DD8B047404AF10FDBBE5CBA0" Packaging="embedded" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" FileSize="1953" Hash="C8FB8982EC71C48D6EA021ADD9AAA7BCB0656281" Packaging="embedded" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" FileSize="2182" Hash="825F27A543907ED27E815EC67DFD48AF7BF5831E" Packaging="embedded" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" FileSize="2369" Hash="39C07C31077AAFDC0DD208273AA41654CAD80FDD" Packaging="embedded" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" FileSize="245760" Hash="6499FA21D178131DDE13A4EF44ABEC32E91D65D4" Packaging="embedded" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" FileSize="11264" Hash="9E6452891E401EB211DD41550A09FDF98EC0992F" Packaging="embedded" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="14292" Hash="CDF09A0723F4F33C13670BBAFCFFA7E660E15DFC" Packaging="embedded" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u34" /></UX><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1479400" Hash="5A84A8E612E270E27D0061D58DB6B470153BE1F9" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="PackageAv1.msi" FileSize="32768" Hash="2369B16B7219B3C834DFBC5D2AF8B2EF8803D43D" Packaging="external" SourcePath="PackageAv1.msi" /><Payload Id="PatchA" FilePath="PatchA.msp" FileSize="20480" Hash="FABC6C18E4A778E127E84CDF67F93A291CAEC8BB" Packaging="external" SourcePath="PatchA.msp" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{22D1DDBA-284D-40A7-BD14-95EA07906F21}" ExecutableName="BundleA.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{22D1DDBA-284D-40A7-BD14-95EA07906F21}"><Arp Register="yes" DisplayName="~SlipstreamTests - BundleA" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="keep" CacheId="5A84A8E612E270E27D0061D58DB6B470153BE1F9" InstallSize="1479400" Size="1479400" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="/uninstall /q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" RepairArguments="/q /norestart /repair /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" Repairable="yes" Uninstallable="yes" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><MsiPackage Id="PackageA" Cache="keep" CacheId="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}v1.0.0.0" InstallSize="2103" Size="32768" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Language="1033" Version="1.0.0.0" UpgradeCode="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><SlipstreamMsp Id="PatchA" /><Provides Key="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Version="1.0.0.0" DisplayName="~SlipstreamTests - PackageA" /><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /></MsiPackage><MspPackage Id="PatchA" Cache="keep" CacheId="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" InstallSize="20480" Size="20480" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PatchA" RollbackLogPathVariable="WixBundleRollbackLog_PatchA" PatchCode="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" PatchXml="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;&lt;MsiPatch xmlns=&quot;http://www.microsoft.com/msi/patch_applicability.xsd&quot; SchemaVersion=&quot;1.0.0.0&quot; PatchGUID=&quot;{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}&quot; MinMsiVersion=&quot;5&quot; TargetsRTM=&quot;true&quot;&gt;&lt;TargetProduct MinMsiVersion=&quot;500&quot;&gt;&lt;TargetProductCode Validate=&quot;true&quot;&gt;{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}&lt;/TargetProductCode&gt;&lt;TargetVersion Validate=&quot;true&quot; ComparisonType=&quot;Equal&quot; ComparisonFilter=&quot;MajorMinorUpdate&quot;&gt;1.0.0.0&lt;/TargetVersion&gt;&lt;UpdatedVersion&gt;1.0.1.0&lt;/UpdatedVersion&gt;&lt;TargetLanguage Validate=&quot;false&quot;&gt;1033&lt;/TargetLanguage&gt;&lt;UpdatedLanguages&gt;1033&lt;/UpdatedLanguages&gt;&lt;UpgradeCode Validate=&quot;true&quot;&gt;{DB87BB66-FE5D-4293-81AC-EE313D3F864B}&lt;/UpgradeCode&gt;&lt;/TargetProduct&gt;&lt;TargetProductCode&gt;{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}&lt;/TargetProductCode&gt;&lt;/MsiPatch&gt;"><Provides Key="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" DisplayName="SlipstreamTests - Patch A" /><PayloadRef Id="PatchA" /></MspPackage></Chain><PatchTargetCode TargetCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Product="yes" /><CommandLine Variables="upperCase" /></BurnManifest> <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~SlipstreamTests_BundleA" Extension=".log" /><RelatedBundle Id="{62C28DAF-A13E-4F55-ACA1-FB843630789C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="SlipstreamTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" FileSize="140288" Hash="4569C53566B1025E243E0C29A96C608BD4019979" Packaging="embedded" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" FileSize="783" Hash="B5BDD5E7179A94C2C817069913CA8C099DF811B9" Packaging="embedded" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" FileSize="25088" Hash="DB12DB6565CDBC4E9705204830E421ACEB710129" Packaging="embedded" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" FileSize="118272" Hash="3A7A20D97B0546A23A025EE5774BE237C14D2957" Packaging="embedded" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" FileSize="114688" Hash="56BA3EA94BEBF8EB562C914495E1594E74F05DBE" Packaging="embedded" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" FileSize="3599" Hash="8D9797C1E1A50AECB8B85FFCEA6A2A2EF611BD7F" Packaging="embedded" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" FileSize="797" Hash="75AE41181581FD6376CA9CA88147011E48BF9A30" Packaging="embedded" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" FileSize="2237" Hash="068B3C5E27AECE7987EABAA2802C9EB07B39EAF8" Packaging="embedded" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" FileSize="1998" Hash="A989D9B892F497215D81F903591ECB6CD50CFFFC" Packaging="embedded" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" FileSize="2428" Hash="E6B8E4B1AA89430EB6A5A1E997CA3D1D2F968285" Packaging="embedded" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" FileSize="2256" Hash="612CD2FD0CF3800639385C0BF4D805B24507D356" Packaging="embedded" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" FileSize="2409" Hash="E59A8F11D95AC17FC70BD718706EE36BFA50EF02" Packaging="embedded" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" FileSize="3368" Hash="154E0A658BA7EE59889224A231423634A9725547" Packaging="embedded" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" FileSize="2205" Hash="6AAE55269E42F99A5D88ADD18C433384DEB9E956" Packaging="embedded" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" FileSize="2276" Hash="7DC74874357F50AE8C4871D8F4DC06B337CF6352" Packaging="embedded" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" FileSize="2362" Hash="B60C34DE38E6E48BA0841E8A962C17179FC1B69A" Packaging="embedded" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" FileSize="2273" Hash="902D231AD6306087F215DEABB7F2AB2F8072C401" Packaging="embedded" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" FileSize="2518" Hash="4095A1AFCF18C01F7DA51A1A389C2FBBB1A82A12" Packaging="embedded" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" FileSize="2209" Hash="99CE8B42300EF656E6BD44F01766DC638CB0496F" Packaging="embedded" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" FileSize="2282" Hash="87117EE32E0004E25DDCEB1A7D417F3A02856A50" Packaging="embedded" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" FileSize="2141" Hash="5AED841C6A870C3A8BAF8A10D00F887A781D0CF0" Packaging="embedded" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" FileSize="2338" Hash="07E37CBC59298F24A5C8C3B8FEB7A45DADF8CD07" Packaging="embedded" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" FileSize="2118" Hash="AEC0CE51E8E335E9B86F1AC7E39CCD172B896582" Packaging="embedded" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" FileSize="2851" Hash="9628BADB173B171ED85D902634D9AA5D91FE9721" Packaging="embedded" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" FileSize="2304" Hash="B584E8C0D7F9B7A1BB70BC00E42BFD35BED5D81D" Packaging="embedded" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" FileSize="2102" Hash="67E93F555DBFEF8508E79F7CA8CE76B881308760" Packaging="embedded" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" FileSize="2273" Hash="AEB8C90D66942A5CD73EA52A6F2ADD4F7D518A0D" Packaging="embedded" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" FileSize="2170" Hash="B1D4B71907B8BD82DD8B047404AF10FDBBE5CBA0" Packaging="embedded" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" FileSize="1953" Hash="C8FB8982EC71C48D6EA021ADD9AAA7BCB0656281" Packaging="embedded" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" FileSize="2182" Hash="825F27A543907ED27E815EC67DFD48AF7BF5831E" Packaging="embedded" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" FileSize="2369" Hash="39C07C31077AAFDC0DD208273AA41654CAD80FDD" Packaging="embedded" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" FileSize="245760" Hash="6499FA21D178131DDE13A4EF44ABEC32E91D65D4" Packaging="embedded" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" FileSize="11264" Hash="9E6452891E401EB211DD41550A09FDF98EC0992F" Packaging="embedded" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="14292" Hash="CDF09A0723F4F33C13670BBAFCFFA7E660E15DFC" Packaging="embedded" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u34" /></UX><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1479400" Hash="5A84A8E612E270E27D0061D58DB6B470153BE1F9" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="PackageAv1.msi" FileSize="32768" Hash="2369B16B7219B3C834DFBC5D2AF8B2EF8803D43D" Packaging="external" SourcePath="PackageAv1.msi" /><Payload Id="PatchA" FilePath="PatchA.msp" FileSize="20480" Hash="FABC6C18E4A778E127E84CDF67F93A291CAEC8BB" Packaging="external" SourcePath="PatchA.msp" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{22D1DDBA-284D-40A7-BD14-95EA07906F21}" ExecutableName="BundleA.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{22D1DDBA-284D-40A7-BD14-95EA07906F21}"><Arp Register="yes" DisplayName="~SlipstreamTests - BundleA" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="keep" CacheId="5A84A8E612E270E27D0061D58DB6B470153BE1F9" InstallSize="1479400" Size="1479400" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="/uninstall /q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" RepairArguments="/q /norestart /repair /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" Repairable="yes" Uninstallable="yes" Protocol="netfx4" DetectionType="condition"><PayloadRef Id="NetFx48Web" /></ExePackage><MsiPackage Id="PackageA" Cache="keep" CacheId="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}v1.0.0.0" InstallSize="2103" Size="32768" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Language="1033" Version="1.0.0.0" UpgradeCode="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><SlipstreamMsp Id="PatchA" /><Provides Key="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Version="1.0.0.0" DisplayName="~SlipstreamTests - PackageA" /><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /></MsiPackage><MspPackage Id="PatchA" Cache="keep" CacheId="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" InstallSize="20480" Size="20480" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PatchA" RollbackLogPathVariable="WixBundleRollbackLog_PatchA" PatchCode="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" PatchXml="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;&lt;MsiPatch xmlns=&quot;http://www.microsoft.com/msi/patch_applicability.xsd&quot; SchemaVersion=&quot;1.0.0.0&quot; PatchGUID=&quot;{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}&quot; MinMsiVersion=&quot;5&quot; TargetsRTM=&quot;true&quot;&gt;&lt;TargetProduct MinMsiVersion=&quot;500&quot;&gt;&lt;TargetProductCode Validate=&quot;true&quot;&gt;{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}&lt;/TargetProductCode&gt;&lt;TargetVersion Validate=&quot;true&quot; ComparisonType=&quot;Equal&quot; ComparisonFilter=&quot;MajorMinorUpdate&quot;&gt;1.0.0.0&lt;/TargetVersion&gt;&lt;UpdatedVersion&gt;1.0.1.0&lt;/UpdatedVersion&gt;&lt;TargetLanguage Validate=&quot;false&quot;&gt;1033&lt;/TargetLanguage&gt;&lt;UpdatedLanguages&gt;1033&lt;/UpdatedLanguages&gt;&lt;UpgradeCode Validate=&quot;true&quot;&gt;{DB87BB66-FE5D-4293-81AC-EE313D3F864B}&lt;/UpgradeCode&gt;&lt;/TargetProduct&gt;&lt;TargetProductCode&gt;{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}&lt;/TargetProductCode&gt;&lt;/MsiPatch&gt;"><Provides Key="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" DisplayName="SlipstreamTests - Patch A" /><PayloadRef Id="PatchA" /></MspPackage></Chain><PatchTargetCode TargetCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Product="yes" /><CommandLine Variables="upperCase" /></BurnManifest>
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_modified_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_modified_manifest.xml
index 0b35860b..175bfba1 100644
--- a/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_modified_manifest.xml
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_modified_manifest.xml
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~SlipstreamTests_BundleA" Extension=".log" /><RelatedBundle Id="{62C28DAF-A13E-4F55-ACA1-FB843630789C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="SlipstreamTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" FileSize="140288" Hash="4569C53566B1025E243E0C29A96C608BD4019979" Packaging="embedded" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" FileSize="783" Hash="B5BDD5E7179A94C2C817069913CA8C099DF811B9" Packaging="embedded" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" FileSize="25088" Hash="DB12DB6565CDBC4E9705204830E421ACEB710129" Packaging="embedded" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" FileSize="118272" Hash="3A7A20D97B0546A23A025EE5774BE237C14D2957" Packaging="embedded" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" FileSize="114688" Hash="56BA3EA94BEBF8EB562C914495E1594E74F05DBE" Packaging="embedded" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" FileSize="3599" Hash="8D9797C1E1A50AECB8B85FFCEA6A2A2EF611BD7F" Packaging="embedded" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" FileSize="797" Hash="75AE41181581FD6376CA9CA88147011E48BF9A30" Packaging="embedded" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" FileSize="2237" Hash="068B3C5E27AECE7987EABAA2802C9EB07B39EAF8" Packaging="embedded" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" FileSize="1998" Hash="A989D9B892F497215D81F903591ECB6CD50CFFFC" Packaging="embedded" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" FileSize="2428" Hash="E6B8E4B1AA89430EB6A5A1E997CA3D1D2F968285" Packaging="embedded" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" FileSize="2256" Hash="612CD2FD0CF3800639385C0BF4D805B24507D356" Packaging="embedded" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" FileSize="2409" Hash="E59A8F11D95AC17FC70BD718706EE36BFA50EF02" Packaging="embedded" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" FileSize="3368" Hash="154E0A658BA7EE59889224A231423634A9725547" Packaging="embedded" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" FileSize="2205" Hash="6AAE55269E42F99A5D88ADD18C433384DEB9E956" Packaging="embedded" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" FileSize="2276" Hash="7DC74874357F50AE8C4871D8F4DC06B337CF6352" Packaging="embedded" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" FileSize="2362" Hash="B60C34DE38E6E48BA0841E8A962C17179FC1B69A" Packaging="embedded" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" FileSize="2273" Hash="902D231AD6306087F215DEABB7F2AB2F8072C401" Packaging="embedded" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" FileSize="2518" Hash="4095A1AFCF18C01F7DA51A1A389C2FBBB1A82A12" Packaging="embedded" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" FileSize="2209" Hash="99CE8B42300EF656E6BD44F01766DC638CB0496F" Packaging="embedded" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" FileSize="2282" Hash="87117EE32E0004E25DDCEB1A7D417F3A02856A50" Packaging="embedded" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" FileSize="2141" Hash="5AED841C6A870C3A8BAF8A10D00F887A781D0CF0" Packaging="embedded" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" FileSize="2338" Hash="07E37CBC59298F24A5C8C3B8FEB7A45DADF8CD07" Packaging="embedded" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" FileSize="2118" Hash="AEC0CE51E8E335E9B86F1AC7E39CCD172B896582" Packaging="embedded" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" FileSize="2851" Hash="9628BADB173B171ED85D902634D9AA5D91FE9721" Packaging="embedded" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" FileSize="2304" Hash="B584E8C0D7F9B7A1BB70BC00E42BFD35BED5D81D" Packaging="embedded" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" FileSize="2102" Hash="67E93F555DBFEF8508E79F7CA8CE76B881308760" Packaging="embedded" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" FileSize="2273" Hash="AEB8C90D66942A5CD73EA52A6F2ADD4F7D518A0D" Packaging="embedded" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" FileSize="2170" Hash="B1D4B71907B8BD82DD8B047404AF10FDBBE5CBA0" Packaging="embedded" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" FileSize="1953" Hash="C8FB8982EC71C48D6EA021ADD9AAA7BCB0656281" Packaging="embedded" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" FileSize="2182" Hash="825F27A543907ED27E815EC67DFD48AF7BF5831E" Packaging="embedded" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" FileSize="2369" Hash="39C07C31077AAFDC0DD208273AA41654CAD80FDD" Packaging="embedded" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" FileSize="245760" Hash="6499FA21D178131DDE13A4EF44ABEC32E91D65D4" Packaging="embedded" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" FileSize="11264" Hash="9E6452891E401EB211DD41550A09FDF98EC0992F" Packaging="embedded" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="14292" Hash="CDF09A0723F4F33C13670BBAFCFFA7E660E15DFC" Packaging="embedded" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u34" /></UX><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1479400" Hash="5A84A8E612E270E27D0061D58DB6B470153BE1F9" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="PackageAv1.msi" FileSize="32768" Hash="2369B16B7219B3C834DFBC5D2AF8B2EF8803D43D" Packaging="external" SourcePath="PackageAv1.msi" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{22D1DDBA-284D-40A7-BD14-95EA07906F21}" ExecutableName="BundleA.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{DC94A8E0-4BF4-4026-B80B-2755DAFC05D3}"><Arp Register="yes" DisplayName="~SlipstreamTests - BundleA" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="keep" CacheId="5A84A8E612E270E27D0061D58DB6B470153BE1F9" InstallSize="1479400" Size="1479400" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" RepairArguments="/q /norestart /repair /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" Repairable="yes" Uninstallable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><MsiPackage Id="PackageA" Cache="keep" CacheId="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}v1.0.0.0" InstallSize="2103" Size="32768" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Language="1033" Version="1.0.0.0" UpgradeCode="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><Provides Key="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Version="1.0.0.0" DisplayName="~SlipstreamTests - PackageA" /><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /></MsiPackage></Chain><PatchTargetCode TargetCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Product="yes" /><CommandLine Variables="upperCase" /></BurnManifest> <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~SlipstreamTests_BundleA" Extension=".log" /><RelatedBundle Id="{62C28DAF-A13E-4F55-ACA1-FB843630789C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="SlipstreamTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" FileSize="140288" Hash="4569C53566B1025E243E0C29A96C608BD4019979" Packaging="embedded" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" FileSize="783" Hash="B5BDD5E7179A94C2C817069913CA8C099DF811B9" Packaging="embedded" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" FileSize="25088" Hash="DB12DB6565CDBC4E9705204830E421ACEB710129" Packaging="embedded" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" FileSize="118272" Hash="3A7A20D97B0546A23A025EE5774BE237C14D2957" Packaging="embedded" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" FileSize="114688" Hash="56BA3EA94BEBF8EB562C914495E1594E74F05DBE" Packaging="embedded" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" FileSize="3599" Hash="8D9797C1E1A50AECB8B85FFCEA6A2A2EF611BD7F" Packaging="embedded" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" FileSize="797" Hash="75AE41181581FD6376CA9CA88147011E48BF9A30" Packaging="embedded" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" FileSize="2237" Hash="068B3C5E27AECE7987EABAA2802C9EB07B39EAF8" Packaging="embedded" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" FileSize="1998" Hash="A989D9B892F497215D81F903591ECB6CD50CFFFC" Packaging="embedded" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" FileSize="2428" Hash="E6B8E4B1AA89430EB6A5A1E997CA3D1D2F968285" Packaging="embedded" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" FileSize="2256" Hash="612CD2FD0CF3800639385C0BF4D805B24507D356" Packaging="embedded" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" FileSize="2409" Hash="E59A8F11D95AC17FC70BD718706EE36BFA50EF02" Packaging="embedded" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" FileSize="3368" Hash="154E0A658BA7EE59889224A231423634A9725547" Packaging="embedded" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" FileSize="2205" Hash="6AAE55269E42F99A5D88ADD18C433384DEB9E956" Packaging="embedded" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" FileSize="2276" Hash="7DC74874357F50AE8C4871D8F4DC06B337CF6352" Packaging="embedded" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" FileSize="2362" Hash="B60C34DE38E6E48BA0841E8A962C17179FC1B69A" Packaging="embedded" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" FileSize="2273" Hash="902D231AD6306087F215DEABB7F2AB2F8072C401" Packaging="embedded" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" FileSize="2518" Hash="4095A1AFCF18C01F7DA51A1A389C2FBBB1A82A12" Packaging="embedded" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" FileSize="2209" Hash="99CE8B42300EF656E6BD44F01766DC638CB0496F" Packaging="embedded" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" FileSize="2282" Hash="87117EE32E0004E25DDCEB1A7D417F3A02856A50" Packaging="embedded" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" FileSize="2141" Hash="5AED841C6A870C3A8BAF8A10D00F887A781D0CF0" Packaging="embedded" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" FileSize="2338" Hash="07E37CBC59298F24A5C8C3B8FEB7A45DADF8CD07" Packaging="embedded" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" FileSize="2118" Hash="AEC0CE51E8E335E9B86F1AC7E39CCD172B896582" Packaging="embedded" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" FileSize="2851" Hash="9628BADB173B171ED85D902634D9AA5D91FE9721" Packaging="embedded" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" FileSize="2304" Hash="B584E8C0D7F9B7A1BB70BC00E42BFD35BED5D81D" Packaging="embedded" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" FileSize="2102" Hash="67E93F555DBFEF8508E79F7CA8CE76B881308760" Packaging="embedded" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" FileSize="2273" Hash="AEB8C90D66942A5CD73EA52A6F2ADD4F7D518A0D" Packaging="embedded" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" FileSize="2170" Hash="B1D4B71907B8BD82DD8B047404AF10FDBBE5CBA0" Packaging="embedded" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" FileSize="1953" Hash="C8FB8982EC71C48D6EA021ADD9AAA7BCB0656281" Packaging="embedded" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" FileSize="2182" Hash="825F27A543907ED27E815EC67DFD48AF7BF5831E" Packaging="embedded" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" FileSize="2369" Hash="39C07C31077AAFDC0DD208273AA41654CAD80FDD" Packaging="embedded" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" FileSize="245760" Hash="6499FA21D178131DDE13A4EF44ABEC32E91D65D4" Packaging="embedded" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" FileSize="11264" Hash="9E6452891E401EB211DD41550A09FDF98EC0992F" Packaging="embedded" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="14292" Hash="CDF09A0723F4F33C13670BBAFCFFA7E660E15DFC" Packaging="embedded" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u34" /></UX><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1479400" Hash="5A84A8E612E270E27D0061D58DB6B470153BE1F9" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="PackageAv1.msi" FileSize="32768" Hash="2369B16B7219B3C834DFBC5D2AF8B2EF8803D43D" Packaging="external" SourcePath="PackageAv1.msi" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{22D1DDBA-284D-40A7-BD14-95EA07906F21}" ExecutableName="BundleA.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{DC94A8E0-4BF4-4026-B80B-2755DAFC05D3}"><Arp Register="yes" DisplayName="~SlipstreamTests - BundleA" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="keep" CacheId="5A84A8E612E270E27D0061D58DB6B470153BE1F9" InstallSize="1479400" Size="1479400" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" RepairArguments="/q /norestart /repair /ChainingPackage &quot;[WixBundleName]&quot; /log &quot;[NetFx48WebLog].html&quot;" Repairable="yes" Uninstallable="no" Protocol="netfx4" DetectionType="condition"><PayloadRef Id="NetFx48Web" /></ExePackage><MsiPackage Id="PackageA" Cache="keep" CacheId="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}v1.0.0.0" InstallSize="2103" Size="32768" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Language="1033" Version="1.0.0.0" UpgradeCode="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><Provides Key="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Version="1.0.0.0" DisplayName="~SlipstreamTests - PackageA" /><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /></MsiPackage></Chain><PatchTargetCode TargetCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Product="yes" /><CommandLine Variables="upperCase" /></BurnManifest>
diff --git a/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs b/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs
index f371f674..22152da2 100644
--- a/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs
+++ b/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs
@@ -4,7 +4,7 @@
4 <Fragment> 4 <Fragment>
5 <PackageGroup Id="BundlePackages"> 5 <PackageGroup Id="BundlePackages">
6 <MsiPackage Id="PackageA" SourceFile="$(var.PackageAv1.TargetPath)" /> 6 <MsiPackage Id="PackageA" SourceFile="$(var.PackageAv1.TargetPath)" />
7 <ExePackage Id="TestExe" Cache="remove" PerMachine="yes" Permanent="yes" InstallArguments="/ec 1603"> 7 <ExePackage Id="TestExe" Cache="remove" PerMachine="yes" Permanent="yes" DetectCondition="" InstallArguments="/ec 1603">
8 <PayloadGroupRef Id="TestExePayloads" /> 8 <PayloadGroupRef Id="TestExePayloads" />
9 </ExePackage> 9 </ExePackage>
10 </PackageGroup> 10 </PackageGroup>
diff --git a/src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wixproj b/src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wixproj
new file mode 100644
index 00000000..bcb447b0
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wixproj
@@ -0,0 +1,17 @@
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<Project Sdk="WixToolset.Sdk">
3 <PropertyGroup>
4 <OutputType>Bundle</OutputType>
5 <UpgradeCode>{A843CC02-6814-48F5-997D-052073BAE744}</UpgradeCode>
6 </PropertyGroup>
7 <ItemGroup>
8 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
9 </ItemGroup>
10 <ItemGroup>
11 <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
12 </ItemGroup>
13 <ItemGroup>
14 <PackageReference Include="WixToolset.Bal.wixext" />
15 <PackageReference Include="WixToolset.NetFx.wixext" />
16 </ItemGroup>
17</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wxs b/src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wxs
new file mode 100644
index 00000000..709a7c3c
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/BrokenPerUserArpEntryExePackage/BrokenPerUserArpEntryExePackage.wxs
@@ -0,0 +1,18 @@
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<?define ArpId = {DE9F8594-5856-4454-AB10-3C01ED246D7D}?>
4<?define ArpKeyPath = HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(var.ArpId)?>
5<?define ArpVersion = 1.0.0.0?>
6
7<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
8 <Fragment>
9 <PackageGroup Id="BundlePackages">
10 <ExePackage Id="TestExe" PerMachine="no"
11 InstallArguments="/regw &quot;$(var.ArpKeyPath),DisplayVersion,String,$(var.ArpVersion)&quot;">
12 <ArpEntry Id="$(var.ArpId)" Version="$(var.ArpVersion)" Win64="no" />
13
14 <PayloadGroupRef Id="TestExePayloads" />
15 </ExePackage>
16 </PackageGroup>
17 </Fragment>
18</Wix>
diff --git a/src/test/burn/TestData/ExePackageTests/PackageFail/PackageFail.wixproj b/src/test/burn/TestData/ExePackageTests/PackageFail/PackageFail.wixproj
new file mode 100644
index 00000000..19c5463d
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/PackageFail/PackageFail.wixproj
@@ -0,0 +1,12 @@
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<Project Sdk="WixToolset.Sdk">
3 <PropertyGroup>
4 <UpgradeCode>{6C5A2C71-2009-4B52-BC20-C1C6A5C87EA6}</UpgradeCode>
5 </PropertyGroup>
6 <ItemGroup>
7 <Compile Include="..\..\Templates\PackageFail.wxs" Link="PackageFail.wxs" />
8 </ItemGroup>
9 <ItemGroup>
10 <PackageReference Include="WixToolset.Util.wixext" />
11 </ItemGroup>
12</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wixproj b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wixproj
new file mode 100644
index 00000000..ed46e6a5
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wixproj
@@ -0,0 +1,19 @@
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<Project Sdk="WixToolset.Sdk">
3 <PropertyGroup>
4 <OutputType>Bundle</OutputType>
5 <InstallerPlatform>x64</InstallerPlatform>
6 <BA>TestBA_x64</BA>
7 <UpgradeCode>{5923A558-091E-4015-A9CC-BA92E7A2405A}</UpgradeCode>
8 </PropertyGroup>
9 <ItemGroup>
10 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
11 </ItemGroup>
12 <ItemGroup>
13 <ProjectReference Include="..\..\TestBA\TestBAWixlib_x64\testbawixlib_x64.wixproj" />
14 </ItemGroup>
15 <ItemGroup>
16 <PackageReference Include="WixToolset.Bal.wixext" />
17 <PackageReference Include="WixToolset.NetFx.wixext" />
18 </ItemGroup>
19</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wxs b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wxs
new file mode 100644
index 00000000..a966283f
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackage/PerMachineArpEntryExePackage.wxs
@@ -0,0 +1,18 @@
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<?define ArpId = {4D9EC36A-1E63-4244-875C-3ECB0A2CAE30}?>
4<?define ArpKeyPath = HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(var.ArpId)?>
5<?define ArpVersion = 1.0.0.0?>
6
7<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
8 <Fragment>
9 <PackageGroup Id="BundlePackages">
10 <ExePackage Id="TestExe" PerMachine="yes"
11 InstallArguments="/regw &quot;$(var.ArpKeyPath),DisplayVersion,String,$(var.ArpVersion)&quot; /regw &quot;$(var.ArpKeyPath),QuietUninstallString,String,\&quot;[WixBundleExecutePackageCacheFolder]testexe.exe\&quot; /regd \&quot;$(var.ArpKeyPath)\&quot;&quot;">
12 <ArpEntry Id="$(var.ArpId)" Version="$(var.ArpVersion)" Win64="yes" />
13
14 <PayloadGroupRef Id="TestExePayloads_x64" />
15 </ExePackage>
16 </PackageGroup>
17 </Fragment>
18</Wix>
diff --git a/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wixproj b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wixproj
new file mode 100644
index 00000000..e4219565
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wixproj
@@ -0,0 +1,18 @@
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<Project Sdk="WixToolset.Sdk">
3 <PropertyGroup>
4 <OutputType>Bundle</OutputType>
5 <UpgradeCode>{6436F747-08F7-416F-BE92-DB48F282AFC1}</UpgradeCode>
6 </PropertyGroup>
7 <ItemGroup>
8 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
9 </ItemGroup>
10 <ItemGroup>
11 <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
12 <ProjectReference Include="..\PackageFail\PackageFail.wixproj" />
13 </ItemGroup>
14 <ItemGroup>
15 <PackageReference Include="WixToolset.Bal.wixext" />
16 <PackageReference Include="WixToolset.NetFx.wixext" />
17 </ItemGroup>
18</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wxs b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wxs
new file mode 100644
index 00000000..945146f0
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageFailure/PerMachineArpEntryExePackageFailure.wxs
@@ -0,0 +1,19 @@
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<?define ArpId = {80E90929-EEA5-48A7-A680-A0237A1CAD84}?>
4<?define ArpKeyPath = HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(var.ArpId)?>
5<?define ArpVersion = 1.0.0.0?>
6
7<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
8 <Fragment>
9 <PackageGroup Id="BundlePackages">
10 <ExePackage Id="TestExe" PerMachine="yes"
11 InstallArguments="/regw &quot;$(var.ArpKeyPath),DisplayVersion,String,$(var.ArpVersion)&quot; /regw &quot;$(var.ArpKeyPath),QuietUninstallString,String,\&quot;[WixBundleExecutePackageCacheFolder]testexe.exe\&quot; /regd \&quot;$(var.ArpKeyPath)\&quot;&quot;">
12 <ArpEntry Id="$(var.ArpId)" Version="$(var.ArpVersion)" Win64="no" />
13
14 <PayloadGroupRef Id="TestExePayloads" />
15 </ExePackage>
16 <MsiPackage Id="PackageFail" SourceFile="$(var.PackageFail.TargetPath)" />
17 </PackageGroup>
18 </Fragment>
19</Wix>
diff --git a/src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wixproj b/src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wixproj
new file mode 100644
index 00000000..06395843
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wixproj
@@ -0,0 +1,17 @@
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<Project Sdk="WixToolset.Sdk">
3 <PropertyGroup>
4 <OutputType>Bundle</OutputType>
5 <UpgradeCode>{E4683E88-AF03-40D0-B308-5C084B0E1FA0}</UpgradeCode>
6 </PropertyGroup>
7 <ItemGroup>
8 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
9 </ItemGroup>
10 <ItemGroup>
11 <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
12 </ItemGroup>
13 <ItemGroup>
14 <PackageReference Include="WixToolset.Bal.wixext" />
15 <PackageReference Include="WixToolset.NetFx.wixext" />
16 </ItemGroup>
17</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wxs b/src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wxs
new file mode 100644
index 00000000..e2792693
--- /dev/null
+++ b/src/test/burn/TestData/ExePackageTests/PerUserArpEntryExePackage/PerUserArpEntryExePackage.wxs
@@ -0,0 +1,18 @@
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<?define ArpId = {9B5300C7-9B34-4670-9614-185B02AB87EF}?>
4<?define ArpKeyPath = HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(var.ArpId)?>
5<?define ArpVersion = 1.0.0.0?>
6
7<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
8 <Fragment>
9 <PackageGroup Id="BundlePackages">
10 <ExePackage Id="TestExe" PerMachine="no"
11 InstallArguments="/regw &quot;$(var.ArpKeyPath),DisplayVersion,String,$(var.ArpVersion)&quot; /regw &quot;$(var.ArpKeyPath),QuietUninstallString,String,\&quot;[WixBundleExecutePackageCacheFolder]testexe.exe\&quot; /regd \&quot;$(var.ArpKeyPath)\&quot;&quot;">
12 <ArpEntry Id="$(var.ArpId)" Version="$(var.ArpVersion)" Win64="no" />
13
14 <PayloadGroupRef Id="TestExePayloads" />
15 </ExePackage>
16 </PackageGroup>
17 </Fragment>
18</Wix>
diff --git a/src/test/burn/WixTestTools/ArpEntryInstaller.cs b/src/test/burn/WixTestTools/ArpEntryInstaller.cs
new file mode 100644
index 00000000..96d9fab9
--- /dev/null
+++ b/src/test/burn/WixTestTools/ArpEntryInstaller.cs
@@ -0,0 +1,43 @@
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 WixTestTools
4{
5 using System;
6 using Xunit;
7
8 public partial class ArpEntryInstaller : IDisposable
9 {
10 public ArpEntryInstaller(WixTestContext testContext, string id, bool perMachine = true, bool x64 = false)
11 {
12 this.ArpId = id;
13 this.PerMachine = perMachine;
14 this.X64 = x64;
15 this.TestContext = testContext;
16 }
17
18 public string ArpId { get; }
19
20 public bool PerMachine { get; }
21
22 public bool X64 { get; }
23
24 private WixTestContext TestContext { get; }
25
26 public void Unregister(bool assertIfMissing = true)
27 {
28 if (this.TryGetRegistration(out var registration))
29 {
30 registration.Delete();
31 }
32 else
33 {
34 Assert.True(false, "Tried to unregister when not registered.");
35 }
36 }
37
38 public void Dispose()
39 {
40 this.Unregister(false);
41 }
42 }
43}
diff --git a/src/test/burn/WixTestTools/ArpEntryVerifier.cs b/src/test/burn/WixTestTools/ArpEntryVerifier.cs
new file mode 100644
index 00000000..b3c70337
--- /dev/null
+++ b/src/test/burn/WixTestTools/ArpEntryVerifier.cs
@@ -0,0 +1,24 @@
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 WixTestTools
4{
5 using Xunit;
6
7 public partial class ArpEntryInstaller
8 {
9 public bool TryGetRegistration(out GenericArpRegistration registration)
10 {
11 bool success = !this.PerMachine ? GenericArpRegistration.TryGetPerUserRegistrationById(this.ArpId, out registration)
12 : GenericArpRegistration.TryGetPerMachineRegistrationById(this.ArpId, this.X64, out registration);
13
14 return success;
15 }
16
17 public void VerifyRegistered(bool registered)
18 {
19 bool success = this.TryGetRegistration(out _);
20
21 Assert.Equal(registered, success);
22 }
23 }
24}
diff --git a/src/test/burn/WixTestTools/BundleRegistration.cs b/src/test/burn/WixTestTools/BundleRegistration.cs
index 3541e7ea..524d4616 100644
--- a/src/test/burn/WixTestTools/BundleRegistration.cs
+++ b/src/test/burn/WixTestTools/BundleRegistration.cs
@@ -5,108 +5,51 @@ namespace WixTestTools
5 using System; 5 using System;
6 using Microsoft.Win32; 6 using Microsoft.Win32;
7 7
8 public class BundleRegistration 8 public class BundleRegistration : GenericArpRegistration
9 { 9 {
10 public const string BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
11 public const string BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY_WOW6432NODE = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
12 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH = "BundleCachePath";
13 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE = "BundleAddonCode"; 10 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE = "BundleAddonCode";
11 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH = "BundleCachePath";
14 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE = "BundleDetectCode"; 12 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE = "BundleDetectCode";
15 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE = "BundlePatchCode"; 13 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE = "BundlePatchCode";
14 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY = "BundleProviderKey";
15 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_RESUME_COMMAND_LINE = "BundleResumeCommandLine";
16 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_TAG = "BundleTag";
16 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE = "BundleUpgradeCode"; 17 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE = "BundleUpgradeCode";
17 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME = "DisplayName";
18 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION = "BundleVersion"; 18 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION = "BundleVersion";
19 public const string BURN_REGISTRATION_REGISTRY_ENGINE_VERSION = "EngineVersion"; 19 public const string BURN_REGISTRATION_REGISTRY_ENGINE_VERSION = "EngineVersion";
20 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY = "BundleProviderKey";
21 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_TAG = "BundleTag";
22 public const string REGISTRY_REBOOT_PENDING_FORMAT = "{0}.RebootRequired";
23 public const string REGISTRY_BUNDLE_INSTALLED = "Installed";
24 public const string REGISTRY_BUNDLE_DISPLAY_ICON = "DisplayIcon";
25 public const string REGISTRY_BUNDLE_DISPLAY_VERSION = "DisplayVersion";
26 public const string REGISTRY_BUNDLE_ESTIMATED_SIZE = "EstimatedSize";
27 public const string REGISTRY_BUNDLE_PUBLISHER = "Publisher";
28 public const string REGISTRY_BUNDLE_HELP_LINK = "HelpLink";
29 public const string REGISTRY_BUNDLE_HELP_TELEPHONE = "HelpTelephone";
30 public const string REGISTRY_BUNDLE_URL_INFO_ABOUT = "URLInfoAbout";
31 public const string REGISTRY_BUNDLE_URL_UPDATE_INFO = "URLUpdateInfo";
32 public const string REGISTRY_BUNDLE_PARENT_DISPLAY_NAME = "ParentDisplayName";
33 public const string REGISTRY_BUNDLE_PARENT_KEY_NAME = "ParentKeyName";
34 public const string REGISTRY_BUNDLE_COMMENTS = "Comments";
35 public const string REGISTRY_BUNDLE_CONTACT = "Contact";
36 public const string REGISTRY_BUNDLE_NO_MODIFY = "NoModify";
37 public const string REGISTRY_BUNDLE_MODIFY_PATH = "ModifyPath";
38 public const string REGISTRY_BUNDLE_NO_ELEVATE_ON_MODIFY = "NoElevateOnModify";
39 public const string REGISTRY_BUNDLE_NO_REMOVE = "NoRemove";
40 public const string REGISTRY_BUNDLE_SYSTEM_COMPONENT = "SystemComponent";
41 public const string REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING = "QuietUninstallString";
42 public const string REGISTRY_BUNDLE_UNINSTALL_STRING = "UninstallString";
43 public const string REGISTRY_BUNDLE_RESUME_COMMAND_LINE = "BundleResumeCommandLine";
44 public const string REGISTRY_BUNDLE_VERSION_MAJOR = "VersionMajor";
45 public const string REGISTRY_BUNDLE_VERSION_MINOR = "VersionMinor";
46 20
47 public string[] AddonCodes { get; set; } 21 public string[] AddonCodes { get; set; }
48 22
49 public string CachePath { get; set; } 23 public string BundleVersion { get; set; }
50 24
51 public string DisplayName { get; set; } 25 public string CachePath { get; set; }
52 26
53 public string[] DetectCodes { get; set; } 27 public string[] DetectCodes { get; set; }
54 28
55 public string EngineVersion { get; set; } 29 public string EngineVersion { get; set; }
56 30
57 public int? EstimatedSize { get; set; }
58
59 public int? Installed { get; set; }
60
61 public string ModifyPath { get; set; }
62
63 public string[] PatchCodes { get; set; } 31 public string[] PatchCodes { get; set; }
64 32
65 public string ProviderKey { get; set; } 33 public string ProviderKey { get; set; }
66 34
67 public string Publisher { get; set; }
68
69 public int? SystemComponent { get; set; }
70
71 public string QuietUninstallString { get; set; }
72
73 public string QuietUninstallCommand { get; set; }
74
75 public string QuietUninstallCommandArguments { get; set; }
76
77 public string Tag { get; set; } 35 public string Tag { get; set; }
78 36
79 public string UninstallCommand { get; set; }
80
81 public string UninstallCommandArguments { get; set; }
82
83 public string UninstallString { get; set; }
84
85 public string[] UpgradeCodes { get; set; } 37 public string[] UpgradeCodes { get; set; }
86 38
87 public string UrlInfoAbout { get; set; } 39 public static bool TryGetPerMachineBundleRegistrationById(string id, bool x64, out BundleRegistration registration)
88 40 {
89 public string UrlUpdateInfo { get; set; } 41 return TryGetRegistrationById(id, x64, false, out registration);
90 42 }
91 public string Version { get; set; }
92 43
93 public static bool TryGetPerMachineBundleRegistrationById(string bundleId, bool x64, out BundleRegistration registration) 44 public static bool TryGetPerUserBundleRegistrationById(string id, out BundleRegistration registration)
94 { 45 {
95 var baseKeyPath = x64 ? BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY : BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY_WOW6432NODE; 46 return TryGetRegistrationById(id, true, true, out registration);
96 var registrationKeyPath = $"{baseKeyPath}\\{bundleId}";
97 using var registrationKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
98 var success = registrationKey != null;
99 registration = success ? GetBundleRegistration(registrationKey) : null;
100 return success;
101 } 47 }
102 48
103 public static bool TryGetPerUserBundleRegistrationById(string bundleId, out BundleRegistration registration) 49 private static bool TryGetRegistrationById(string id, bool x64, bool perUser, out BundleRegistration registration)
104 { 50 {
105 var registrationKeyPath = $"{BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY}\\{bundleId}"; 51 registration = GetGenericArpRegistration(id, x64, perUser, key => GetBundleRegistration(key));
106 using var registrationKey = Registry.CurrentUser.OpenSubKey(registrationKeyPath); 52 return registration != null;
107 var success = registrationKey != null;
108 registration = success ? GetBundleRegistration(registrationKey) : null;
109 return success;
110 } 53 }
111 54
112 private static BundleRegistration GetBundleRegistration(RegistryKey idKey) 55 private static BundleRegistration GetBundleRegistration(RegistryKey idKey)
@@ -120,38 +63,8 @@ namespace WixTestTools
120 registration.ProviderKey = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY) as string; 63 registration.ProviderKey = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY) as string;
121 registration.Tag = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_TAG) as string; 64 registration.Tag = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_TAG) as string;
122 registration.UpgradeCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE) as string[]; 65 registration.UpgradeCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE) as string[];
123 registration.Version = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION) as string; 66 registration.BundleVersion = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION) as string;
124 registration.DisplayName = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME) as string;
125 registration.EngineVersion = idKey.GetValue(BURN_REGISTRATION_REGISTRY_ENGINE_VERSION) as string; 67 registration.EngineVersion = idKey.GetValue(BURN_REGISTRATION_REGISTRY_ENGINE_VERSION) as string;
126 registration.EstimatedSize = idKey.GetValue(REGISTRY_BUNDLE_ESTIMATED_SIZE) as int?;
127 registration.Installed = idKey.GetValue(REGISTRY_BUNDLE_INSTALLED) as int?;
128 registration.ModifyPath = idKey.GetValue(REGISTRY_BUNDLE_MODIFY_PATH) as string;
129 registration.Publisher = idKey.GetValue(REGISTRY_BUNDLE_PUBLISHER) as string;
130 registration.SystemComponent = idKey.GetValue(REGISTRY_BUNDLE_SYSTEM_COMPONENT) as int?;
131 registration.UrlInfoAbout = idKey.GetValue(REGISTRY_BUNDLE_URL_INFO_ABOUT) as string;
132 registration.UrlUpdateInfo = idKey.GetValue(REGISTRY_BUNDLE_URL_UPDATE_INFO) as string;
133
134 registration.QuietUninstallString = idKey.GetValue(REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING) as string;
135 if (!String.IsNullOrEmpty(registration.QuietUninstallString))
136 {
137 var closeQuote = registration.QuietUninstallString.IndexOf("\"", 1);
138 if (closeQuote > 0)
139 {
140 registration.QuietUninstallCommand = registration.QuietUninstallString.Substring(1, closeQuote - 1).Trim();
141 registration.QuietUninstallCommandArguments = registration.QuietUninstallString.Substring(closeQuote + 1).Trim();
142 }
143 }
144
145 registration.UninstallString = idKey.GetValue(REGISTRY_BUNDLE_UNINSTALL_STRING) as string;
146 if (!String.IsNullOrEmpty(registration.UninstallString))
147 {
148 var closeQuote = registration.UninstallString.IndexOf("\"", 1);
149 if (closeQuote > 0)
150 {
151 registration.UninstallCommand = registration.UninstallString.Substring(1, closeQuote - 1).Trim();
152 registration.UninstallCommandArguments = registration.UninstallString.Substring(closeQuote + 1).Trim();
153 }
154 }
155 68
156 return registration; 69 return registration;
157 } 70 }
diff --git a/src/test/burn/WixTestTools/BundleVerifier.cs b/src/test/burn/WixTestTools/BundleVerifier.cs
index 103171cd..ff45a291 100644
--- a/src/test/burn/WixTestTools/BundleVerifier.cs
+++ b/src/test/burn/WixTestTools/BundleVerifier.cs
@@ -80,6 +80,29 @@ namespace WixTestTools
80 File.Delete(expectedCachePath); 80 File.Delete(expectedCachePath);
81 } 81 }
82 82
83 public bool TryGetArpEntryExePackageConfiguration(string packageId, out string arpId, out string arpVersion, out bool arpWin64, out bool perMachine)
84 {
85 using var wixOutput = WixOutput.Read(this.BundlePdb);
86 var intermediate = Intermediate.Load(wixOutput);
87 var section = intermediate.Sections.Single();
88 var packageSymbol = section.Symbols.OfType<WixBundlePackageSymbol>().SingleOrDefault(p => p.Id.Id == packageId);
89 var exePackageSymbol = section.Symbols.OfType<WixBundleExePackageSymbol>().SingleOrDefault(p => p.Id.Id == packageId);
90 if (packageSymbol == null || exePackageSymbol == null || exePackageSymbol.DetectionType != WixBundleExePackageDetectionType.Arp)
91 {
92 arpId = null;
93 arpVersion = null;
94 arpWin64 = false;
95 perMachine = false;
96 return false;
97 }
98
99 arpId = exePackageSymbol.ArpId;
100 arpVersion = exePackageSymbol.ArpDisplayVersion;
101 arpWin64 = exePackageSymbol.ArpWin64;
102 perMachine = packageSymbol.PerMachine == true;
103 return true;
104 }
105
83 public bool TryGetRegistration(out BundleRegistration registration) 106 public bool TryGetRegistration(out BundleRegistration registration)
84 { 107 {
85 var bundleSymbol = this.GetBundleSymbol(); 108 var bundleSymbol = this.GetBundleSymbol();
diff --git a/src/test/burn/WixTestTools/GenericArpRegistration.cs b/src/test/burn/WixTestTools/GenericArpRegistration.cs
new file mode 100644
index 00000000..d87c4feb
--- /dev/null
+++ b/src/test/burn/WixTestTools/GenericArpRegistration.cs
@@ -0,0 +1,143 @@
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 WixTestTools
4{
5 using System;
6 using Microsoft.Win32;
7
8 public class GenericArpRegistration
9 {
10 public const string UNINSTALL_KEY = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
11 public const string UNINSTALL_KEY_WOW6432NODE = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
12
13 public const string REGISTRY_ARP_INSTALLED = "Installed";
14 public const string REGISTRY_ARP_DISPLAY_ICON = "DisplayIcon";
15 public const string REGISTRY_ARP_DISPLAY_NAME = "DisplayName";
16 public const string REGISTRY_ARP_DISPLAY_VERSION = "DisplayVersion";
17 public const string REGISTRY_ARP_ESTIMATED_SIZE = "EstimatedSize";
18 public const string REGISTRY_ARP_PUBLISHER = "Publisher";
19 public const string REGISTRY_ARP_HELP_LINK = "HelpLink";
20 public const string REGISTRY_ARP_HELP_TELEPHONE = "HelpTelephone";
21 public const string REGISTRY_ARP_URL_INFO_ABOUT = "URLInfoAbout";
22 public const string REGISTRY_ARP_URL_UPDATE_INFO = "URLUpdateInfo";
23 public const string REGISTRY_ARP_COMMENTS = "Comments";
24 public const string REGISTRY_ARP_CONTACT = "Contact";
25 public const string REGISTRY_ARP_NO_MODIFY = "NoModify";
26 public const string REGISTRY_ARP_MODIFY_PATH = "ModifyPath";
27 public const string REGISTRY_ARP_NO_ELEVATE_ON_MODIFY = "NoElevateOnModify";
28 public const string REGISTRY_ARP_NO_REMOVE = "NoRemove";
29 public const string REGISTRY_ARP_SYSTEM_COMPONENT = "SystemComponent";
30 public const string REGISTRY_ARP_QUIET_UNINSTALL_STRING = "QuietUninstallString";
31 public const string REGISTRY_ARP_UNINSTALL_STRING = "UninstallString";
32 public const string REGISTRY_ARP_VERSION_MAJOR = "VersionMajor";
33 public const string REGISTRY_ARP_VERSION_MINOR = "VersionMinor";
34
35 public RegistryKey BaseKey { get; set; }
36
37 public string KeyPath { get; set; }
38
39 public string DisplayName { get; set; }
40
41 public string DisplayVersion { get; set; }
42
43 public int? EstimatedSize { get; set; }
44
45 public int? Installed { get; set; }
46
47 public string ModifyPath { get; set; }
48
49 public string Publisher { get; set; }
50
51 public int? SystemComponent { get; set; }
52
53 public string QuietUninstallString { get; set; }
54
55 public string QuietUninstallCommand { get; set; }
56
57 public string QuietUninstallCommandArguments { get; set; }
58
59 public string UninstallCommand { get; set; }
60
61 public string UninstallCommandArguments { get; set; }
62
63 public string UninstallString { get; set; }
64
65 public string UrlInfoAbout { get; set; }
66
67 public string UrlUpdateInfo { get; set; }
68
69 public static bool TryGetPerMachineRegistrationById(string id, bool x64, out GenericArpRegistration registration)
70 {
71 return TryGetRegistrationById(id, x64, false, out registration);
72 }
73
74 public static bool TryGetPerUserRegistrationById(string id, out GenericArpRegistration registration)
75 {
76 return TryGetRegistrationById(id, true, true, out registration);
77 }
78
79 private static bool TryGetRegistrationById(string id, bool x64, bool perUser, out GenericArpRegistration registration)
80 {
81 registration = GetGenericArpRegistration(id, x64, perUser, key => new GenericArpRegistration());
82 return registration != null;
83 }
84
85 protected static T GetGenericArpRegistration<T>(string id, bool x64, bool perUser, Func<RegistryKey, T> fnCreate)
86 where T : GenericArpRegistration
87 {
88 var baseKey = perUser ? Registry.CurrentUser : Registry.LocalMachine;
89 var baseKeyPath = x64 ? UNINSTALL_KEY : UNINSTALL_KEY_WOW6432NODE;
90 var registrationKeyPath = $"{baseKeyPath}\\{id}";
91 using var idKey = baseKey.OpenSubKey(registrationKeyPath);
92
93 if (idKey == null)
94 {
95 return null;
96 }
97
98 var registration = fnCreate(idKey);
99
100 registration.BaseKey = baseKey;
101 registration.KeyPath = registrationKeyPath;
102
103 registration.DisplayName = idKey.GetValue(REGISTRY_ARP_DISPLAY_NAME) as string;
104 registration.DisplayVersion = idKey.GetValue(REGISTRY_ARP_DISPLAY_VERSION) as string;
105 registration.EstimatedSize = idKey.GetValue(REGISTRY_ARP_ESTIMATED_SIZE) as int?;
106 registration.Installed = idKey.GetValue(REGISTRY_ARP_INSTALLED) as int?;
107 registration.ModifyPath = idKey.GetValue(REGISTRY_ARP_MODIFY_PATH) as string;
108 registration.Publisher = idKey.GetValue(REGISTRY_ARP_PUBLISHER) as string;
109 registration.SystemComponent = idKey.GetValue(REGISTRY_ARP_SYSTEM_COMPONENT) as int?;
110 registration.UrlInfoAbout = idKey.GetValue(REGISTRY_ARP_URL_INFO_ABOUT) as string;
111 registration.UrlUpdateInfo = idKey.GetValue(REGISTRY_ARP_URL_UPDATE_INFO) as string;
112
113 registration.QuietUninstallString = idKey.GetValue(REGISTRY_ARP_QUIET_UNINSTALL_STRING) as string;
114 if (!String.IsNullOrEmpty(registration.QuietUninstallString))
115 {
116 var closeQuote = registration.QuietUninstallString.IndexOf("\"", 1);
117 if (closeQuote > 0)
118 {
119 registration.QuietUninstallCommand = registration.QuietUninstallString.Substring(1, closeQuote - 1).Trim();
120 registration.QuietUninstallCommandArguments = registration.QuietUninstallString.Substring(closeQuote + 1).Trim();
121 }
122 }
123
124 registration.UninstallString = idKey.GetValue(REGISTRY_ARP_UNINSTALL_STRING) as string;
125 if (!String.IsNullOrEmpty(registration.UninstallString))
126 {
127 var closeQuote = registration.UninstallString.IndexOf("\"", 1);
128 if (closeQuote > 0)
129 {
130 registration.UninstallCommand = registration.UninstallString.Substring(1, closeQuote - 1).Trim();
131 registration.UninstallCommandArguments = registration.UninstallString.Substring(closeQuote + 1).Trim();
132 }
133 }
134
135 return registration;
136 }
137
138 public void Delete()
139 {
140 this.BaseKey.DeleteSubKeyTree(this.KeyPath);
141 }
142 }
143}
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs b/src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs
index 6664b849..5caedacb 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs
@@ -31,6 +31,23 @@ namespace WixToolsetTest.BurnE2E
31 this.Installers.Push(installer); 31 this.Installers.Push(installer);
32 } 32 }
33 33
34 protected ArpEntryInstaller CreateArpEntryInstaller(string id, bool perMachine = true, bool x64 = false)
35 {
36 var installer = new ArpEntryInstaller(this.TestContext, id, perMachine, x64);
37 this.Installers.Push(installer);
38 return installer;
39 }
40
41 protected ArpEntryInstaller CreateArpEntryInstaller(BundleInstaller bundleInstaller, string packageId)
42 {
43 if (!bundleInstaller.TryGetArpEntryExePackageConfiguration(packageId, out var arpId, out _, out var arpWin64, out var perMachine))
44 {
45 return null;
46 }
47
48 return this.CreateArpEntryInstaller(arpId, perMachine, arpWin64);
49 }
50
34 protected BundleInstaller CreateBundleInstaller(string name) 51 protected BundleInstaller CreateBundleInstaller(string name)
35 { 52 {
36 var installer = new BundleInstaller(this.TestContext, name); 53 var installer = new BundleInstaller(this.TestContext, name);
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs
index f5a1cda8..e5e3259f 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs
@@ -33,12 +33,12 @@ namespace WixToolsetTest.BurnE2E
33 33
34 if (!File.Exists(targetFilePath)) 34 if (!File.Exists(targetFilePath))
35 { 35 {
36 var testTool = new TestTool(Path.Combine(TestData.Get(), "win-x86", "TestExe.exe")) 36 var testExeTool = new TestExeTool
37 { 37 {
38 Arguments = "/lf \"" + targetFilePath + $"|{FiveGB}\"", 38 Arguments = "/lf \"" + targetFilePath + $"|{FiveGB}\"",
39 ExpectedExitCode = 0, 39 ExpectedExitCode = 0,
40 }; 40 };
41 testTool.Run(true); 41 testExeTool.Run(true);
42 } 42 }
43 } 43 }
44 44
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs
new file mode 100644
index 00000000..dc6515b5
--- /dev/null
+++ b/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs
@@ -0,0 +1,99 @@
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 WixToolsetTest.BurnE2E
4{
5 using WixTestTools;
6 using Xunit;
7 using Xunit.Abstractions;
8
9 public class ExePackageTests : BurnE2ETests
10 {
11 public ExePackageTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
12
13 [RuntimeFact]
14 public void CanInstallAndUninstallPerMachineArpEntryExePackage()
15 {
16 const string arpId = "{4D9EC36A-1E63-4244-875C-3ECB0A2CAE30}";
17 var perMachineArpEntryExePackageBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackage");
18 var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageBundle, "TestExe");
19
20 arpEntryExePackage.VerifyRegistered(false);
21
22 var installLogPath = perMachineArpEntryExePackageBundle.Install();
23 perMachineArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
24 arpEntryExePackage.VerifyRegistered(true);
25
26 LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"");
27
28 var uninstallLogPath = perMachineArpEntryExePackageBundle.Uninstall();
29 perMachineArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
30 arpEntryExePackage.VerifyRegistered(false);
31
32 LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}");
33 }
34
35 [RuntimeFact]
36 public void CanUninstallPerMachineArpEntryExePackageOnRollback()
37 {
38 const string arpId = "{80E90929-EEA5-48A7-A680-A0237A1CAD84}";
39 var perMachineArpEntryExePackageFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageFailure");
40 var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageFailureBundle, "TestExe");
41
42 arpEntryExePackage.VerifyRegistered(false);
43
44 var installLogPath = perMachineArpEntryExePackageFailureBundle.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE);
45 perMachineArpEntryExePackageFailureBundle.VerifyUnregisteredAndRemovedFromPackageCache();
46 arpEntryExePackage.VerifyRegistered(false);
47
48 LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"");
49 LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}");
50 }
51
52 [RuntimeFact]
53 public void CanInstallAndUninstallPerUserArpEntryExePackage()
54 {
55 const string arpId = "{9B5300C7-9B34-4670-9614-185B02AB87EF}";
56 var perUserArpEntryExePackageBundle = this.CreateBundleInstaller(@"PerUserArpEntryExePackage");
57 var arpEntryExePackage = this.CreateArpEntryInstaller(perUserArpEntryExePackageBundle, "TestExe");
58
59 arpEntryExePackage.VerifyRegistered(false);
60
61 var installLogPath = perUserArpEntryExePackageBundle.Install();
62 perUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
63 arpEntryExePackage.VerifyRegistered(true);
64
65 LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"");
66
67 var uninstallLogPath = perUserArpEntryExePackageBundle.Uninstall();
68 perUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
69 arpEntryExePackage.VerifyRegistered(false);
70
71 LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}");
72 }
73
74 [RuntimeFact]
75 public void FailsUninstallWhenPerUserArpEntryExePackageMissingQuietUninstallString()
76 {
77 const string arpId = "{DE9F8594-5856-4454-AB10-3C01ED246D7D}";
78 var brokenPerUserArpEntryExePackageBundle = this.CreateBundleInstaller(@"BrokenPerUserArpEntryExePackage");
79 var arpEntryExePackage = this.CreateArpEntryInstaller(brokenPerUserArpEntryExePackageBundle, "TestExe");
80
81 arpEntryExePackage.VerifyRegistered(false);
82 brokenPerUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
83
84 var installLogPath = brokenPerUserArpEntryExePackageBundle.Install();
85 brokenPerUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
86 arpEntryExePackage.VerifyRegistered(true);
87
88 LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\"");
89
90 brokenPerUserArpEntryExePackageBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INVALID_PARAMETER);
91 brokenPerUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
92
93 arpEntryExePackage.Unregister();
94
95 brokenPerUserArpEntryExePackageBundle.Uninstall();
96 brokenPerUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
97 }
98 }
99}
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/IWebServer.cs
index a4d46d48..a4d46d48 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/IWebServer.cs
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs
index 8e6611a2..8e6611a2 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestExeTool.cs b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestExeTool.cs
new file mode 100644
index 00000000..a02299d7
--- /dev/null
+++ b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestExeTool.cs
@@ -0,0 +1,17 @@
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 WixTestTools
4{
5 using System.IO;
6 using WixBuildTools.TestSupport;
7
8 public class TestExeTool : TestTool
9 {
10 private static readonly string TestExePath32 = Path.Combine(TestData.Get(), "win-x86", "TestExe.exe");
11
12 public TestExeTool()
13 : base(TestExePath32)
14 {
15 }
16 }
17}
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
index 78e02534..25a155d6 100644
--- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
@@ -411,13 +411,37 @@ namespace WixToolset.Core.Burn.Bundles
411 } 411 }
412 else if (package.SpecificPackageSymbol is WixBundleExePackageSymbol exePackage) // EXE 412 else if (package.SpecificPackageSymbol is WixBundleExePackageSymbol exePackage) // EXE
413 { 413 {
414 writer.WriteAttributeString("DetectCondition", exePackage.DetectCondition);
415 writer.WriteAttributeString("InstallArguments", exePackage.InstallCommand); 414 writer.WriteAttributeString("InstallArguments", exePackage.InstallCommand);
416 writer.WriteAttributeString("UninstallArguments", exePackage.UninstallCommand);
417 writer.WriteAttributeString("Uninstallable", exePackage.Uninstallable ? "yes" : "no");
418 writer.WriteAttributeString("RepairArguments", exePackage.RepairCommand); 415 writer.WriteAttributeString("RepairArguments", exePackage.RepairCommand);
419 writer.WriteAttributeString("Repairable", exePackage.Repairable ? "yes" : "no"); 416 writer.WriteAttributeString("Repairable", exePackage.Repairable ? "yes" : "no");
420 417
418 switch (exePackage.DetectionType)
419 {
420 case WixBundleExePackageDetectionType.Condition:
421 writer.WriteAttributeString("DetectionType", "condition");
422 writer.WriteAttributeString("DetectCondition", exePackage.DetectCondition);
423
424 if (exePackage.Uninstallable)
425 {
426 writer.WriteAttributeString("UninstallArguments", exePackage.UninstallCommand);
427 writer.WriteAttributeString("Uninstallable", "yes");
428 }
429 break;
430 case WixBundleExePackageDetectionType.Arp:
431 writer.WriteAttributeString("DetectionType", "arp");
432 writer.WriteAttributeString("ArpId", exePackage.ArpId);
433 writer.WriteAttributeString("ArpDisplayVersion", exePackage.ArpDisplayVersion);
434
435 if (exePackage.ArpWin64)
436 {
437 writer.WriteAttributeString("ArpWin64", "yes");
438 }
439 break;
440 case WixBundleExePackageDetectionType.None:
441 writer.WriteAttributeString("DetectionType", "none");
442 break;
443 }
444
421 if (!String.IsNullOrEmpty(exePackage.ExeProtocol)) 445 if (!String.IsNullOrEmpty(exePackage.ExeProtocol))
422 { 446 {
423 writer.WriteAttributeString("Protocol", exePackage.ExeProtocol); 447 writer.WriteAttributeString("Protocol", exePackage.ExeProtocol);
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs
index 5d9acb4a..cc3c22db 100644
--- a/src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs
@@ -109,7 +109,17 @@ namespace WixToolset.Core.Burn.Bundles
109 109
110 if (!packageSymbol.Permanent) 110 if (!packageSymbol.Permanent)
111 { 111 {
112 this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "ExePackage", "DetectCondition", symbol.DetectCondition, BundleConditionPhase.Detect); 112 if (symbol.DetectionType == WixBundleExePackageDetectionType.Condition)
113 {
114 this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "ExePackage", "DetectCondition", symbol.DetectCondition, BundleConditionPhase.Detect);
115 }
116 else if (symbol.DetectionType == WixBundleExePackageDetectionType.Arp)
117 {
118 if (!this.BackendHelper.IsValidWixVersion(symbol.ArpDisplayVersion))
119 {
120 this.Messaging.Write(WarningMessages.InvalidWixVersion(symbol.SourceLineNumbers, symbol.ArpDisplayVersion, "ArpEntry", "Version"));
121 }
122 }
113 } 123 }
114 } 124 }
115 125
diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs
index 36194882..b8f449d6 100644
--- a/src/wix/WixToolset.Core/Compiler_Bundle.cs
+++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs
@@ -2026,6 +2026,10 @@ namespace WixToolset.Core
2026 var bundle = YesNoType.NotSet; 2026 var bundle = YesNoType.NotSet;
2027 var slipstream = YesNoType.NotSet; 2027 var slipstream = YesNoType.NotSet;
2028 var hasPayloadInfo = false; 2028 var hasPayloadInfo = false;
2029 WixBundleExePackageDetectionType? exeDetectionType = WixBundleExePackageDetectionType.None;
2030 string arpId = null;
2031 string arpDisplayVersion = null;
2032 var arpWin64 = YesNoType.NotSet;
2029 2033
2030 var expectedNetFx4Args = new string[] { "/q", "/norestart" }; 2034 var expectedNetFx4Args = new string[] { "/q", "/norestart" };
2031 2035
@@ -2204,6 +2208,112 @@ namespace WixToolset.Core
2204 compilerPayload.FinishCompilingPackage(); 2208 compilerPayload.FinishCompilingPackage();
2205 var id = compilerPayload.Id; 2209 var id = compilerPayload.Id;
2206 2210
2211 // Now that the package ID is known, we can parse the extension attributes...
2212 var contextValues = new Dictionary<string, string>() { { "PackageId", id.Id } };
2213 foreach (var attribute in extensionAttributes)
2214 {
2215 this.Core.ParseExtensionAttribute(node, attribute, contextValues);
2216 }
2217
2218 if (packageType == WixBundlePackageType.Exe && (detectCondition != null || uninstallArguments != null))
2219 {
2220 exeDetectionType = WixBundleExePackageDetectionType.Condition;
2221 }
2222
2223 foreach (var child in node.Elements())
2224 {
2225 if (CompilerCore.WixNamespace == child.Name.Namespace)
2226 {
2227 var allowed = true;
2228 switch (child.Name.LocalName)
2229 {
2230 case "ArpEntry":
2231 allowed = packageType == WixBundlePackageType.Exe;
2232 if (allowed)
2233 {
2234 if (exeDetectionType == WixBundleExePackageDetectionType.Arp)
2235 {
2236 this.Core.Write(ErrorMessages.TooManyChildren(Preprocessor.GetSourceLineNumbers(child), node.Name.LocalName, child.Name.LocalName));
2237 }
2238 else if (!exeDetectionType.HasValue || exeDetectionType.Value == WixBundleExePackageDetectionType.Condition)
2239 {
2240 exeDetectionType = null;
2241 }
2242 else
2243 {
2244 if (exeDetectionType.Value != WixBundleExePackageDetectionType.None)
2245 {
2246 throw new WixException($"Unexpected WixBundleExePackageDetectionType: {exeDetectionType}");
2247 }
2248
2249 exeDetectionType = WixBundleExePackageDetectionType.Arp;
2250 }
2251
2252 this.ParseExePackageArpEntryElement(child, out arpId, out arpDisplayVersion, out arpWin64);
2253 }
2254 break;
2255 case "SlipstreamMsp":
2256 allowed = (packageType == WixBundlePackageType.Msi);
2257 if (allowed)
2258 {
2259 this.ParseSlipstreamMspElement(child, id.Id);
2260 }
2261 break;
2262 case "MsiProperty":
2263 allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp);
2264 if (allowed)
2265 {
2266 this.ParseMsiPropertyElement(child, id.Id);
2267 }
2268 break;
2269 case "Payload":
2270 this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id);
2271 break;
2272 case "PayloadGroupRef":
2273 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id);
2274 break;
2275 case "Provides":
2276 this.ParseProvidesElement(child, packageType, id.Id, out _);
2277 break;
2278 case "ExitCode":
2279 allowed = (packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Exe);
2280 if (allowed)
2281 {
2282 this.ParseExitCodeElement(child, id.Id);
2283 }
2284 break;
2285 case "CommandLine":
2286 allowed = (packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Exe);
2287 if (allowed)
2288 {
2289 this.ParseCommandLineElement(child, id.Id);
2290 }
2291 break;
2292 case "BundlePackagePayload":
2293 case "ExePackagePayload":
2294 case "MsiPackagePayload":
2295 case "MspPackagePayload":
2296 case "MsuPackagePayload":
2297 allowed = packagePayloadElementName == child.Name.LocalName;
2298 // Handled previously
2299 break;
2300 default:
2301 allowed = false;
2302 break;
2303 }
2304
2305 if (!allowed)
2306 {
2307 this.Core.UnexpectedElement(node, child);
2308 }
2309 }
2310 else
2311 {
2312 var context = new Dictionary<string, string>() { { "Id", id.Id } };
2313 this.Core.ParseExtensionElement(node, child, context);
2314 }
2315 }
2316
2207 if (id.Id == BurnConstants.BundleDefaultBoundaryId) 2317 if (id.Id == BurnConstants.BundleDefaultBoundaryId)
2208 { 2318 {
2209 this.Messaging.Write(CompilerErrors.ReservedValue(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); 2319 this.Messaging.Write(CompilerErrors.ReservedValue(sourceLineNumbers, node.Name.LocalName, "Id", id.Id));
@@ -2234,37 +2344,72 @@ namespace WixToolset.Core
2234 perMachine = YesNoDefaultType.Default; 2344 perMachine = YesNoDefaultType.Default;
2235 } 2345 }
2236 2346
2237 if (permanent == YesNoType.No) 2347 if (exeDetectionType == WixBundleExePackageDetectionType.Arp)
2238 { 2348 {
2239 if (uninstallArguments == null) 2349 // Missing attributes are reported when parsing the element.
2240 {
2241 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UninstallArguments", "Permanent", "no"));
2242 }
2243 } 2350 }
2244 else if (permanent == YesNoType.NotSet) 2351 else if (exeDetectionType == WixBundleExePackageDetectionType.Condition)
2245 { 2352 {
2353 if (String.IsNullOrEmpty(detectCondition))
2354 {
2355 if (permanent == YesNoType.No)
2356 {
2357 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "Permanent", "no"));
2358 }
2359 else if (permanent == YesNoType.NotSet)
2360 {
2361 this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "Permanent"));
2362 }
2363 else if (repairArguments != null)
2364 {
2365 this.Core.Write(ErrorMessages.ExpectedAttributeWithValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "RepairArguments"));
2366 }
2367 else if (uninstallArguments != null)
2368 {
2369 this.Core.Write(ErrorMessages.ExpectedAttributeWithValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "UninstallArguments"));
2370 }
2371 else
2372 {
2373 Debug.Assert(detectCondition == String.Empty);
2374 exeDetectionType = WixBundleExePackageDetectionType.None;
2375 }
2376 }
2377
2246 if (uninstallArguments == null) 2378 if (uninstallArguments == null)
2247 { 2379 {
2248 this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "UninstallArguments", "Permanent")); 2380 if (permanent == YesNoType.No)
2381 {
2382 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UninstallArguments", "Permanent", "no"));
2383 }
2384 else if (permanent == YesNoType.NotSet)
2385 {
2386 this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "UninstallArguments", "Permanent"));
2387 }
2249 } 2388 }
2250 } 2389 }
2251 2390 else if (exeDetectionType == WixBundleExePackageDetectionType.None)
2252 // Detect condition is recommended or required for Exe packages (depending on whether repair or uninstall arguments were provided).
2253 if (String.IsNullOrEmpty(detectCondition))
2254 { 2391 {
2255 if (repairArguments != null) 2392 if (permanent == YesNoType.No)
2393 {
2394 this.Core.Write(ErrorMessages.ExpectedAttributeOrElementWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "ArpEntry", "Permanent", "no"));
2395 }
2396 else if (permanent == YesNoType.NotSet)
2256 { 2397 {
2257 this.Core.Write(ErrorMessages.ExpectedAttributeWithValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "RepairArguments")); 2398 this.Core.Write(ErrorMessages.ExpectedAttributeOrElementWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "ArpEntry", "Permanent"));
2258 } 2399 }
2259 else if (uninstallArguments != null) 2400 else if (repairArguments != null)
2260 { 2401 {
2261 this.Core.Write(ErrorMessages.ExpectedAttributeWithValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "UninstallArguments")); 2402 this.Core.Write(ErrorMessages.ExpectedAttributeOrElementWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DetectCondition", "ArpEntry", "RepairArguments"));
2262 } 2403 }
2263 else 2404 else
2264 { 2405 {
2265 this.Core.Write(WarningMessages.DetectConditionRecommended(sourceLineNumbers, node.Name.LocalName)); 2406 this.Core.Write(WarningMessages.ExePackageDetectInformationRecommended(sourceLineNumbers));
2266 } 2407 }
2267 } 2408 }
2409 else
2410 {
2411 this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, "ArpEntry", String.IsNullOrEmpty(detectCondition) ? "UninstallArguments" : "DetectCondition"));
2412 }
2268 2413
2269 if (repairArguments == null && repairCondition != null) 2414 if (repairArguments == null && repairCondition != null)
2270 { 2415 {
@@ -2341,82 +2486,6 @@ namespace WixToolset.Core
2341 } 2486 }
2342 } 2487 }
2343 2488
2344 // Now that the package ID is known, we can parse the extension attributes...
2345 var contextValues = new Dictionary<string, string>() { { "PackageId", id.Id } };
2346 foreach (var attribute in extensionAttributes)
2347 {
2348 this.Core.ParseExtensionAttribute(node, attribute, contextValues);
2349 }
2350
2351 foreach (var child in node.Elements())
2352 {
2353 if (CompilerCore.WixNamespace == child.Name.Namespace)
2354 {
2355 var allowed = true;
2356 switch (child.Name.LocalName)
2357 {
2358 case "SlipstreamMsp":
2359 allowed = (packageType == WixBundlePackageType.Msi);
2360 if (allowed)
2361 {
2362 this.ParseSlipstreamMspElement(child, id.Id);
2363 }
2364 break;
2365 case "MsiProperty":
2366 allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp);
2367 if (allowed)
2368 {
2369 this.ParseMsiPropertyElement(child, id.Id);
2370 }
2371 break;
2372 case "Payload":
2373 this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id);
2374 break;
2375 case "PayloadGroupRef":
2376 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id);
2377 break;
2378 case "Provides":
2379 this.ParseProvidesElement(child, packageType, id.Id, out _);
2380 break;
2381 case "ExitCode":
2382 allowed = (packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Exe);
2383 if (allowed)
2384 {
2385 this.ParseExitCodeElement(child, id.Id);
2386 }
2387 break;
2388 case "CommandLine":
2389 allowed = (packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Exe);
2390 if (allowed)
2391 {
2392 this.ParseCommandLineElement(child, id.Id);
2393 }
2394 break;
2395 case "BundlePackagePayload":
2396 case "ExePackagePayload":
2397 case "MsiPackagePayload":
2398 case "MspPackagePayload":
2399 case "MsuPackagePayload":
2400 allowed = packagePayloadElementName == child.Name.LocalName;
2401 // Handled previously
2402 break;
2403 default:
2404 allowed = false;
2405 break;
2406 }
2407
2408 if (!allowed)
2409 {
2410 this.Core.UnexpectedElement(node, child);
2411 }
2412 }
2413 else
2414 {
2415 var context = new Dictionary<string, string>() { { "Id", id.Id } };
2416 this.Core.ParseExtensionElement(node, child, context);
2417 }
2418 }
2419
2420 if (!this.Core.EncounteredError) 2489 if (!this.Core.EncounteredError)
2421 { 2490 {
2422 var compilerPackagePayload = childCompilerPackagePayload ?? (hasPayloadInfo ? new CompilerPackagePayload(compilerPayload, packageType) : null); 2491 var compilerPackagePayload = childCompilerPackagePayload ?? (hasPayloadInfo ? new CompilerPackagePayload(compilerPayload, packageType) : null);
@@ -2474,6 +2543,7 @@ namespace WixToolset.Core
2474 case WixBundlePackageType.Exe: 2543 case WixBundlePackageType.Exe:
2475 WixBundleExePackageAttributes exeAttributes = 0; 2544 WixBundleExePackageAttributes exeAttributes = 0;
2476 exeAttributes |= (YesNoType.Yes == bundle) ? WixBundleExePackageAttributes.Bundle : 0; 2545 exeAttributes |= (YesNoType.Yes == bundle) ? WixBundleExePackageAttributes.Bundle : 0;
2546 exeAttributes |= (YesNoType.Yes == arpWin64) ? WixBundleExePackageAttributes.ArpWin64 : 0;
2477 2547
2478 this.Core.AddSymbol(new WixBundleExePackageSymbol(sourceLineNumbers, id) 2548 this.Core.AddSymbol(new WixBundleExePackageSymbol(sourceLineNumbers, id)
2479 { 2549 {
@@ -2482,7 +2552,10 @@ namespace WixToolset.Core
2482 InstallCommand = installArguments, 2552 InstallCommand = installArguments,
2483 RepairCommand = repairArguments, 2553 RepairCommand = repairArguments,
2484 UninstallCommand = uninstallArguments, 2554 UninstallCommand = uninstallArguments,
2485 ExeProtocol = protocol 2555 ExeProtocol = protocol,
2556 DetectionType = exeDetectionType.Value,
2557 ArpId = arpId,
2558 ArpDisplayVersion = arpDisplayVersion,
2486 }); 2559 });
2487 break; 2560 break;
2488 2561
@@ -2946,6 +3019,57 @@ namespace WixToolset.Core
2946 } 3019 }
2947 } 3020 }
2948 3021
3022 private void ParseExePackageArpEntryElement(XElement node, out string id, out string version, out YesNoType win64)
3023 {
3024 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
3025 id = null;
3026 version = null;
3027 win64 = YesNoType.NotSet;
3028
3029 foreach (var attrib in node.Attributes())
3030 {
3031 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
3032 {
3033 switch (attrib.Name.LocalName)
3034 {
3035 case "Id":
3036 id = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib);
3037 break;
3038 case "Version":
3039 version = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
3040 break;
3041 case "Win64":
3042 win64 = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3043 break;
3044 default:
3045 this.Core.UnexpectedAttribute(node, attrib);
3046 break;
3047 }
3048 }
3049 else
3050 {
3051 this.Core.ParseExtensionAttribute(node, attrib);
3052 }
3053 }
3054
3055 this.Core.ParseForExtensionElements(node);
3056
3057 if (String.IsNullOrEmpty(id))
3058 {
3059 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
3060 }
3061
3062 if (String.IsNullOrEmpty(version))
3063 {
3064 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
3065 }
3066
3067 if (win64 == YesNoType.NotSet)
3068 {
3069 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Win64"));
3070 }
3071 }
3072
2949 /// <summary> 3073 /// <summary>
2950 /// Parse CommandLine element. 3074 /// Parse CommandLine element.
2951 /// </summary> 3075 /// </summary>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
index 368cd961..242b9303 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
@@ -354,8 +354,8 @@ namespace WixToolsetTest.CoreIntegration
354 { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } }, 354 { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } },
355 }; 355 };
356 Assert.Equal(2, exePackageElements.Count); 356 Assert.Equal(2, exePackageElements.Count);
357 Assert.Equal("<ExePackage Id='credwiz.exe' Cache='keep' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' LogPathVariable='WixBundleLog_credwiz.exe' RollbackLogPathVariable='WixBundleRollbackLog_credwiz.exe' DetectCondition='none' InstallArguments='' UninstallArguments='-foo' Uninstallable='yes' RepairArguments='' Repairable='no' Protocol='burn' Bundle='yes'><PayloadRef Id='credwiz.exe' /><PayloadRef Id='SourceFilePayload' /></ExePackage>", exePackageElements[0].GetTestXml(ignoreAttributesByElementName)); 357 Assert.Equal("<ExePackage Id='credwiz.exe' Cache='keep' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' LogPathVariable='WixBundleLog_credwiz.exe' RollbackLogPathVariable='WixBundleRollbackLog_credwiz.exe' InstallArguments='' RepairArguments='' Repairable='no' DetectionType='condition' DetectCondition='none' UninstallArguments='-foo' Uninstallable='yes' Protocol='burn' Bundle='yes'><PayloadRef Id='credwiz.exe' /><PayloadRef Id='SourceFilePayload' /></ExePackage>", exePackageElements[0].GetTestXml(ignoreAttributesByElementName));
358 Assert.Equal("<ExePackage Id='cscript.exe' Cache='keep' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_cscript.exe' RollbackLogPathVariable='WixBundleRollbackLog_cscript.exe' DetectCondition='none' InstallArguments='' UninstallArguments='' Uninstallable='yes' RepairArguments='' Repairable='no' Protocol='none' Bundle='yes'><PayloadRef Id='cscript.exe' /><PayloadRef Id='SourceFilePayload' /></ExePackage>", exePackageElements[1].GetTestXml(ignoreAttributesByElementName)); 358 Assert.Equal("<ExePackage Id='cscript.exe' Cache='keep' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_cscript.exe' RollbackLogPathVariable='WixBundleRollbackLog_cscript.exe' InstallArguments='' RepairArguments='' Repairable='no' DetectionType='condition' DetectCondition='none' UninstallArguments='' Uninstallable='yes' Protocol='none' Bundle='yes'><PayloadRef Id='cscript.exe' /><PayloadRef Id='SourceFilePayload' /></ExePackage>", exePackageElements[1].GetTestXml(ignoreAttributesByElementName));
359 } 359 }
360 } 360 }
361 361
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs
index 67f295e8..32c207f7 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs
@@ -2,8 +2,10 @@
2 2
3namespace WixToolsetTest.CoreIntegration 3namespace WixToolsetTest.CoreIntegration
4{ 4{
5 using System.Collections.Generic;
5 using System.IO; 6 using System.IO;
6 using System.Linq; 7 using System.Linq;
8 using System.Xml;
7 using WixBuildTools.TestSupport; 9 using WixBuildTools.TestSupport;
8 using WixToolset.Core.TestPackage; 10 using WixToolset.Core.TestPackage;
9 using Xunit; 11 using Xunit;
@@ -11,7 +13,259 @@ namespace WixToolsetTest.CoreIntegration
11 public class ExePackageFixture 13 public class ExePackageFixture
12 { 14 {
13 [Fact] 15 [Fact]
14 public void ErrorWhenMissingDetectCondition() 16 public void CanBuildWithArpEntry()
17 {
18 var folder = TestData.Get(@"TestData");
19
20 using (var fs = new DisposableFileSystem())
21 {
22 var baseFolder = fs.GetFolder();
23 var intermediateFolder = Path.Combine(baseFolder, "obj");
24 var binFolder = Path.Combine(baseFolder, "bin");
25 var bundlePath = Path.Combine(binFolder, "test.exe");
26 var baFolderPath = Path.Combine(baseFolder, "ba");
27 var extractFolderPath = Path.Combine(baseFolder, "extract");
28
29 var result = WixRunner.Execute(new[]
30 {
31 "build",
32 Path.Combine(folder, "ExePackage", "ArpEntry.wxs"),
33 Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
34 "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
35 "-bindpath", Path.Combine(folder, ".Data"),
36 "-intermediateFolder", intermediateFolder,
37 "-o", bundlePath,
38 });
39
40 result.AssertSuccess();
41
42 Assert.True(File.Exists(bundlePath));
43
44 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
45 extractResult.AssertSuccess();
46
47 var ignoreAttributes = new Dictionary<string, List<string>>
48 {
49 { "ExePackage", new List<string> { "CacheId", "Size" } },
50 };
51 var exePackages = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:ExePackage")
52 .Cast<XmlElement>()
53 .Select(e => e.GetTestXml(ignoreAttributes))
54 .ToArray();
55 WixAssert.CompareLineByLine(new string[]
56 {
57 "<ExePackage Id='burn.exe' Cache='keep' CacheId='*' InstallSize='463360' Size='*' PerMachine='yes' Permanent='no' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_burn.exe' RollbackLogPathVariable='WixBundleRollbackLog_burn.exe' InstallArguments='-install' RepairArguments='-repair' Repairable='yes' DetectionType='arp' ArpId='id' ArpDisplayVersion='1.0.0.0'>" +
58 "<PayloadRef Id='burn.exe' />" +
59 "</ExePackage>",
60 }, exePackages);
61 }
62 }
63
64 [Fact]
65 public void WarningWhenInvalidArpEntryVersion()
66 {
67 var folder = TestData.Get(@"TestData");
68
69 using (var fs = new DisposableFileSystem())
70 {
71 var baseFolder = fs.GetFolder();
72 var intermediateFolder = Path.Combine(baseFolder, "obj");
73 var binFolder = Path.Combine(baseFolder, "bin");
74 var bundlePath = Path.Combine(binFolder, "test.exe");
75 var baFolderPath = Path.Combine(baseFolder, "ba");
76 var extractFolderPath = Path.Combine(baseFolder, "extract");
77
78 var result = WixRunner.Execute(false, new[]
79 {
80 "build",
81 Path.Combine(folder, "ExePackage", "InvalidArpEntryVersion.wxs"),
82 Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
83 "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
84 "-bindpath", Path.Combine(folder, ".Data"),
85 "-intermediateFolder", intermediateFolder,
86 "-o", bundlePath,
87 });
88
89 WixAssert.CompareLineByLine(new[]
90 {
91 "Invalid WixVersion '1.0.0.abc' in ArpEntry/@'Version'. Comparisons may yield unexpected results."
92 }, result.Messages.Select(m => m.ToString()).ToArray());
93 result.AssertSuccess();
94
95 Assert.True(File.Exists(bundlePath));
96
97 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
98 extractResult.AssertSuccess();
99
100 var ignoreAttributes = new Dictionary<string, List<string>>
101 {
102 { "ExePackage", new List<string> { "CacheId", "Size" } },
103 };
104 var exePackages = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:ExePackage")
105 .Cast<XmlElement>()
106 .Select(e => e.GetTestXml(ignoreAttributes))
107 .ToArray();
108 WixAssert.CompareLineByLine(new string[]
109 {
110 "<ExePackage Id='burn.exe' Cache='keep' CacheId='*' InstallSize='463360' Size='*' PerMachine='yes' Permanent='no' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_burn.exe' RollbackLogPathVariable='WixBundleRollbackLog_burn.exe' InstallArguments='-install' RepairArguments='' Repairable='no' DetectionType='arp' ArpId='id' ArpDisplayVersion='1.0.0.abc'>" +
111 "<PayloadRef Id='burn.exe' />" +
112 "</ExePackage>",
113 }, exePackages);
114 }
115 }
116
117 [Fact]
118 public void WarningWhenPermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry()
119 {
120 var folder = TestData.Get(@"TestData");
121
122 using (var fs = new DisposableFileSystem())
123 {
124 var baseFolder = fs.GetFolder();
125 var intermediateFolder = Path.Combine(baseFolder, "obj");
126 var binFolder = Path.Combine(baseFolder, "bin");
127 var bundlePath = Path.Combine(binFolder, "test.exe");
128 var baFolderPath = Path.Combine(baseFolder, "ba");
129 var extractFolderPath = Path.Combine(baseFolder, "extract");
130
131 var result = WixRunner.Execute(false, new[]
132 {
133 "build",
134 Path.Combine(folder, "ExePackage", "PermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs"),
135 Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
136 "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
137 "-bindpath", Path.Combine(folder, ".Data"),
138 "-intermediateFolder", intermediateFolder,
139 "-o", bundlePath,
140 });
141
142 WixAssert.CompareLineByLine(new[]
143 {
144 "The ExePackage/@DetectCondition attribute or child element ArpEntry is recommended so the package is only installed when absent."
145 }, result.Messages.Select(m => m.ToString()).ToArray());
146 result.AssertSuccess();
147
148 Assert.True(File.Exists(bundlePath));
149
150 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
151 extractResult.AssertSuccess();
152
153 var ignoreAttributes = new Dictionary<string, List<string>>
154 {
155 { "ExePackage", new List<string> { "CacheId", "Size" } },
156 };
157 var exePackages = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:ExePackage")
158 .Cast<XmlElement>()
159 .Select(e => e.GetTestXml(ignoreAttributes))
160 .ToArray();
161 WixAssert.CompareLineByLine(new string[]
162 {
163 "<ExePackage Id='burn.exe' Cache='keep' CacheId='*' InstallSize='463360' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_burn.exe' RollbackLogPathVariable='WixBundleRollbackLog_burn.exe' InstallArguments='-install' RepairArguments='' Repairable='no' DetectionType='none'>" +
164 "<PayloadRef Id='burn.exe' />" +
165 "</ExePackage>",
166 }, exePackages);
167 }
168 }
169
170 [Fact]
171 public void NoWarningWhenPermanentWithEmptyDetectCondition()
172 {
173 var folder = TestData.Get(@"TestData");
174
175 using (var fs = new DisposableFileSystem())
176 {
177 var baseFolder = fs.GetFolder();
178 var intermediateFolder = Path.Combine(baseFolder, "obj");
179 var binFolder = Path.Combine(baseFolder, "bin");
180 var bundlePath = Path.Combine(binFolder, "test.exe");
181 var baFolderPath = Path.Combine(baseFolder, "ba");
182 var extractFolderPath = Path.Combine(baseFolder, "extract");
183
184 var result = WixRunner.Execute(new[]
185 {
186 "build",
187 Path.Combine(folder, "ExePackage", "PermanentWithEmptyDetectCondition.wxs"),
188 Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
189 "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
190 "-bindpath", Path.Combine(folder, ".Data"),
191 "-intermediateFolder", intermediateFolder,
192 "-o", bundlePath,
193 });
194
195 result.AssertSuccess();
196
197 Assert.True(File.Exists(bundlePath));
198
199 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
200 extractResult.AssertSuccess();
201
202 var ignoreAttributes = new Dictionary<string, List<string>>
203 {
204 { "ExePackage", new List<string> { "CacheId", "Size" } },
205 };
206 var exePackages = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:ExePackage")
207 .Cast<XmlElement>()
208 .Select(e => e.GetTestXml(ignoreAttributes))
209 .ToArray();
210 WixAssert.CompareLineByLine(new string[]
211 {
212 "<ExePackage Id='burn.exe' Cache='keep' CacheId='*' InstallSize='463360' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_burn.exe' RollbackLogPathVariable='WixBundleRollbackLog_burn.exe' InstallArguments='-install' RepairArguments='' Repairable='no' DetectionType='none'>" +
213 "<PayloadRef Id='burn.exe' />" +
214 "</ExePackage>",
215 }, exePackages);
216 }
217 }
218
219 [Fact]
220 public void ErrorWhenArpEntryWithDetectCondition()
221 {
222 var folder = TestData.Get(@"TestData", "ExePackage");
223
224 using (var fs = new DisposableFileSystem())
225 {
226 var baseFolder = fs.GetFolder();
227
228 var result = WixRunner.Execute(new[]
229 {
230 "build",
231 Path.Combine(folder, "ArpEntryWithDetectCondition.wxs"),
232 "-o", Path.Combine(baseFolder, "test.wixlib")
233 });
234
235 WixAssert.CompareLineByLine(new[]
236 {
237 "The ExePackage element cannot have a child element 'ArpEntry' when attribute 'DetectCondition' is set.",
238 }, result.Messages.Select(m => m.ToString()).ToArray());
239 Assert.Equal(372, result.ExitCode);
240 }
241 }
242
243 [Fact]
244 public void ErrorWhenArpEntryWithUninstallArguments()
245 {
246 var folder = TestData.Get(@"TestData", "ExePackage");
247
248 using (var fs = new DisposableFileSystem())
249 {
250 var baseFolder = fs.GetFolder();
251
252 var result = WixRunner.Execute(new[]
253 {
254 "build",
255 Path.Combine(folder, "ArpEntryWithUninstallArguments.wxs"),
256 "-o", Path.Combine(baseFolder, "test.wixlib")
257 });
258
259 WixAssert.CompareLineByLine(new[]
260 {
261 "The ExePackage element cannot have a child element 'ArpEntry' when attribute 'UninstallArguments' is set.",
262 }, result.Messages.Select(m => m.ToString()).ToArray());
263 Assert.Equal(372, result.ExitCode);
264 }
265 }
266
267 [Fact]
268 public void ErrorWhenArpEntryWithInvalidId()
15 { 269 {
16 var folder = TestData.Get(@"TestData", "ExePackage"); 270 var folder = TestData.Get(@"TestData", "ExePackage");
17 271
@@ -22,16 +276,135 @@ namespace WixToolsetTest.CoreIntegration
22 var result = WixRunner.Execute(new[] 276 var result = WixRunner.Execute(new[]
23 { 277 {
24 "build", 278 "build",
25 Path.Combine(folder, "MissingDetectCondition.wxs"), 279 Path.Combine(folder, "InvalidArpEntryId.wxs"),
280 "-o", Path.Combine(baseFolder, "test.wixlib")
281 });
282
283 WixAssert.CompareLineByLine(new[]
284 {
285 "The ArpEntry/@Id attribute's value, '..\\id', is not a valid filename because it contains illegal characters. Legal filenames contain no more than 260 characters and must contain at least one non-period character. Any character except for the follow may be used: \\ ? | > < : / * \".",
286 }, result.Messages.Select(m => m.ToString()).ToArray());
287 Assert.Equal(27, result.ExitCode);
288 }
289 }
290
291 [Fact]
292 public void ErrorWhenNonPermanentWithOnlyDetectCondition()
293 {
294 var folder = TestData.Get(@"TestData", "ExePackage");
295
296 using (var fs = new DisposableFileSystem())
297 {
298 var baseFolder = fs.GetFolder();
299
300 var result = WixRunner.Execute(new[]
301 {
302 "build",
303 Path.Combine(folder, "NonPermanentWithOnlyDetectCondition.wxs"),
26 "-o", Path.Combine(baseFolder, "test.wixlib") 304 "-o", Path.Combine(baseFolder, "test.wixlib")
27 }); 305 });
28 306
29 WixAssert.CompareLineByLine(new[] 307 WixAssert.CompareLineByLine(new[]
30 { 308 {
31 "The ExePackage element's UninstallArguments attribute was not found; it is required without attribute Permanent present.", 309 "The ExePackage element's UninstallArguments attribute was not found; it is required without attribute Permanent present.",
32 "The ExePackage/@DetectCondition attribute is recommended so the package is only installed when absent."
33 }, result.Messages.Select(m => m.ToString()).ToArray()); 310 }, result.Messages.Select(m => m.ToString()).ToArray());
34 Assert.Equal(1153, result.ExitCode); 311 Assert.Equal(408, result.ExitCode);
312 }
313 }
314
315 [Fact]
316 public void ErrorWhenNonPermanentWithOnlyUninstallArguments()
317 {
318 var folder = TestData.Get(@"TestData", "ExePackage");
319
320 using (var fs = new DisposableFileSystem())
321 {
322 var baseFolder = fs.GetFolder();
323
324 var result = WixRunner.Execute(new[]
325 {
326 "build",
327 Path.Combine(folder, "NonPermanentWithOnlyUninstallArguments.wxs"),
328 "-o", Path.Combine(baseFolder, "test.wixlib")
329 });
330
331 WixAssert.CompareLineByLine(new[]
332 {
333 "The ExePackage element's DetectCondition attribute was not found; it is required without attribute Permanent present.",
334 }, result.Messages.Select(m => m.ToString()).ToArray());
335 Assert.Equal(408, result.ExitCode);
336 }
337 }
338
339 [Fact]
340 public void ErrorWhenRepairablePermanentWithoutDetectCondition()
341 {
342 var folder = TestData.Get(@"TestData", "ExePackage");
343
344 using (var fs = new DisposableFileSystem())
345 {
346 var baseFolder = fs.GetFolder();
347
348 var result = WixRunner.Execute(new[]
349 {
350 "build",
351 Path.Combine(folder, "RepairablePermanentWithoutDetectCondition.wxs"),
352 "-o", Path.Combine(baseFolder, "test.wixlib")
353 });
354
355 WixAssert.CompareLineByLine(new[]
356 {
357 "The ExePackage/@DetectCondition attribute is required to have a value when attribute RepairArguments is present.",
358 }, result.Messages.Select(m => m.ToString()).ToArray());
359 Assert.Equal(401, result.ExitCode);
360 }
361 }
362
363 [Fact]
364 public void ErrorWhenRepairablePermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry()
365 {
366 var folder = TestData.Get(@"TestData", "ExePackage");
367
368 using (var fs = new DisposableFileSystem())
369 {
370 var baseFolder = fs.GetFolder();
371
372 var result = WixRunner.Execute(new[]
373 {
374 "build",
375 Path.Combine(folder, "RepairablePermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs"),
376 "-o", Path.Combine(baseFolder, "test.wixlib")
377 });
378
379 WixAssert.CompareLineByLine(new[]
380 {
381 "Element 'ExePackage' missing attribute 'DetectCondition' or child element 'ArpEntry'. Exactly one of those is required when attribute 'RepairArguments' is specified.",
382 }, result.Messages.Select(m => m.ToString()).ToArray());
383 Assert.Equal(413, result.ExitCode);
384 }
385 }
386
387 [Fact]
388 public void ErrorWhenNonPermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry()
389 {
390 var folder = TestData.Get(@"TestData", "ExePackage");
391
392 using (var fs = new DisposableFileSystem())
393 {
394 var baseFolder = fs.GetFolder();
395
396 var result = WixRunner.Execute(new[]
397 {
398 "build",
399 Path.Combine(folder, "NonPermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs"),
400 "-o", Path.Combine(baseFolder, "test.wixlib")
401 });
402
403 WixAssert.CompareLineByLine(new[]
404 {
405 "Element 'ExePackage' missing attribute 'DetectCondition' or child element 'ArpEntry'. Exactly one of those is required when attribute 'Permanent' is not specified.",
406 }, result.Messages.Select(m => m.ToString()).ToArray());
407 Assert.Equal(414, result.ExitCode);
35 } 408 }
36 } 409 }
37 410
@@ -60,7 +433,7 @@ namespace WixToolsetTest.CoreIntegration
60 } 433 }
61 434
62 [Fact] 435 [Fact]
63 public void ErrorWhenRequireDetectCondition() 436 public void ErrorWhenUninstallArgumentsWithoutDetectCondition()
64 { 437 {
65 var folder = TestData.Get(@"TestData", "ExePackage"); 438 var folder = TestData.Get(@"TestData", "ExePackage");
66 439
@@ -71,10 +444,14 @@ namespace WixToolsetTest.CoreIntegration
71 var result = WixRunner.Execute(new[] 444 var result = WixRunner.Execute(new[]
72 { 445 {
73 "build", 446 "build",
74 Path.Combine(folder, "RequireDetectCondition.wxs"), 447 Path.Combine(folder, "UninstallArgumentsWithoutDetectCondition.wxs"),
75 "-o", Path.Combine(baseFolder, "test.wixlib") 448 "-o", Path.Combine(baseFolder, "test.wixlib")
76 }); 449 });
77 450
451 WixAssert.CompareLineByLine(new[]
452 {
453 "The ExePackage/@DetectCondition attribute is required to have a value when attribute UninstallArguments is present.",
454 }, result.Messages.Select(m => m.ToString()).ToArray());
78 Assert.Equal(401, result.ExitCode); 455 Assert.Equal(401, result.ExitCode);
79 } 456 }
80 } 457 }
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs
index 29ea1e7f..da15026a 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs
@@ -126,7 +126,7 @@ namespace WixToolsetTest.CoreIntegration
126 { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } }, 126 { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } },
127 }; 127 };
128 Assert.Equal(1, exePackageElements.Count); 128 Assert.Equal(1, exePackageElements.Count);
129 Assert.Equal("<ExePackage Id='PackagePayloadInPayloadGroup' Cache='keep' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_PackagePayloadInPayloadGroup' RollbackLogPathVariable='WixBundleRollbackLog_PackagePayloadInPayloadGroup' DetectCondition='none' InstallArguments='' UninstallArguments='' Uninstallable='no' RepairArguments='' Repairable='no'><PayloadRef Id='burn.exe' /></ExePackage>", exePackageElements[0].GetTestXml(ignoreAttributesByElementName)); 129 Assert.Equal("<ExePackage Id='PackagePayloadInPayloadGroup' Cache='keep' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_PackagePayloadInPayloadGroup' RollbackLogPathVariable='WixBundleRollbackLog_PackagePayloadInPayloadGroup' InstallArguments='' RepairArguments='' Repairable='no' DetectionType='condition' DetectCondition='none'><PayloadRef Id='burn.exe' /></ExePackage>", exePackageElements[0].GetTestXml(ignoreAttributesByElementName));
130 130
131 var payloadElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='burn.exe']"); 131 var payloadElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='burn.exe']");
132 Assert.Equal(1, payloadElements.Count); 132 Assert.Equal(1, payloadElements.Count);
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntry.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntry.wxs
new file mode 100644
index 00000000..19b20853
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntry.wxs
@@ -0,0 +1,12 @@
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 InstallArguments="-install"
6 RepairArguments="-repair"
7 SourceFile="burn.exe">
8 <ArpEntry Id="id" Version="1.0.0.0" Win64="no" />
9 </ExePackage>
10 </PackageGroup>
11 </Fragment>
12</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithDetectCondition.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithDetectCondition.wxs
new file mode 100644
index 00000000..f9c3414c
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithDetectCondition.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="TestPackageGroup">
5 <ExePackage InstallArguments="-install"
6 DetectCondition="none"
7 SourceFile="testsetup.exe">
8 <ArpEntry Id="id" Version="1.0.0.0" Win64="no" />
9 </ExePackage>
10 </PackageGroup>
11 </Fragment>
12</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithUninstallArguments.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithUninstallArguments.wxs
new file mode 100644
index 00000000..794c6dd3
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/ArpEntryWithUninstallArguments.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="TestPackageGroup">
5 <ExePackage InstallArguments="-install"
6 UninstallArguments="none"
7 SourceFile="testsetup.exe">
8 <ArpEntry Id="id" Version="1.0.0.0" Win64="no" />
9 </ExePackage>
10 </PackageGroup>
11 </Fragment>
12</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryId.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryId.wxs
new file mode 100644
index 00000000..d81267f2
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryId.wxs
@@ -0,0 +1,11 @@
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 InstallArguments="-install"
6 SourceFile="burn.exe">
7 <ArpEntry Id="..\id" Version="1.0.0" Win64="no" />
8 </ExePackage>
9 </PackageGroup>
10 </Fragment>
11</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryVersion.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryVersion.wxs
new file mode 100644
index 00000000..3230d4b6
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/InvalidArpEntryVersion.wxs
@@ -0,0 +1,11 @@
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 InstallArguments="-install"
6 SourceFile="burn.exe">
7 <ArpEntry Id="id" Version="1.0.0.abc" Win64="no" />
8 </ExePackage>
9 </PackageGroup>
10 </Fragment>
11</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyDetectCondition.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyDetectCondition.wxs
new file mode 100644
index 00000000..c47af081
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyDetectCondition.wxs
@@ -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="TestPackageGroup">
5 <ExePackage InstallArguments="-install"
6 DetectCondition="none"
7 SourceFile="testsetup.exe" />
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyUninstallArguments.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyUninstallArguments.wxs
new file mode 100644
index 00000000..004fd093
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithOnlyUninstallArguments.wxs
@@ -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="TestPackageGroup">
5 <ExePackage InstallArguments="-install"
6 UninstallArguments="none"
7 SourceFile="testsetup.exe" />
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/MissingDetectCondition.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs
index e57180f7..e57180f7 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/MissingDetectCondition.wxs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/NonPermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithEmptyDetectCondition.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithEmptyDetectCondition.wxs
new file mode 100644
index 00000000..f16caabf
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithEmptyDetectCondition.wxs
@@ -0,0 +1,11 @@
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 InstallArguments="-install"
6 SourceFile="burn.exe"
7 DetectCondition=""
8 Permanent="yes" />
9 </PackageGroup>
10 </Fragment>
11</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs
new file mode 100644
index 00000000..53c7b2ef
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/PermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs
@@ -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 InstallArguments="-install"
6 SourceFile="burn.exe"
7 Permanent="yes" />
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectCondition.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectCondition.wxs
new file mode 100644
index 00000000..83adeb29
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectCondition.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="TestPackageGroup">
5 <ExePackage InstallArguments="-install"
6 SourceFile="testsetup.exe"
7 RepairArguments="-repair"
8 UninstallArguments="-uninstall"
9 Permanent="yes" />
10 </PackageGroup>
11 </Fragment>
12</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs
new file mode 100644
index 00000000..50d01252
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RepairablePermanentWithoutDetectConditionOrUninstallArgumentsOrArpEntry.wxs
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="TestPackageGroup">
5 <ExePackage InstallArguments="-install"
6 SourceFile="testsetup.exe"
7 RepairArguments="-repair"
8 Permanent="yes" />
9 </PackageGroup>
10 </Fragment>
11</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RequireDetectCondition.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/UninstallArgumentsWithoutDetectCondition.wxs
index 0b094860..792b2503 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/RequireDetectCondition.wxs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/UninstallArgumentsWithoutDetectCondition.wxs
@@ -5,6 +5,7 @@
5 <ExePackage DetectCondition="" 5 <ExePackage DetectCondition=""
6 InstallArguments="-install" 6 InstallArguments="-install"
7 UninstallArguments="-uninstall" 7 UninstallArguments="-uninstall"
8 Permanent="yes"
8 SourceFile="testsetup.exe" /> 9 SourceFile="testsetup.exe" />
9 </PackageGroup> 10 </PackageGroup>
10 </Fragment> 11 </Fragment>