aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ext/Bal/dnchost/dnchost.cpp19
-rw-r--r--src/ext/Bal/mbahost/mbahost.cpp54
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs38
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs12
-rw-r--r--src/ext/Bal/wixext/BalBurnBackendExtension.cs1
-rw-r--r--src/ext/Bal/wixext/BalCompiler.cs27
-rw-r--r--src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs5
-rw-r--r--src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs47
-rw-r--r--src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp179
-rw-r--r--src/ext/Bal/wixstdba/inc/preqba.h1
-rw-r--r--src/test/burn/TestBA/TestBA.cs7
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj5
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs12
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj5
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs12
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wixproj24
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wxs30
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleC/bad.runtimeconfig.json10
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wixproj24
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wxs29
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleD/bad.config17
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wixproj22
-rw-r--r--src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wxs26
-rw-r--r--src/test/burn/TestData/PrereqBaTests/PackageC/PackageC.wixproj (renamed from src/test/burn/TestData/PrereqBaTests/PackageF/PackageF.wixproj)5
-rw-r--r--src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.cpp79
-rw-r--r--src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.def6
-rw-r--r--src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.vcxproj66
-rw-r--r--src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.cpp48
-rw-r--r--src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.h31
-rw-r--r--src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.cpp33
-rw-r--r--src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.vcxproj63
-rw-r--r--src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.cpp3
-rw-r--r--src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.h17
-rw-r--r--src/test/burn/WixTestTools/BundleInstaller.cs14
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs225
35 files changed, 1154 insertions, 42 deletions
diff --git a/src/ext/Bal/dnchost/dnchost.cpp b/src/ext/Bal/dnchost/dnchost.cpp
index 6c066f43..36970f83 100644
--- a/src/ext/Bal/dnchost/dnchost.cpp
+++ b/src/ext/Bal/dnchost/dnchost.cpp
@@ -76,6 +76,16 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
76 vstate.fInitialized = TRUE; 76 vstate.fInitialized = TRUE;
77 } 77 }
78 78
79 if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted)
80 {
81 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application since it's configured to always run before loading the runtime.");
82
83 hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults);
84 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
85
86 ExitFunction();
87 }
88
79 if (!vstate.fInitializedRuntime) 89 if (!vstate.fInitializedRuntime)
80 { 90 {
81 hr = LoadRuntime(&vstate); 91 hr = LoadRuntime(&vstate);
@@ -214,6 +224,15 @@ static HRESULT LoadDncConfiguration(
214 hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0); 224 hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0);
215 BalExitOnFailure(hr, "Failed to concat extension to runtime config path."); 225 BalExitOnFailure(hr, "Failed to concat extension to runtime config path.");
216 226
227 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqOptions", &pixnHost);
228 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to find WixMbaPrereqOptions element in bootstrapper application config.");
229
230 if (fXmlFound)
231 {
232 hr = XmlGetAttributeNumber(pixnHost, L"AlwaysInstallPrereqs", reinterpret_cast<DWORD*>(&pState->prereqData.fAlwaysInstallPrereqs));
233 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value.");
234 }
235
217 pState->type = DNCHOSTTYPE_FDD; 236 pState->type = DNCHOSTTYPE_FDD;
218 237
219 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixDncOptions", &pixnHost); 238 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixDncOptions", &pixnHost);
diff --git a/src/ext/Bal/mbahost/mbahost.cpp b/src/ext/Bal/mbahost/mbahost.cpp
index 3de77a05..0b89fc58 100644
--- a/src/ext/Bal/mbahost/mbahost.cpp
+++ b/src/ext/Bal/mbahost/mbahost.cpp
@@ -24,6 +24,10 @@ static HRESULT GetAppDomain(
24static HRESULT LoadModulePaths( 24static HRESULT LoadModulePaths(
25 __in MBASTATE* pState 25 __in MBASTATE* pState
26 ); 26 );
27static HRESULT LoadMbaConfiguration(
28 __in MBASTATE* pState,
29 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
30 );
27static HRESULT CheckSupportedFrameworks( 31static HRESULT CheckSupportedFrameworks(
28 __in LPCWSTR wzConfigPath 32 __in LPCWSTR wzConfigPath
29 ); 33 );
@@ -96,12 +100,28 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
96 100
97 if (!vstate.fInitialized) 101 if (!vstate.fInitialized)
98 { 102 {
103 hr = XmlInitialize();
104 BalExitOnFailure(hr, "Failed to initialize XML.");
105
99 hr = LoadModulePaths(&vstate); 106 hr = LoadModulePaths(&vstate);
100 BalExitOnFailure(hr, "Failed to load the module paths."); 107 BalExitOnFailure(hr, "Failed to load the module paths.");
101 108
109 hr = LoadMbaConfiguration(&vstate, pArgs);
110 BalExitOnFailure(hr, "Failed to get the mba configuration.");
111
102 vstate.fInitialized = TRUE; 112 vstate.fInitialized = TRUE;
103 } 113 }
104 114
115 if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted)
116 {
117 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application since it's configured to always run before loading the runtime.");
118
119 hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults);
120 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
121
122 ExitFunction();
123 }
124
105 if (!vstate.fInitializedRuntime) 125 if (!vstate.fInitializedRuntime)
106 { 126 {
107 hr = LoadRuntime(&vstate); 127 hr = LoadRuntime(&vstate);
@@ -264,6 +284,35 @@ LExit:
264 return hr; 284 return hr;
265} 285}
266 286
287static HRESULT LoadMbaConfiguration(
288 __in MBASTATE* pState,
289 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
290 )
291{
292 HRESULT hr = S_OK;
293 IXMLDOMDocument* pixdManifest = NULL;
294 IXMLDOMNode* pixnHost = NULL;
295 BOOL fXmlFound = FALSE;
296
297 hr = XmlLoadDocumentFromFile(pArgs->pCommand->wzBootstrapperApplicationDataPath, &pixdManifest);
298 BalExitOnFailure(hr, "Failed to load BalManifest '%ls'", pArgs->pCommand->wzBootstrapperApplicationDataPath);
299
300 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqOptions", &pixnHost);
301 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to find WixMbaPrereqOptions element in bootstrapper application config.");
302
303 if (fXmlFound)
304 {
305 hr = XmlGetAttributeNumber(pixnHost, L"AlwaysInstallPrereqs", reinterpret_cast<DWORD*>(&pState->prereqData.fAlwaysInstallPrereqs));
306 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value.");
307 }
308
309LExit:
310 ReleaseObject(pixnHost);
311 ReleaseObject(pixdManifest);
312
313 return hr;
314}
315
267// Checks whether at least one of required supported frameworks is installed via the NETFX registry keys. 316// Checks whether at least one of required supported frameworks is installed via the NETFX registry keys.
268static HRESULT CheckSupportedFrameworks( 317static HRESULT CheckSupportedFrameworks(
269 __in LPCWSTR wzConfigPath 318 __in LPCWSTR wzConfigPath
@@ -280,9 +329,6 @@ static HRESULT CheckSupportedFrameworks(
280 DWORD dwFrameworkInstalled = 0; 329 DWORD dwFrameworkInstalled = 0;
281 BOOL fUpdatedManifest = FALSE; 330 BOOL fUpdatedManifest = FALSE;
282 331
283 hr = XmlInitialize();
284 ExitOnFailure(hr, "Failed to initialize XML.");
285
286 hr = XmlLoadDocumentFromFile(wzConfigPath, &pixdManifest); 332 hr = XmlLoadDocumentFromFile(wzConfigPath, &pixdManifest);
287 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath); 333 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath);
288 334
@@ -342,8 +388,6 @@ LExit:
342 ReleaseObject(pNodeList); 388 ReleaseObject(pNodeList);
343 ReleaseObject(pixdManifest); 389 ReleaseObject(pixdManifest);
344 390
345 XmlUninitialize();
346
347 return hr; 391 return hr;
348} 392}
349 393
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
index 9aea8c1d..43484855 100644
--- a/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
@@ -107,7 +107,41 @@ namespace WixToolsetTest.Bal
107 } 107 }
108 108
109 [Fact] 109 [Fact]
110 public void CantBuildUsingMBAWithNoPrereqs() 110 public void CanBuildUsingMBAWithAlwaysInstallPrereqs()
111 {
112 using (var fs = new DisposableFileSystem())
113 {
114 var baseFolder = fs.GetFolder();
115 var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
116 var bundleSourceFolder = TestData.Get(@"TestData\MBA");
117 var intermediateFolder = Path.Combine(baseFolder, "obj");
118 var baFolderPath = Path.Combine(baseFolder, "ba");
119 var extractFolderPath = Path.Combine(baseFolder, "extract");
120
121 var compileResult = WixRunner.Execute(new[]
122 {
123 "build",
124 Path.Combine(bundleSourceFolder, "AlwaysInstallPrereqsBundle.wxs"),
125 "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
126 "-intermediateFolder", intermediateFolder,
127 "-o", bundleFile,
128 });
129
130 compileResult.AssertSuccess();
131
132 Assert.True(File.Exists(bundleFile));
133
134 var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
135 extractResult.AssertSuccess();
136
137 var wixMbaPrereqOptionsElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixMbaPrereqOptions");
138 var wixMbaPrereqOptions = (XmlNode)Assert.Single(wixMbaPrereqOptionsElements);
139 Assert.Equal("<WixMbaPrereqOptions AlwaysInstallPrereqs='1' />", wixMbaPrereqOptions.GetTestXml());
140 }
141 }
142
143 [Fact]
144 public void CannotBuildUsingMBAWithNoPrereqs()
111 { 145 {
112 using (var fs = new DisposableFileSystem()) 146 using (var fs = new DisposableFileSystem())
113 { 147 {
@@ -133,7 +167,7 @@ namespace WixToolsetTest.Bal
133 } 167 }
134 168
135 [Fact] 169 [Fact]
136 public void CantBuildUsingOverridableWrongCase() 170 public void CannotBuildUsingOverridableWrongCase()
137 { 171 {
138 using (var fs = new DisposableFileSystem()) 172 using (var fs = new DisposableFileSystem())
139 { 173 {
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs
new file mode 100644
index 00000000..685fef7b
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 <Bundle Name="AlwaysInstallPrereqsBundle" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{36E9E102-E0E4-4A91-941D-6681A49216E6}">
5 <BootstrapperApplication>
6 <bal:WixManagedBootstrapperApplicationHost AlwaysInstallPrereqs="yes" />
7 </BootstrapperApplication>
8 <Chain>
9 <ExePackage bal:PrereqPackage="yes" Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 </Chain>
11 </Bundle>
12</Wix>
diff --git a/src/ext/Bal/wixext/BalBurnBackendExtension.cs b/src/ext/Bal/wixext/BalBurnBackendExtension.cs
index 3b19ae78..d34c159a 100644
--- a/src/ext/Bal/wixext/BalBurnBackendExtension.cs
+++ b/src/ext/Bal/wixext/BalBurnBackendExtension.cs
@@ -24,6 +24,7 @@ namespace WixToolset.Bal
24 BalSymbolDefinitions.WixMbaPrereqInformation, 24 BalSymbolDefinitions.WixMbaPrereqInformation,
25 BalSymbolDefinitions.WixStdbaOptions, 25 BalSymbolDefinitions.WixStdbaOptions,
26 BalSymbolDefinitions.WixStdbaOverridableVariable, 26 BalSymbolDefinitions.WixStdbaOverridableVariable,
27 BalSymbolDefinitions.WixMbaPrereqOptions,
27 }; 28 };
28 29
29 protected override IReadOnlyCollection<IntermediateSymbolDefinition> SymbolDefinitions => BurnSymbolDefinitions; 30 protected override IReadOnlyCollection<IntermediateSymbolDefinition> SymbolDefinitions => BurnSymbolDefinitions;
diff --git a/src/ext/Bal/wixext/BalCompiler.cs b/src/ext/Bal/wixext/BalCompiler.cs
index 267345e7..1721f252 100644
--- a/src/ext/Bal/wixext/BalCompiler.cs
+++ b/src/ext/Bal/wixext/BalCompiler.cs
@@ -117,6 +117,7 @@ namespace WixToolset.Bal
117 117
118 switch (parentElement.Name.LocalName) 118 switch (parentElement.Name.LocalName)
119 { 119 {
120 case "BundlePackage":
120 case "ExePackage": 121 case "ExePackage":
121 case "MsiPackage": 122 case "MsiPackage":
122 case "MspPackage": 123 case "MspPackage":
@@ -216,7 +217,7 @@ namespace WixToolset.Bal
216 case "PrereqPackage": 217 case "PrereqPackage":
217 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute)) 218 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute))
218 { 219 {
219 if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo)) 220 if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out _))
220 { 221 {
221 prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers) 222 prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
222 { 223 {
@@ -703,6 +704,7 @@ namespace WixToolset.Bal
703 private void ParseWixManagedBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node) 704 private void ParseWixManagedBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node)
704 { 705 {
705 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); 706 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
707 bool alwaysInstallPrereqs = false;
706 string logoFile = null; 708 string logoFile = null;
707 string themeFile = null; 709 string themeFile = null;
708 string localizationFile = null; 710 string localizationFile = null;
@@ -714,6 +716,9 @@ namespace WixToolset.Bal
714 { 716 {
715 switch (attrib.Name.LocalName) 717 switch (attrib.Name.LocalName)
716 { 718 {
719 case "AlwaysInstallPrereqs":
720 alwaysInstallPrereqs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes;
721 break;
717 case "LogoFile": 722 case "LogoFile":
718 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 723 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
719 break; 724 break;
@@ -792,6 +797,14 @@ namespace WixToolset.Bal
792 } 797 }
793 798
794 this.CreateBARef(section, sourceLineNumbers, node, baId); 799 this.CreateBARef(section, sourceLineNumbers, node, baId);
800
801 if (alwaysInstallPrereqs)
802 {
803 section.AddSymbol(new WixMbaPrereqOptionsSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixMbaPrereqOptions"))
804 {
805 AlwaysInstallPrereqs = 1,
806 });
807 }
795 } 808 }
796 } 809 }
797 810
@@ -802,6 +815,7 @@ namespace WixToolset.Bal
802 private void ParseWixDotNetCoreBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node) 815 private void ParseWixDotNetCoreBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node)
803 { 816 {
804 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); 817 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
818 bool alwaysInstallPrereqs = false;
805 string logoFile = null; 819 string logoFile = null;
806 string themeFile = null; 820 string themeFile = null;
807 string localizationFile = null; 821 string localizationFile = null;
@@ -814,6 +828,9 @@ namespace WixToolset.Bal
814 { 828 {
815 switch (attrib.Name.LocalName) 829 switch (attrib.Name.LocalName)
816 { 830 {
831 case "AlwaysInstallPrereqs":
832 alwaysInstallPrereqs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes;
833 break;
817 case "LogoFile": 834 case "LogoFile":
818 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 835 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
819 break; 836 break;
@@ -903,6 +920,14 @@ namespace WixToolset.Bal
903 } 920 }
904 921
905 this.CreateBARef(section, sourceLineNumbers, node, baId); 922 this.CreateBARef(section, sourceLineNumbers, node, baId);
923
924 if (alwaysInstallPrereqs)
925 {
926 section.AddSymbol(new WixMbaPrereqOptionsSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixMbaPrereqOptions"))
927 {
928 AlwaysInstallPrereqs = 1,
929 });
930 }
906 } 931 }
907 } 932 }
908 933
diff --git a/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs b/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
index 90865621..9010ce2d 100644
--- a/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
+++ b/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
@@ -16,6 +16,7 @@ namespace WixToolset.Bal
16 WixMbaPrereqInformation, 16 WixMbaPrereqInformation,
17 WixStdbaOptions, 17 WixStdbaOptions,
18 WixStdbaOverridableVariable, 18 WixStdbaOverridableVariable,
19 WixMbaPrereqOptions,
19 } 20 }
20 21
21 public static partial class BalSymbolDefinitions 22 public static partial class BalSymbolDefinitions
@@ -60,6 +61,9 @@ namespace WixToolset.Bal
60 case BalSymbolDefinitionType.WixStdbaOverridableVariable: 61 case BalSymbolDefinitionType.WixStdbaOverridableVariable:
61 return BalSymbolDefinitions.WixStdbaOverridableVariable; 62 return BalSymbolDefinitions.WixStdbaOverridableVariable;
62 63
64 case BalSymbolDefinitionType.WixMbaPrereqOptions:
65 return BalSymbolDefinitions.WixMbaPrereqOptions;
66
63 default: 67 default:
64 throw new ArgumentOutOfRangeException(nameof(type)); 68 throw new ArgumentOutOfRangeException(nameof(type));
65 } 69 }
@@ -75,6 +79,7 @@ namespace WixToolset.Bal
75 WixMbaPrereqInformation.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); 79 WixMbaPrereqInformation.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
76 WixStdbaOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); 80 WixStdbaOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
77 WixStdbaOverridableVariable.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); 81 WixStdbaOverridableVariable.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
82 WixMbaPrereqOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
78 } 83 }
79 } 84 }
80} 85}
diff --git a/src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs b/src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs
new file mode 100644
index 00000000..66374579
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs
@@ -0,0 +1,47 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixMbaPrereqOptions = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixMbaPrereqOptions.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs), IntermediateFieldType.Number),
15 },
16 typeof(WixMbaPrereqOptionsSymbol));
17 }
18}
19
20namespace WixToolset.Bal.Symbols
21{
22 using WixToolset.Data;
23
24 public enum WixMbaPrereqOptionsSymbolFields
25 {
26 AlwaysInstallPrereqs,
27 }
28
29 public class WixMbaPrereqOptionsSymbol : IntermediateSymbol
30 {
31 public WixMbaPrereqOptionsSymbol() : base(BalSymbolDefinitions.WixMbaPrereqOptions, null, null)
32 {
33 }
34
35 public WixMbaPrereqOptionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixMbaPrereqOptions, sourceLineNumber, id)
36 {
37 }
38
39 public IntermediateField this[WixMbaPrereqOptionsSymbolFields index] => this.Fields[(int)index];
40
41 public int AlwaysInstallPrereqs
42 {
43 get => this.Fields[(int)WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs].AsNumber();
44 set => this.Set((int)WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs, value);
45 }
46 }
47}
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
index 3774f49c..9c0f9576 100644
--- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
@@ -30,6 +30,8 @@ enum WIXSTDBA_STATE
30 WIXSTDBA_STATE_HELP, 30 WIXSTDBA_STATE_HELP,
31 WIXSTDBA_STATE_DETECTING, 31 WIXSTDBA_STATE_DETECTING,
32 WIXSTDBA_STATE_DETECTED, 32 WIXSTDBA_STATE_DETECTED,
33 WIXSTDBA_STATE_PLANNING_PREREQS,
34 WIXSTDBA_STATE_PLANNED_PREREQS,
33 WIXSTDBA_STATE_PLANNING, 35 WIXSTDBA_STATE_PLANNING,
34 WIXSTDBA_STATE_PLANNED, 36 WIXSTDBA_STATE_PLANNED,
35 WIXSTDBA_STATE_APPLYING, 37 WIXSTDBA_STATE_APPLYING,
@@ -49,6 +51,7 @@ enum WM_WIXSTDBA
49 WM_WIXSTDBA_APPLY_PACKAGES, 51 WM_WIXSTDBA_APPLY_PACKAGES,
50 WM_WIXSTDBA_CHANGE_STATE, 52 WM_WIXSTDBA_CHANGE_STATE,
51 WM_WIXSTDBA_SHOW_FAILURE, 53 WM_WIXSTDBA_SHOW_FAILURE,
54 WM_WIXSTDBA_PLAN_PREREQS,
52}; 55};
53 56
54// This enum must be kept in the same order as the vrgwzPageNames array. 57// This enum must be kept in the same order as the vrgwzPageNames array.
@@ -217,9 +220,11 @@ public: // IBootstrapperApplication
217 : "A restart is required by the prerequisites but the user delayed it. The bootstrapper application will be reloaded after the computer is restarted."); 220 : "A restart is required by the prerequisites but the user delayed it. The bootstrapper application will be reloaded after the computer is restarted.");
218 } 221 }
219 } 222 }
220 else if (m_fPrereqInstalled) 223 else if (m_fPrereqInstalled || m_fPrereqSkipped)
221 { 224 {
222 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were successfully installed. The bootstrapper application will be reloaded."); 225 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, m_fPrereqInstalled
226 ? "The prerequisites were successfully installed. The bootstrapper application will be reloaded."
227 : "The prerequisites were already installed. The bootstrapper application will be reloaded.");
223 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER; 228 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER;
224 m_pPrereqData->fCompleted = TRUE; 229 m_pPrereqData->fCompleted = TRUE;
225 } 230 }
@@ -275,13 +280,16 @@ public: // IBootstrapperApplication
275 hr = S_OK; 280 hr = S_OK;
276 } 281 }
277 282
278 // If the UI should be visible, display it now and hide the splash screen 283 if (!m_fPreplanPrereqs)
279 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
280 { 284 {
281 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW); 285 // If the UI should be visible, display it now and hide the splash screen
282 } 286 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
287 {
288 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW);
289 }
283 290
284 m_pEngine->CloseSplashScreen(); 291 m_pEngine->CloseSplashScreen();
292 }
285 293
286 return __super::OnDetectBegin(fCached, registrationType, cPackages, pfCancel); 294 return __super::OnDetectBegin(fCached, registrationType, cPackages, pfCancel);
287 } 295 }
@@ -331,24 +339,37 @@ public: // IBootstrapperApplication
331 if (fEvaluateConditions) 339 if (fEvaluateConditions)
332 { 340 {
333 hrStatus = EvaluateConditions(); 341 hrStatus = EvaluateConditions();
334
335 if (FAILED(hrStatus))
336 {
337 fSkipToPlan = FALSE;
338 }
339 } 342 }
340 343
341 SetState(WIXSTDBA_STATE_DETECTED, hrStatus); 344 SetState(WIXSTDBA_STATE_DETECTED, hrStatus);
342 345
343 if (fSkipToPlan) 346 if (SUCCEEDED(hrStatus))
344 { 347 {
345 ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action); 348 if (m_fPreplanPrereqs)
349 {
350 ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PREREQS, 0, BOOTSTRAPPER_ACTION_INSTALL);
351 }
352 else if (fSkipToPlan)
353 {
354 ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action);
355 }
346 } 356 }
347 357
348 return hr; 358 return hr;
349 } 359 }
350 360
351 361
362 virtual STDMETHODIMP OnPlanBegin(
363 __in DWORD cPackages,
364 __in BOOL* pfCancel
365 )
366 {
367 m_fPrereqPackagePlanned = FALSE;
368
369 return __super::OnPlanBegin(cPackages, pfCancel);
370 }
371
372
352 virtual STDMETHODIMP OnPlanRelatedBundleType( 373 virtual STDMETHODIMP OnPlanRelatedBundleType(
353 __in_z LPCWSTR wzBundleId, 374 __in_z LPCWSTR wzBundleId,
354 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE recommendedType, 375 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE recommendedType,
@@ -484,24 +505,97 @@ public: // IBootstrapperApplication
484 } 505 }
485 506
486 507
508 virtual STDMETHODIMP OnPlannedPackage(
509 __in_z LPCWSTR wzPackageId,
510 __in BOOTSTRAPPER_ACTION_STATE execute,
511 __in BOOTSTRAPPER_ACTION_STATE rollback,
512 __in BOOL fPlannedCache,
513 __in BOOL fPlannedUncache
514 )
515 {
516 if (m_fPrereq && BOOTSTRAPPER_ACTION_STATE_NONE != execute)
517 {
518 m_fPrereqPackagePlanned = TRUE;
519 }
520
521 return __super::OnPlannedPackage(wzPackageId, execute, rollback, fPlannedCache, fPlannedUncache);
522 }
523
524
487 virtual STDMETHODIMP OnPlanComplete( 525 virtual STDMETHODIMP OnPlanComplete(
488 __in HRESULT hrStatus 526 __in HRESULT hrStatus
489 ) 527 )
490 { 528 {
491 HRESULT hr = S_OK; 529 HRESULT hr = S_OK;
530 BOOL fPlannedPrereqs = WIXSTDBA_STATE_PLANNING_PREREQS == m_state;
531 WIXSTDBA_STATE completedState = WIXSTDBA_STATE_PLANNED;
532 BOOL fApply = TRUE;
492 533
493 SetState(WIXSTDBA_STATE_PLANNED, hrStatus); 534 if (fPlannedPrereqs)
535 {
536 if (SUCCEEDED(hrStatus) && !m_fPrereqPackagePlanned)
537 {
538 // Nothing to do, so close and let the parent BA take over.
539 m_fPrereqSkipped = TRUE;
540 SetState(WIXSTDBA_STATE_APPLIED, S_OK);
541 ExitFunction();
542 }
543 else if (BOOTSTRAPPER_ACTION_HELP == m_command.action)
544 {
545 // If prereq packages were planned then the managed BA probably can't be loaded, so show the help from this BA.
494 546
495 if (SUCCEEDED(hrStatus)) 547 // Need to force the state change since normally moving backwards is prevented.
548 ::PostMessageW(m_hWnd, WM_WIXSTDBA_CHANGE_STATE, 0, WIXSTDBA_STATE_HELP);
549
550 ::PostMessageW(m_hWnd, WM_WIXSTDBA_SHOW_HELP, 0, 0);
551
552 ExitFunction();
553 }
554
555 completedState = WIXSTDBA_STATE_PLANNED_PREREQS;
556 }
557
558 SetState(completedState, hrStatus);
559
560 if (FAILED(hrStatus))
561 {
562 ExitFunction();
563 }
564
565 if (fPlannedPrereqs)
566 {
567 // If the UI should be visible, display it now and hide the splash screen
568 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
569 {
570 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW);
571 }
572
573 m_pEngine->CloseSplashScreen();
574
575 fApply = BOOTSTRAPPER_DISPLAY_FULL > m_command.display ||
576 BOOTSTRAPPER_RESUME_TYPE_REBOOT == m_command.resumeType;
577 }
578
579 if (fApply)
496 { 580 {
497 ::PostMessageW(m_hWnd, WM_WIXSTDBA_APPLY_PACKAGES, 0, 0); 581 ::PostMessageW(m_hWnd, WM_WIXSTDBA_APPLY_PACKAGES, 0, 0);
498 } 582 }
499 583
584 LExit:
585 return hr;
586 }
587
588
589 virtual STDMETHODIMP OnApplyBegin(
590 __in DWORD dwPhaseCount,
591 __in BOOL* pfCancel
592 )
593 {
500 m_fStartedExecution = FALSE; 594 m_fStartedExecution = FALSE;
501 m_dwCalculatedCacheProgress = 0; 595 m_dwCalculatedCacheProgress = 0;
502 m_dwCalculatedExecuteProgress = 0; 596 m_dwCalculatedExecuteProgress = 0;
503 597
504 return hr; 598 return __super::OnApplyBegin(dwPhaseCount, pfCancel);
505 } 599 }
506 600
507 601
@@ -2149,6 +2243,7 @@ private:
2149 BOOL fRet = FALSE; 2243 BOOL fRet = FALSE;
2150 MSG msg = { }; 2244 MSG msg = { };
2151 DWORD dwQuit = 0; 2245 DWORD dwQuit = 0;
2246 WM_WIXSTDBA firstAction = WM_WIXSTDBA_DETECT_PACKAGES;
2152 2247
2153 // Initialize COM and theme. 2248 // Initialize COM and theme.
2154 hr = ::CoInitialize(NULL); 2249 hr = ::CoInitialize(NULL);
@@ -2169,15 +2264,21 @@ private:
2169 if (FAILED(pThis->m_hrFinal)) 2264 if (FAILED(pThis->m_hrFinal))
2170 { 2265 {
2171 pThis->SetState(WIXSTDBA_STATE_FAILED, hr); 2266 pThis->SetState(WIXSTDBA_STATE_FAILED, hr);
2172 ::PostMessageW(pThis->m_hWnd, WM_WIXSTDBA_SHOW_FAILURE, 0, 0); 2267 firstAction = WM_WIXSTDBA_SHOW_FAILURE;
2173 } 2268 }
2174 else 2269 else
2175 { 2270 {
2176 // Okay, we're ready for packages now. 2271 // Okay, we're ready for packages now.
2177 pThis->SetState(WIXSTDBA_STATE_INITIALIZED, hr); 2272 pThis->SetState(WIXSTDBA_STATE_INITIALIZED, hr);
2178 ::PostMessageW(pThis->m_hWnd, BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action ? WM_WIXSTDBA_SHOW_HELP : WM_WIXSTDBA_DETECT_PACKAGES, 0, 0); 2273
2274 if (!pThis->m_fPreplanPrereqs && BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action)
2275 {
2276 firstAction = WM_WIXSTDBA_SHOW_HELP;
2277 }
2179 } 2278 }
2180 2279
2280 ::PostMessageW(pThis->m_hWnd, firstAction, 0, 0);
2281
2181 // message pump 2282 // message pump
2182 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) 2283 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
2183 { 2284 {
@@ -2647,7 +2748,7 @@ private:
2647 2748
2648 // Calculate the window style based on the theme style and command display value. 2749 // Calculate the window style based on the theme style and command display value.
2649 dwWindowStyle = m_pTheme->dwStyle; 2750 dwWindowStyle = m_pTheme->dwStyle;
2650 if (BOOTSTRAPPER_DISPLAY_NONE >= m_command.display) 2751 if (BOOTSTRAPPER_DISPLAY_NONE >= m_command.display || m_fPreplanPrereqs)
2651 { 2752 {
2652 dwWindowStyle &= ~WS_VISIBLE; 2753 dwWindowStyle &= ~WS_VISIBLE;
2653 } 2754 }
@@ -2850,6 +2951,10 @@ private:
2850 pBA->OnShowFailure(); 2951 pBA->OnShowFailure();
2851 return 0; 2952 return 0;
2852 2953
2954 case WM_WIXSTDBA_PLAN_PREREQS:
2955 pBA->OnPlanPrereqs(static_cast<BOOTSTRAPPER_ACTION>(lParam));
2956 return 0;
2957
2853 case WM_THMUTIL_CONTROL_WM_COMMAND: 2958 case WM_THMUTIL_CONTROL_WM_COMMAND:
2854 return pBA->OnThemeControlWmCommand(reinterpret_cast<THEME_CONTROLWMCOMMAND_ARGS*>(wParam), reinterpret_cast<THEME_CONTROLWMCOMMAND_RESULTS*>(lParam)); 2959 return pBA->OnThemeControlWmCommand(reinterpret_cast<THEME_CONTROLWMCOMMAND_ARGS*>(wParam), reinterpret_cast<THEME_CONTROLWMCOMMAND_RESULTS*>(lParam));
2855 2960
@@ -3141,6 +3246,30 @@ private:
3141 3246
3142 3247
3143 // 3248 //
3249 // OnPlanPrereqs - preplan the packages to see if the preqba can be skipped.
3250 //
3251 void OnPlanPrereqs(
3252 __in BOOTSTRAPPER_ACTION action
3253 )
3254 {
3255 HRESULT hr = S_OK;
3256
3257 m_plannedAction = action;
3258
3259 SetState(WIXSTDBA_STATE_PLANNING_PREREQS, hr);
3260
3261 hr = m_pEngine->Plan(action);
3262 BalExitOnFailure(hr, "Failed to start planning prereq packages.");
3263
3264 LExit:
3265 if (FAILED(hr))
3266 {
3267 SetState(WIXSTDBA_STATE_PLANNING_PREREQS, hr);
3268 }
3269 }
3270
3271
3272 //
3144 // OnApply - apply the packages. 3273 // OnApply - apply the packages.
3145 // 3274 //
3146 void OnApply() 3275 void OnApply()
@@ -3838,6 +3967,8 @@ LExit:
3838 break; 3967 break;
3839 3968
3840 case WIXSTDBA_STATE_DETECTED: __fallthrough; 3969 case WIXSTDBA_STATE_DETECTED: __fallthrough;
3970 case WIXSTDBA_STATE_PLANNING_PREREQS: __fallthrough;
3971 case WIXSTDBA_STATE_PLANNED_PREREQS: __fallthrough;
3841 case WIXSTDBA_STATE_PLANNING: __fallthrough; 3972 case WIXSTDBA_STATE_PLANNING: __fallthrough;
3842 case WIXSTDBA_STATE_PLANNED: __fallthrough; 3973 case WIXSTDBA_STATE_PLANNED: __fallthrough;
3843 case WIXSTDBA_STATE_APPLYING: __fallthrough; 3974 case WIXSTDBA_STATE_APPLYING: __fallthrough;
@@ -3874,6 +4005,8 @@ LExit:
3874 break; 4005 break;
3875 4006
3876 case WIXSTDBA_STATE_DETECTED: 4007 case WIXSTDBA_STATE_DETECTED:
4008 case WIXSTDBA_STATE_PLANNING_PREREQS: __fallthrough;
4009 case WIXSTDBA_STATE_PLANNED_PREREQS: __fallthrough;
3877 switch (m_command.action) 4010 switch (m_command.action)
3878 { 4011 {
3879 case BOOTSTRAPPER_ACTION_INSTALL: 4012 case BOOTSTRAPPER_ACTION_INSTALL:
@@ -4124,7 +4257,10 @@ public:
4124 4257
4125 m_pPrereqData = pPrereqData; 4258 m_pPrereqData = pPrereqData;
4126 m_fPrereq = NULL != pPrereqData; 4259 m_fPrereq = NULL != pPrereqData;
4260 m_fPreplanPrereqs = m_fPrereq && m_pPrereqData->fAlwaysInstallPrereqs;
4261 m_fPrereqPackagePlanned = FALSE;
4127 m_fPrereqInstalled = FALSE; 4262 m_fPrereqInstalled = FALSE;
4263 m_fPrereqSkipped = FALSE;
4128 4264
4129 pEngine->AddRef(); 4265 pEngine->AddRef();
4130 m_pEngine = pEngine; 4266 m_pEngine = pEngine;
@@ -4405,7 +4541,10 @@ private:
4405 4541
4406 PREQBA_DATA* m_pPrereqData; 4542 PREQBA_DATA* m_pPrereqData;
4407 BOOL m_fPrereq; 4543 BOOL m_fPrereq;
4544 BOOL m_fPreplanPrereqs;
4545 BOOL m_fPrereqPackagePlanned;
4408 BOOL m_fPrereqInstalled; 4546 BOOL m_fPrereqInstalled;
4547 BOOL m_fPrereqSkipped;
4409 4548
4410 ITaskbarList3* m_pTaskbarList; 4549 ITaskbarList3* m_pTaskbarList;
4411 UINT m_uTaskbarButtonCreatedMessage; 4550 UINT m_uTaskbarButtonCreatedMessage;
diff --git a/src/ext/Bal/wixstdba/inc/preqba.h b/src/ext/Bal/wixstdba/inc/preqba.h
index 93a547ed..ed339730 100644
--- a/src/ext/Bal/wixstdba/inc/preqba.h
+++ b/src/ext/Bal/wixstdba/inc/preqba.h
@@ -5,6 +5,7 @@
5struct PREQBA_DATA 5struct PREQBA_DATA
6{ 6{
7 HRESULT hrHostInitialization; 7 HRESULT hrHostInitialization;
8 BOOL fAlwaysInstallPrereqs;
8 BOOL fCompleted; 9 BOOL fCompleted;
9}; 10};
10 11
diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs
index 1548c05b..9ca82377 100644
--- a/src/test/burn/TestBA/TestBA.cs
+++ b/src/test/burn/TestBA/TestBA.cs
@@ -146,6 +146,13 @@ namespace WixToolset.Test.BA
146 146
147 this.wait.WaitOne(); 147 this.wait.WaitOne();
148 148
149 if (this.action == LaunchAction.Help)
150 {
151 this.Log("This is a BA for automated testing");
152 this.Engine.Quit(0);
153 return;
154 }
155
149 this.redetectRemaining = redetectCount; 156 this.redetectRemaining = redetectCount;
150 for (int i = -1; i < redetectCount; i++) 157 for (int i = -1; i < redetectCount; i++)
151 { 158 {
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj
index 0199f91f..b084997c 100644
--- a/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj
+++ b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj
@@ -13,9 +13,12 @@
13 </ItemGroup> 13 </ItemGroup>
14 <ItemGroup> 14 <ItemGroup>
15 <ProjectReference Include="..\PackageA\PackageA.wixproj" /> 15 <ProjectReference Include="..\PackageA\PackageA.wixproj" />
16 <ProjectReference Include="..\PackageF\PackageF.wixproj" /> 16 <ProjectReference Include="..\PackageC\PackageC.wixproj" />
17 <ProjectReference Include="..\PrereqBaf\PrereqBaf.vcxproj" />
18 <ProjectReference Include="..\ReplaceConfig\ReplaceConfig.vcxproj" />
17 </ItemGroup> 19 </ItemGroup>
18 <ItemGroup> 20 <ItemGroup>
19 <PackageReference Include="WixToolset.Bal.wixext" /> 21 <PackageReference Include="WixToolset.Bal.wixext" />
22 <PackageReference Include="WixToolset.Util.wixext" />
20 </ItemGroup> 23 </ItemGroup>
21</Project> \ No newline at end of file 24</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs
index 682f0bd7..6073e09f 100644
--- a/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs
+++ b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs
@@ -1,22 +1,30 @@
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. --> 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 2
3 3
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal"> 4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
5 <Fragment> 5 <Fragment>
6 <BootstrapperApplication Id="BrokenDnc"> 6 <BootstrapperApplication Id="BrokenDnc">
7 <Payload SourceFile="!(bindpath.dncx86)\TestBA.deps.json" /> 7 <Payload SourceFile="!(bindpath.dncx86)\TestBA.deps.json" />
8 <Payload SourceFile="!(bindpath.dncx86)\TestBA.dll" bal:BAFactoryAssembly="yes" /> 8 <Payload SourceFile="!(bindpath.dncx86)\TestBA.dll" bal:BAFactoryAssembly="yes" />
9 <Payload Name="good.runtimeconfig.json" SourceFile="!(bindpath.dncx86)\TestBA.runtimeconfig.json" />
9 <Payload Name="TestBA.runtimeconfig.json" SourceFile="bad.runtimeconfig.json" /> 10 <Payload Name="TestBA.runtimeconfig.json" SourceFile="bad.runtimeconfig.json" />
10 <Payload SourceFile="!(bindpath.dncx86)\mbanative.dll" /> 11 <Payload SourceFile="!(bindpath.dncx86)\mbanative.dll" />
11 <Payload SourceFile="!(bindpath.dncx86)\WixToolset.Mba.Core.dll" /> 12 <Payload SourceFile="!(bindpath.dncx86)\WixToolset.Mba.Core.dll" />
13 <Payload SourceFile="$(var.PrereqBaf.TargetPath)" bal:BAFunctions="yes" />
12 <bal:WixDotNetCoreBootstrapperApplicationHost /> 14 <bal:WixDotNetCoreBootstrapperApplicationHost />
13 </BootstrapperApplication> 15 </BootstrapperApplication>
14 </Fragment> 16 </Fragment>
15 17
16 <Fragment> 18 <Fragment>
19 <util:FileSearch Variable="GoodConfigPresent" Path="[BARuntimeDirectory]\good.runtimeconfig.json" Result="exists" />
20 <Variable Name="CAUSEINFINITELOOP" bal:Overridable="yes" />
21
17 <PackageGroup Id="BundlePackages"> 22 <PackageGroup Id="BundlePackages">
23 <ExePackage SourceFile="$(var.ReplaceConfig.TargetPath)" bal:PrereqPackage="yes"
24 Permanent="yes" DetectCondition="NOT GoodConfigPresent OR CAUSEINFINITELOOP = 1"
25 InstallArguments="&quot;[BARuntimeDirectory]TestBA.runtimeconfig.json&quot; &quot;[BARuntimeDirectory]good.runtimeconfig.json&quot; &quot;[BARuntimeDirectory]bad.runtimeconfig.json&quot;" />
18 <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" bal:PrereqPackage="yes" Permanent="yes" /> 26 <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" bal:PrereqPackage="yes" Permanent="yes" />
19 <MsiPackage Id="PackageF" SourceFile="$(var.PackageF.TargetPath)" Cache="force" /> 27 <MsiPackage Id="PackageC" SourceFile="$(var.PackageC.TargetPath)" Cache="force" />
20 </PackageGroup> 28 </PackageGroup>
21 </Fragment> 29 </Fragment>
22</Wix> 30</Wix>
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj
index d4288d4b..843b382a 100644
--- a/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj
+++ b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj
@@ -13,9 +13,12 @@
13 </ItemGroup> 13 </ItemGroup>
14 <ItemGroup> 14 <ItemGroup>
15 <ProjectReference Include="..\PackageB\PackageB.wixproj" /> 15 <ProjectReference Include="..\PackageB\PackageB.wixproj" />
16 <ProjectReference Include="..\PackageF\PackageF.wixproj" /> 16 <ProjectReference Include="..\PackageC\PackageC.wixproj" />
17 <ProjectReference Include="..\PrereqBaf\PrereqBaf.vcxproj" />
18 <ProjectReference Include="..\ReplaceConfig\ReplaceConfig.vcxproj" />
17 </ItemGroup> 19 </ItemGroup>
18 <ItemGroup> 20 <ItemGroup>
19 <PackageReference Include="WixToolset.Bal.wixext" /> 21 <PackageReference Include="WixToolset.Bal.wixext" />
22 <PackageReference Include="WixToolset.Util.wixext" />
20 </ItemGroup> 23 </ItemGroup>
21</Project> \ No newline at end of file 24</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs
index 603c3aee..b7742582 100644
--- a/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs
+++ b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs
@@ -1,21 +1,29 @@
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. --> 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 2
3 3
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal"> 4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
5 <Fragment> 5 <Fragment>
6 <BootstrapperApplication Id="BrokenMba"> 6 <BootstrapperApplication Id="BrokenMba">
7 <Payload Name="good.config" SourceFile="!(bindpath.net2x86)\TestBA.BootstrapperCore.config" />
7 <Payload Name="WixToolset.Mba.Host.config" SourceFile="bad.config" /> 8 <Payload Name="WixToolset.Mba.Host.config" SourceFile="bad.config" />
8 <Payload SourceFile="!(bindpath.net2x86)\TestBA.dll" /> 9 <Payload SourceFile="!(bindpath.net2x86)\TestBA.dll" />
9 <Payload SourceFile="!(bindpath.net2x86)\mbanative.dll" /> 10 <Payload SourceFile="!(bindpath.net2x86)\mbanative.dll" />
10 <Payload SourceFile="!(bindpath.net2x86)\WixToolset.Mba.Core.dll" /> 11 <Payload SourceFile="!(bindpath.net2x86)\WixToolset.Mba.Core.dll" />
12 <Payload SourceFile="$(var.PrereqBaf.TargetPath)" bal:BAFunctions="yes" />
11 <bal:WixManagedBootstrapperApplicationHost /> 13 <bal:WixManagedBootstrapperApplicationHost />
12 </BootstrapperApplication> 14 </BootstrapperApplication>
13 </Fragment> 15 </Fragment>
14 16
15 <Fragment> 17 <Fragment>
18 <util:FileSearch Variable="GoodConfigPresent" Path="[BARuntimeDirectory]\good.config" Result="exists" />
19 <Variable Name="CAUSEINFINITELOOP" bal:Overridable="yes" />
20
16 <PackageGroup Id="BundlePackages"> 21 <PackageGroup Id="BundlePackages">
22 <ExePackage SourceFile="$(var.ReplaceConfig.TargetPath)" bal:PrereqPackage="yes"
23 Permanent="yes" DetectCondition="NOT GoodConfigPresent OR CAUSEINFINITELOOP = 1"
24 InstallArguments="&quot;[BARuntimeDirectory]WixToolset.Mba.Host.config&quot; &quot;[BARuntimeDirectory]good.config&quot; &quot;[BARuntimeDirectory]bad.config&quot;" />
17 <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" bal:PrereqPackage="yes" Permanent="yes" /> 25 <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" bal:PrereqPackage="yes" Permanent="yes" />
18 <MsiPackage Id="PackageF" SourceFile="$(var.PackageF.TargetPath)" /> 26 <MsiPackage Id="PackageC" SourceFile="$(var.PackageC.TargetPath)" />
19 </PackageGroup> 27 </PackageGroup>
20 </Fragment> 28 </Fragment>
21</Wix> 29</Wix>
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wixproj b/src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wixproj
new file mode 100644
index 00000000..81641f66
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wixproj
@@ -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<Project Sdk="WixToolset.Sdk">
3 <PropertyGroup>
4 <OutputType>Bundle</OutputType>
5 <BA>BrokenDncAlwaysPrereq</BA>
6 <UpgradeCode>{D2763AB7-979B-485C-AE52-DD03C23CCB93}</UpgradeCode>
7 </PropertyGroup>
8 <ItemGroup>
9 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
10 </ItemGroup>
11 <ItemGroup>
12 <BindInputPaths Include="$(BaseOutputPath)$(Configuration)\net6.0-windows\win-x86" BindName="dncx86" />
13 </ItemGroup>
14 <ItemGroup>
15 <ProjectReference Include="..\PackageA\PackageA.wixproj" />
16 <ProjectReference Include="..\PackageC\PackageC.wixproj" />
17 <ProjectReference Include="..\PrereqBaf\PrereqBaf.vcxproj" />
18 <ProjectReference Include="..\ReplaceConfig\ReplaceConfig.vcxproj" />
19 </ItemGroup>
20 <ItemGroup>
21 <PackageReference Include="WixToolset.Bal.wixext" />
22 <PackageReference Include="WixToolset.Util.wixext" />
23 </ItemGroup>
24</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wxs b/src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wxs
new file mode 100644
index 00000000..fe9425f7
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleC/BundleC.wxs
@@ -0,0 +1,30 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
5 <Fragment>
6 <BootstrapperApplication Id="BrokenDncAlwaysPrereq">
7 <Payload SourceFile="!(bindpath.dncx86)\TestBA.deps.json" />
8 <Payload SourceFile="!(bindpath.dncx86)\TestBA.dll" bal:BAFactoryAssembly="yes" />
9 <Payload Name="good.runtimeconfig.json" SourceFile="!(bindpath.dncx86)\TestBA.runtimeconfig.json" />
10 <Payload Name="TestBA.runtimeconfig.json" SourceFile="bad.runtimeconfig.json" />
11 <Payload SourceFile="!(bindpath.dncx86)\mbanative.dll" />
12 <Payload SourceFile="!(bindpath.dncx86)\WixToolset.Mba.Core.dll" />
13 <Payload SourceFile="$(var.PrereqBaf.TargetPath)" bal:BAFunctions="yes" />
14 <bal:WixDotNetCoreBootstrapperApplicationHost AlwaysInstallPrereqs="yes" />
15 </BootstrapperApplication>
16 </Fragment>
17
18 <Fragment>
19 <util:FileSearch Variable="GoodConfigPresent" Path="[BARuntimeDirectory]\good.runtimeconfig.json" Result="exists" />
20 <Variable Name="CAUSEINFINITELOOP" bal:Overridable="yes" />
21
22 <PackageGroup Id="BundlePackages">
23 <ExePackage SourceFile="$(var.ReplaceConfig.TargetPath)" bal:PrereqPackage="yes"
24 Permanent="yes" DetectCondition="NOT GoodConfigPresent OR CAUSEINFINITELOOP = 1"
25 InstallArguments="&quot;[BARuntimeDirectory]TestBA.runtimeconfig.json&quot; &quot;[BARuntimeDirectory]good.runtimeconfig.json&quot; &quot;[BARuntimeDirectory]bad.runtimeconfig.json&quot;" />
26 <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" bal:PrereqPackage="yes" Permanent="yes" />
27 <MsiPackage Id="PackageC" SourceFile="$(var.PackageC.TargetPath)" Cache="force" />
28 </PackageGroup>
29 </Fragment>
30</Wix>
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleC/bad.runtimeconfig.json b/src/test/burn/TestData/PrereqBaTests/BundleC/bad.runtimeconfig.json
new file mode 100644
index 00000000..07a1a830
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleC/bad.runtimeconfig.json
@@ -0,0 +1,10 @@
1{
2 "runtimeOptions": {
3 "tfm": "net5.5",
4 "rollForward": "Disable",
5 "framework": {
6 "name": "Microsoft.WindowsDesktop.App",
7 "version": "5.5.0"
8 }
9 }
10} \ No newline at end of file
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wixproj b/src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wixproj
new file mode 100644
index 00000000..314fe2e2
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wixproj
@@ -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<Project Sdk="WixToolset.Sdk">
3 <PropertyGroup>
4 <OutputType>Bundle</OutputType>
5 <BA>BrokenMbaAlwaysPrereq</BA>
6 <UpgradeCode>{415CA128-60E1-4D16-ACE8-A1D43E98B997}</UpgradeCode>
7 </PropertyGroup>
8 <ItemGroup>
9 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
10 </ItemGroup>
11 <ItemGroup>
12 <BindInputPaths Include="$(BaseOutputPath)$(Configuration)\net35\win-x86" BindName="net2x86" />
13 </ItemGroup>
14 <ItemGroup>
15 <ProjectReference Include="..\PackageB\PackageB.wixproj" />
16 <ProjectReference Include="..\PackageC\PackageC.wixproj" />
17 <ProjectReference Include="..\PrereqBaf\PrereqBaf.vcxproj" />
18 <ProjectReference Include="..\ReplaceConfig\ReplaceConfig.vcxproj" />
19 </ItemGroup>
20 <ItemGroup>
21 <PackageReference Include="WixToolset.Bal.wixext" />
22 <PackageReference Include="WixToolset.Util.wixext" />
23 </ItemGroup>
24</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wxs b/src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wxs
new file mode 100644
index 00000000..0e866295
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleD/BundleD.wxs
@@ -0,0 +1,29 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
5 <Fragment>
6 <BootstrapperApplication Id="BrokenMbaAlwaysPrereq">
7 <Payload Name="good.config" SourceFile="!(bindpath.net2x86)\TestBA.BootstrapperCore.config" />
8 <Payload Name="WixToolset.Mba.Host.config" SourceFile="bad.config" />
9 <Payload SourceFile="!(bindpath.net2x86)\TestBA.dll" />
10 <Payload SourceFile="!(bindpath.net2x86)\mbanative.dll" />
11 <Payload SourceFile="!(bindpath.net2x86)\WixToolset.Mba.Core.dll" />
12 <Payload SourceFile="$(var.PrereqBaf.TargetPath)" bal:BAFunctions="yes" />
13 <bal:WixManagedBootstrapperApplicationHost AlwaysInstallPrereqs="yes" />
14 </BootstrapperApplication>
15 </Fragment>
16
17 <Fragment>
18 <util:FileSearch Variable="GoodConfigPresent" Path="[BARuntimeDirectory]\good.config" Result="exists" />
19 <Variable Name="CAUSEINFINITELOOP" bal:Overridable="yes" />
20
21 <PackageGroup Id="BundlePackages">
22 <ExePackage SourceFile="$(var.ReplaceConfig.TargetPath)" bal:PrereqPackage="yes"
23 Permanent="yes" DetectCondition="NOT GoodConfigPresent OR CAUSEINFINITELOOP = 1"
24 InstallArguments="&quot;[BARuntimeDirectory]WixToolset.Mba.Host.config&quot; &quot;[BARuntimeDirectory]good.config&quot; &quot;[BARuntimeDirectory]bad.config&quot;" />
25 <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" bal:PrereqPackage="yes" Permanent="yes" />
26 <MsiPackage Id="PackageC" SourceFile="$(var.PackageC.TargetPath)" />
27 </PackageGroup>
28 </Fragment>
29</Wix>
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleD/bad.config b/src/test/burn/TestData/PrereqBaTests/BundleD/bad.config
new file mode 100644
index 00000000..1512e59a
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleD/bad.config
@@ -0,0 +1,17 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<!-- 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. -->
3
4
5<configuration>
6 <configSections>
7 <sectionGroup name="wix.bootstrapper" type="WixToolset.Mba.Host.BootstrapperSectionGroup, WixToolset.Mba.Host">
8 <section name="host" type="WixToolset.Mba.Host.HostSection, WixToolset.Mba.Host" />
9 </sectionGroup>
10 </configSections>
11 <startup>
12 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v5.8" />
13 </startup>
14 <wix.bootstrapper>
15 <host assemblyName="TestBA" />
16 </wix.bootstrapper>
17</configuration>
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wixproj b/src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wixproj
new file mode 100644
index 00000000..5d271f55
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wixproj
@@ -0,0 +1,22 @@
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 <BA>DncAlwaysPrereq</BA>
6 <UpgradeCode>{2F61ECD8-C28B-4FF9-9609-0E9633716CF9}</UpgradeCode>
7 </PropertyGroup>
8 <ItemGroup>
9 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
10 </ItemGroup>
11 <ItemGroup>
12 <BindInputPaths Include="$(BaseOutputPath)$(Configuration)\net6.0-windows\win-x86" BindName="dncx86" />
13 </ItemGroup>
14 <ItemGroup>
15 <ProjectReference Include="..\PrereqBaf\PrereqBaf.vcxproj" />
16 <ProjectReference Include="..\ReplaceConfig\ReplaceConfig.vcxproj" />
17 </ItemGroup>
18 <ItemGroup>
19 <PackageReference Include="WixToolset.Bal.wixext" />
20 <PackageReference Include="WixToolset.Util.wixext" />
21 </ItemGroup>
22</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wxs b/src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wxs
new file mode 100644
index 00000000..5f2e6a75
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/BundleE/BundleE.wxs
@@ -0,0 +1,26 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
5 <Fragment>
6 <BootstrapperApplication Id="DncAlwaysPrereq">
7 <Payload SourceFile="!(bindpath.dncx86)\TestBA.deps.json" />
8 <Payload SourceFile="!(bindpath.dncx86)\TestBA.dll" bal:BAFactoryAssembly="yes" />
9 <Payload SourceFile="!(bindpath.dncx86)\TestBA.runtimeconfig.json" />
10 <Payload SourceFile="!(bindpath.dncx86)\mbanative.dll" />
11 <Payload SourceFile="!(bindpath.dncx86)\WixToolset.Mba.Core.dll" />
12 <Payload SourceFile="$(var.PrereqBaf.TargetPath)" bal:BAFunctions="yes" />
13 <bal:WixDotNetCoreBootstrapperApplicationHost AlwaysInstallPrereqs="yes" />
14 </BootstrapperApplication>
15 </Fragment>
16
17 <Fragment>
18 <util:FileSearch Variable="GoodConfigPresent" Path="[BARuntimeDirectory]\good.runtimeconfig.json" Result="exists" />
19
20 <PackageGroup Id="BundlePackages">
21 <ExePackage SourceFile="$(var.ReplaceConfig.TargetPath)" bal:PrereqPackage="yes"
22 Permanent="yes" DetectCondition="NOT GoodConfigPresent"
23 InstallArguments="&quot;[BARuntimeDirectory]TestBA.runtimeconfig.json&quot; &quot;[BARuntimeDirectory]good.runtimeconfig.json&quot; &quot;[BARuntimeDirectory]bad.runtimeconfig.json&quot;" />
24 </PackageGroup>
25 </Fragment>
26</Wix>
diff --git a/src/test/burn/TestData/PrereqBaTests/PackageF/PackageF.wixproj b/src/test/burn/TestData/PrereqBaTests/PackageC/PackageC.wixproj
index 00ffb7d8..1c8c4fa8 100644
--- a/src/test/burn/TestData/PrereqBaTests/PackageF/PackageF.wixproj
+++ b/src/test/burn/TestData/PrereqBaTests/PackageC/PackageC.wixproj
@@ -4,9 +4,6 @@
4 <UpgradeCode>{7DEEE928-CD7F-49AD-8000-2ED6339D8A78}</UpgradeCode> 4 <UpgradeCode>{7DEEE928-CD7F-49AD-8000-2ED6339D8A78}</UpgradeCode>
5 </PropertyGroup> 5 </PropertyGroup>
6 <ItemGroup> 6 <ItemGroup>
7 <Compile Include="..\..\Templates\PackageFail.wxs" Link="PackageFail.wxs" /> 7 <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
8 </ItemGroup>
9 <ItemGroup>
10 <PackageReference Include="WixToolset.Util.wixext" />
11 </ItemGroup> 8 </ItemGroup>
12</Project> \ No newline at end of file 9</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.cpp b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.cpp
new file mode 100644
index 00000000..35949eb9
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.cpp
@@ -0,0 +1,79 @@
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#include "precomp.h"
4#include "BalBaseBAFunctions.h"
5#include "BalBaseBAFunctionsProc.h"
6
7class CPrereqBaf : public CBalBaseBAFunctions
8{
9public: // IBAFunctions
10
11public: //IBootstrapperApplication
12
13 virtual STDMETHODIMP OnDetectBegin(
14 __in BOOL /*fCached*/,
15 __in BOOTSTRAPPER_REGISTRATION_TYPE /*registrationType*/,
16 __in DWORD /*cPackages*/,
17 __inout BOOL* /*pfCancel*/
18 )
19 {
20 HRESULT hr = S_OK;
21
22 hr = m_pEngine->SetVariableString(L"BARuntimeDirectory", m_command.wzBootstrapperWorkingFolder, FALSE);
23 ExitOnFailure(hr, "Failed to set BARuntimeDirectory");
24
25 LExit:
26 return hr;
27 }
28
29private:
30
31public:
32 //
33 // Constructor - initialize member variables.
34 //
35 CPrereqBaf(
36 __in HMODULE hModule,
37 __in IBootstrapperEngine* pEngine,
38 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs
39 ) : CBalBaseBAFunctions(hModule, pEngine, pArgs)
40 {
41 }
42
43 //
44 // Destructor - release member variables.
45 //
46 ~CPrereqBaf()
47 {
48 }
49
50private:
51};
52
53
54HRESULT WINAPI CreateBAFunctions(
55 __in HMODULE hModule,
56 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs,
57 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults
58 )
59{
60 HRESULT hr = S_OK;
61 CPrereqBaf* pBAFunctions = NULL;
62 IBootstrapperEngine* pEngine = NULL;
63
64 hr = BalInitializeFromCreateArgs(pArgs->pBootstrapperCreateArgs, &pEngine);
65 ExitOnFailure(hr, "Failed to initialize Bal.");
66
67 pBAFunctions = new CPrereqBaf(hModule, pEngine, pArgs);
68 ExitOnNull(pBAFunctions, hr, E_OUTOFMEMORY, "Failed to create new CPrereqBaf object.");
69
70 pResults->pfnBAFunctionsProc = BalBaseBAFunctionsProc;
71 pResults->pvBAFunctionsProcContext = pBAFunctions;
72 pBAFunctions = NULL;
73
74LExit:
75 ReleaseObject(pBAFunctions);
76 ReleaseObject(pEngine);
77
78 return hr;
79}
diff --git a/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.def b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.def
new file mode 100644
index 00000000..6e016dad
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.def
@@ -0,0 +1,6 @@
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
4EXPORTS
5 BAFunctionsCreate
6 BAFunctionsDestroy
diff --git a/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.vcxproj b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.vcxproj
new file mode 100644
index 00000000..0d8d63be
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/PrereqBaf.vcxproj
@@ -0,0 +1,66 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project DefaultTargets="Build" Toolsxmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|ARM64">
7 <Configuration>Debug</Configuration>
8 <Platform>ARM64</Platform>
9 </ProjectConfiguration>
10 <ProjectConfiguration Include="Release|ARM64">
11 <Configuration>Release</Configuration>
12 <Platform>ARM64</Platform>
13 </ProjectConfiguration>
14 <ProjectConfiguration Include="Debug|Win32">
15 <Configuration>Debug</Configuration>
16 <Platform>Win32</Platform>
17 </ProjectConfiguration>
18 <ProjectConfiguration Include="Release|Win32">
19 <Configuration>Release</Configuration>
20 <Platform>Win32</Platform>
21 </ProjectConfiguration>
22 <ProjectConfiguration Include="Debug|x64">
23 <Configuration>Debug</Configuration>
24 <Platform>x64</Platform>
25 </ProjectConfiguration>
26 <ProjectConfiguration Include="Release|x64">
27 <Configuration>Release</Configuration>
28 <Platform>x64</Platform>
29 </ProjectConfiguration>
30 </ItemGroup>
31
32 <PropertyGroup Label="Globals">
33 <ProjectGuid>{C0A11DDB-6CCE-44EC-88FD-93910C2916E3}</ProjectGuid>
34 <ConfigurationType>DynamicLibrary</ConfigurationType>
35 <CharacterSet>Unicode</CharacterSet>
36 <TargetName>PrereqBaf</TargetName>
37 <ProjectModuleDefinitionFile>PrereqBaf.def</ProjectModuleDefinitionFile>
38 <IsWixTestProject>true</IsWixTestProject>
39 </PropertyGroup>
40
41 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
42 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
43
44 <PropertyGroup>
45 <ProjectAdditionalLinkLibraries>comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib</ProjectAdditionalLinkLibraries>
46 </PropertyGroup>
47
48 <ItemGroup>
49 <ClCompile Include="precomp.cpp">
50 <PrecompiledHeader>Create</PrecompiledHeader>
51 </ClCompile>
52 <ClCompile Include="PrereqBaf.cpp" />
53 </ItemGroup>
54 <ItemGroup>
55 <ClInclude Include="precomp.h" />
56 </ItemGroup>
57 <ItemGroup>
58 <None Include="PrereqBaf.def" />
59 </ItemGroup>
60
61 <ItemGroup>
62 <PackageReference Include="WixToolset.BalUtil" />
63 </ItemGroup>
64
65 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
66</Project>
diff --git a/src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.cpp b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.cpp
new file mode 100644
index 00000000..fc9d1177
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.cpp
@@ -0,0 +1,48 @@
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#include "precomp.h"
4
5static HINSTANCE vhInstance = NULL;
6
7extern "C" BOOL WINAPI DllMain(
8 IN HINSTANCE hInstance,
9 IN DWORD dwReason,
10 IN LPVOID /* pvReserved */
11 )
12{
13 switch (dwReason)
14 {
15 case DLL_PROCESS_ATTACH:
16 ::DisableThreadLibraryCalls(hInstance);
17 vhInstance = hInstance;
18 break;
19
20 case DLL_PROCESS_DETACH:
21 vhInstance = NULL;
22 break;
23 }
24
25 return TRUE;
26}
27
28extern "C" HRESULT WINAPI BAFunctionsCreate(
29 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs,
30 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults
31 )
32{
33 HRESULT hr = S_OK;
34
35 hr = CreateBAFunctions(vhInstance, pArgs, pResults);
36 BalExitOnFailure(hr, "Failed to create BAFunctions interface.");
37
38LExit:
39 return hr;
40}
41
42extern "C" void WINAPI BAFunctionsDestroy(
43 __in const BA_FUNCTIONS_DESTROY_ARGS* /*pArgs*/,
44 __inout BA_FUNCTIONS_DESTROY_RESULTS* /*pResults*/
45 )
46{
47 BalUninitialize();
48}
diff --git a/src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.h b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.h
new file mode 100644
index 00000000..8320bdd8
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/PrereqBaf/precomp.h
@@ -0,0 +1,31 @@
1#pragma once
2// 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.
3
4
5#include <windows.h>
6#include <msiquery.h>
7#include <objbase.h>
8#include <shlobj.h>
9#include <shlwapi.h>
10#include <stdlib.h>
11#include <strsafe.h>
12#include <CommCtrl.h>
13
14#include "dutil.h"
15#include "dictutil.h"
16#include "fileutil.h"
17#include "locutil.h"
18#include "pathutil.h"
19#include "strutil.h"
20
21#include "BalBaseBootstrapperApplication.h"
22#include "balutil.h"
23
24#include "BAFunctions.h"
25#include "IBAFunctions.h"
26
27HRESULT WINAPI CreateBAFunctions(
28 __in HMODULE hModule,
29 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs,
30 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults
31 );
diff --git a/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.cpp b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.cpp
new file mode 100644
index 00000000..1fa71bc2
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.cpp
@@ -0,0 +1,33 @@
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#include "precomp.h"
4
5int __cdecl wmain(
6 __in int argc,
7 __in LPWSTR argv[]
8 )
9{
10 HRESULT hr = S_OK;
11 DWORD dwExitCode = 0;
12 LPCWSTR wzDestinationFile = argc > 1 ? argv[1] : NULL;
13 LPCWSTR wzGoodFile = argc > 2 ? argv[2] : NULL;
14 LPCWSTR wzBadFile = argc > 3 ? argv[3] : NULL;
15
16 if (argc != 4)
17 {
18 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid args");
19 }
20
21 if (!::MoveFileW(wzDestinationFile, wzBadFile))
22 {
23 ExitWithLastError(hr, "Failed to move bad file");
24 }
25
26 if (!::MoveFileW(wzGoodFile, wzDestinationFile))
27 {
28 ExitWithLastError(hr, "Failed to move good file");
29 }
30
31LExit:
32 return FAILED(hr) ? (int)hr : (int)dwExitCode;
33}
diff --git a/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.vcxproj b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.vcxproj
new file mode 100644
index 00000000..c5d7b046
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/ReplaceConfig.vcxproj
@@ -0,0 +1,63 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project DefaultTargets="Build" Toolsxmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|ARM64">
7 <Configuration>Debug</Configuration>
8 <Platform>ARM64</Platform>
9 </ProjectConfiguration>
10 <ProjectConfiguration Include="Release|ARM64">
11 <Configuration>Release</Configuration>
12 <Platform>ARM64</Platform>
13 </ProjectConfiguration>
14 <ProjectConfiguration Include="Debug|Win32">
15 <Configuration>Debug</Configuration>
16 <Platform>Win32</Platform>
17 </ProjectConfiguration>
18 <ProjectConfiguration Include="Release|Win32">
19 <Configuration>Release</Configuration>
20 <Platform>Win32</Platform>
21 </ProjectConfiguration>
22 <ProjectConfiguration Include="Debug|x64">
23 <Configuration>Debug</Configuration>
24 <Platform>x64</Platform>
25 </ProjectConfiguration>
26 <ProjectConfiguration Include="Release|x64">
27 <Configuration>Release</Configuration>
28 <Platform>x64</Platform>
29 </ProjectConfiguration>
30 </ItemGroup>
31
32 <PropertyGroup Label="Globals">
33 <ProjectGuid>{3D10A07D-3321-4F8E-B884-951F8FB5D636}</ProjectGuid>
34 <ConfigurationType>Application</ConfigurationType>
35 <ProjectSubSystem>Console</ProjectSubSystem>
36 <CharacterSet>Unicode</CharacterSet>
37 <TargetName>ReplaceConfig</TargetName>
38 <IsWixTestProject>true</IsWixTestProject>
39 </PropertyGroup>
40
41 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
42 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
43
44 <PropertyGroup>
45 <ProjectAdditionalLinkLibraries>comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib</ProjectAdditionalLinkLibraries>
46 </PropertyGroup>
47
48 <ItemGroup>
49 <ClCompile Include="precomp.cpp">
50 <PrecompiledHeader>Create</PrecompiledHeader>
51 </ClCompile>
52 <ClCompile Include="ReplaceConfig.cpp" />
53 </ItemGroup>
54 <ItemGroup>
55 <ClInclude Include="precomp.h" />
56 </ItemGroup>
57
58 <ItemGroup>
59 <PackageReference Include="WixToolset.DUtil" />
60 </ItemGroup>
61
62 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
63</Project>
diff --git a/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.cpp b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.cpp
@@ -0,0 +1,3 @@
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#include "precomp.h"
diff --git a/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.h b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.h
new file mode 100644
index 00000000..f4180c2e
--- /dev/null
+++ b/src/test/burn/TestData/PrereqBaTests/ReplaceConfig/precomp.h
@@ -0,0 +1,17 @@
1#pragma once
2// 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.
3
4
5#include <windows.h>
6#include <msiquery.h>
7#include <objbase.h>
8#include <shlobj.h>
9#include <shlwapi.h>
10#include <stdlib.h>
11#include <strsafe.h>
12#include <CommCtrl.h>
13
14#include "dutil.h"
15#include "fileutil.h"
16#include "pathutil.h"
17#include "strutil.h"
diff --git a/src/test/burn/WixTestTools/BundleInstaller.cs b/src/test/burn/WixTestTools/BundleInstaller.cs
index 2b449ebf..0ab02d1b 100644
--- a/src/test/burn/WixTestTools/BundleInstaller.cs
+++ b/src/test/burn/WixTestTools/BundleInstaller.cs
@@ -27,6 +27,20 @@ namespace WixTestTools
27 public string TestName { get; } 27 public string TestName { get; }
28 28
29 /// <summary> 29 /// <summary>
30 /// Runs the bundle asking for help.
31 /// </summary>
32 /// <param name="expectedExitCode">Expected exit code, defaults to success.</param>
33 /// <param name="arguments">Optional arguments to pass to the tool.</param>
34 /// <returns>Path to the generated log file.</returns>
35 public string Help(int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments)
36 {
37 var newArgumentList = new List<string>();
38 newArgumentList.Add("-help");
39 newArgumentList.AddRange(arguments);
40 return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Custom, newArgumentList.ToArray());
41 }
42
43 /// <summary>
30 /// Installs the bundle with optional arguments. 44 /// Installs the bundle with optional arguments.
31 /// </summary> 45 /// </summary>
32 /// <param name="expectedExitCode">Expected exit code, defaults to success.</param> 46 /// <param name="expectedExitCode">Expected exit code, defaults to success.</param>
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs
index 52e165b4..d958b454 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs
@@ -18,6 +18,39 @@ namespace WixToolsetTest.BurnE2E
18 /// This bundle purposely provides a .runtimeconfig.json file that requires a version of .NET Core that doesn't exist, 18 /// This bundle purposely provides a .runtimeconfig.json file that requires a version of .NET Core that doesn't exist,
19 /// with an MSI package to represent the prerequisite package. 19 /// with an MSI package to represent the prerequisite package.
20 /// This verifies that: 20 /// This verifies that:
21 /// The preqba doesn't infinitely try to install prereqs.
22 /// The engine automatically uninstalls the bundle since only permanent packages were installed.
23 /// </summary>
24 [RuntimeFact]
25 public void DncAlwaysPreqBaDetectsInfiniteLoop()
26 {
27 var packageA = this.CreatePackageInstaller("PackageA");
28 var packageC = this.CreatePackageInstaller("PackageC");
29
30 var bundleC = this.CreateBundleInstaller("BundleC");
31
32 var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
33
34 // Source file should *not* be installed
35 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
36 packageC.VerifyInstalled(false);
37
38 bundleC.Install(E_PREREQBA_INFINITE_LOOP, "CAUSEINFINITELOOP=1");
39
40 // Part of the test is Install actually completing.
41
42 // Source file should be installed
43 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
44 packageC.VerifyInstalled(false);
45
46 // No non-permanent packages should have ended up installed or cached so it should have unregistered.
47 bundleC.VerifyUnregisteredAndRemovedFromPackageCache();
48 }
49
50 /// <summary>
51 /// This bundle purposely provides a .runtimeconfig.json file that requires a version of .NET Core that doesn't exist,
52 /// with an MSI package to represent the prerequisite package.
53 /// This verifies that:
21 /// The preqba doesn't infinitely reload itself after failing to load the managed BA. 54 /// The preqba doesn't infinitely reload itself after failing to load the managed BA.
22 /// The engine automatically uninstalls the bundle since only permanent packages were installed. 55 /// The engine automatically uninstalls the bundle since only permanent packages were installed.
23 /// </summary> 56 /// </summary>
@@ -25,7 +58,7 @@ namespace WixToolsetTest.BurnE2E
25 public void DncPreqBaDetectsInfiniteLoop() 58 public void DncPreqBaDetectsInfiniteLoop()
26 { 59 {
27 var packageA = this.CreatePackageInstaller("PackageA"); 60 var packageA = this.CreatePackageInstaller("PackageA");
28 this.CreatePackageInstaller("PackageF"); 61 var packageC = this.CreatePackageInstaller("PackageC");
29 62
30 var bundleA = this.CreateBundleInstaller("BundleA"); 63 var bundleA = this.CreateBundleInstaller("BundleA");
31 64
@@ -33,19 +66,132 @@ namespace WixToolsetTest.BurnE2E
33 66
34 // Source file should *not* be installed 67 // Source file should *not* be installed
35 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); 68 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
69 packageC.VerifyInstalled(false);
36 70
37 bundleA.Install(E_PREREQBA_INFINITE_LOOP); 71 bundleA.Install(E_PREREQBA_INFINITE_LOOP, "CAUSEINFINITELOOP=1");
38 72
39 // Part of the test is Install actually completing. 73 // Part of the test is Install actually completing.
40 74
41 // Source file should be installed 75 // Source file should be installed
42 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); 76 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
77 packageC.VerifyInstalled(false);
43 78
44 // No non-permanent packages should have ended up installed or cached so it should have unregistered. 79 // No non-permanent packages should have ended up installed or cached so it should have unregistered.
45 bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); 80 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
46 } 81 }
47 82
48 /// <summary> 83 /// <summary>
84 /// This bundle purposely provides a .runtimeconfig.json file that requires a version of .NET Core that doesn't exist,
85 /// with an EXE prereq package to swap it out with a good one.
86 /// This verifies that:
87 /// The preqba doesn't infinitely try to install prereqs.
88 /// The managed BA gets loaded after installing prereqs.
89 /// </summary>
90 [RuntimeFact]
91 public void DncAlwaysPreqBaLoadsManagedBaAfterInstallingPrereqs()
92 {
93 var packageA = this.CreatePackageInstaller("PackageA");
94 var packageC = this.CreatePackageInstaller("PackageC");
95
96 var bundleC = this.CreateBundleInstaller("BundleC");
97
98 var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
99
100 // Source file should *not* be installed
101 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
102 packageC.VerifyInstalled(false);
103
104 bundleC.Install();
105
106 // Source file should be installed
107 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
108 packageC.VerifyInstalled(true);
109
110 bundleC.VerifyRegisteredAndInPackageCache();
111
112 bundleC.Uninstall();
113
114 bundleC.VerifyUnregisteredAndRemovedFromPackageCache();
115 }
116
117 /// <summary>
118 /// This bundle purposely provides a .runtimeconfig.json file that requires a version of .NET Core that doesn't exist,
119 /// with an EXE prereq package to swap it out with a good one.
120 /// This verifies that:
121 /// The preqba doesn't infinitely reload itself after failing to load the managed BA.
122 /// The managed BA gets loaded after installing prereqs.
123 /// </summary>
124 [RuntimeFact]
125 public void DncPreqBaLoadsManagedBaAfterInstallingPrereqs()
126 {
127 var packageA = this.CreatePackageInstaller("PackageA");
128 var packageC = this.CreatePackageInstaller("PackageC");
129
130 var bundleA = this.CreateBundleInstaller("BundleA");
131
132 var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
133
134 // Source file should *not* be installed
135 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
136 packageC.VerifyInstalled(false);
137
138 bundleA.Install();
139
140 // Source file should be installed
141 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
142 packageC.VerifyInstalled(true);
143
144 bundleA.VerifyRegisteredAndInPackageCache();
145
146 bundleA.Uninstall();
147
148 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
149 }
150
151 [RuntimeFact]
152 public void DncAlwaysPreqBaForwardsHelpToManagedBa()
153 {
154 var bundleE = this.CreateBundleInstaller("BundleE");
155
156 var bundleLog = bundleE.Help();
157
158 Assert.True(LogVerifier.MessageInLogFile(bundleLog, "This is a BA for automated testing"));
159 }
160
161 /// <summary>
162 /// This bundle purposely provides a WixToolset.Mba.Host.config file that requires a version of .NET Framework that doesn't exist,
163 /// with an MSI package to represent the prerequisite package.
164 /// This verifies that:
165 /// The preqba doesn't infinitely try to install prereqs.
166 /// The engine automatically uninstalls the bundle since only permanent packages were installed.
167 /// </summary>
168 [RuntimeFact]
169 public void MbaAlwaysPreqBaDetectsInfiniteLoop()
170 {
171 var packageB = this.CreatePackageInstaller("PackageB");
172 var packageC = this.CreatePackageInstaller("PackageC");
173
174 var bundleD = this.CreateBundleInstaller("BundleD");
175
176 var packageBSourceCodeInstalled = packageB.GetInstalledFilePath("Package.wxs");
177
178 // Source file should *not* be installed
179 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}");
180 packageC.VerifyInstalled(false);
181
182 bundleD.Install(E_PREREQBA_INFINITE_LOOP, "CAUSEINFINITELOOP=1");
183
184 // Part of the test is Install actually completing.
185
186 // Source file should be installed
187 Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled));
188 packageC.VerifyInstalled(false);
189
190 // No non-permanent packages should have ended up installed or cached so it should have unregistered.
191 bundleD.VerifyUnregisteredAndRemovedFromPackageCache();
192 }
193
194 /// <summary>
49 /// This bundle purposely provides a WixToolset.Mba.Host.config file that requires a version of .NET Framework that doesn't exist, 195 /// This bundle purposely provides a WixToolset.Mba.Host.config file that requires a version of .NET Framework that doesn't exist,
50 /// with an MSI package to represent the prerequisite package. 196 /// with an MSI package to represent the prerequisite package.
51 /// This verifies that: 197 /// This verifies that:
@@ -56,7 +202,7 @@ namespace WixToolsetTest.BurnE2E
56 public void MbaPreqBaDetectsInfiniteLoop() 202 public void MbaPreqBaDetectsInfiniteLoop()
57 { 203 {
58 var packageB = this.CreatePackageInstaller("PackageB"); 204 var packageB = this.CreatePackageInstaller("PackageB");
59 this.CreatePackageInstaller("PackageF"); 205 var packageC = this.CreatePackageInstaller("PackageC");
60 206
61 var bundleB = this.CreateBundleInstaller("BundleB"); 207 var bundleB = this.CreateBundleInstaller("BundleB");
62 208
@@ -64,13 +210,84 @@ namespace WixToolsetTest.BurnE2E
64 210
65 // Source file should *not* be installed 211 // Source file should *not* be installed
66 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}"); 212 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}");
213 packageC.VerifyInstalled(false);
67 214
68 bundleB.Install(E_PREREQBA_INFINITE_LOOP); 215 bundleB.Install(E_PREREQBA_INFINITE_LOOP, "CAUSEINFINITELOOP=1");
69 216
70 // Part of the test is Install actually completing. 217 // Part of the test is Install actually completing.
71 218
72 // Source file should be installed 219 // Source file should be installed
73 Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled)); 220 Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled));
221 packageC.VerifyInstalled(false);
222
223 // No non-permanent packages should have ended up installed or cached so it should have unregistered.
224 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
225 }
226
227 /// <summary>
228 /// This bundle purposely provides a WixToolset.Mba.Host.config file that requires a version of .NET Framework that doesn't exist,
229 /// with an EXE prereq package to swap it out with a good one.
230 /// This verifies that:
231 /// The preqba doesn't infinitely try to install prereqs.
232 /// The managed BA gets loaded after installing prereqs.
233 /// </summary>
234 [RuntimeFact]
235 public void MbaAlwaysPreqBaLoadsManagedBaAfterInstallingPrereqs()
236 {
237 var packageB = this.CreatePackageInstaller("PackageB");
238 var packageC = this.CreatePackageInstaller("PackageC");
239
240 var bundleD = this.CreateBundleInstaller("BundleD");
241
242 var packageBSourceCodeInstalled = packageB.GetInstalledFilePath("Package.wxs");
243
244 // Source file should *not* be installed
245 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}");
246 packageC.VerifyInstalled(false);
247
248 bundleD.Install();
249
250 // Source file should be installed
251 Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled));
252 packageC.VerifyInstalled(true);
253
254 bundleD.VerifyRegisteredAndInPackageCache();
255
256 bundleD.Uninstall();
257
258 bundleD.VerifyUnregisteredAndRemovedFromPackageCache();
259 }
260
261 /// <summary>
262 /// This bundle purposely provides a WixToolset.Mba.Host.config file that requires a version of .NET Framework that doesn't exist,
263 /// with an EXE prereq package to swap it out with a good one.
264 /// This verifies that:
265 /// The preqba doesn't infinitely reload itself after failing to load the managed BA.
266 /// The managed BA gets loaded after installing prereqs.
267 /// </summary>
268 [RuntimeFact]
269 public void MbaPreqBaLoadsManagedBaAfterInstallingPrereqs()
270 {
271 var packageB = this.CreatePackageInstaller("PackageB");
272 var packageC = this.CreatePackageInstaller("PackageC");
273
274 var bundleB = this.CreateBundleInstaller("BundleB");
275
276 var packageBSourceCodeInstalled = packageB.GetInstalledFilePath("Package.wxs");
277
278 // Source file should *not* be installed
279 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}");
280 packageC.VerifyInstalled(false);
281
282 bundleB.Install();
283
284 // Source file should be installed
285 Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled));
286 packageC.VerifyInstalled(true);
287
288 bundleB.VerifyRegisteredAndInPackageCache();
289
290 bundleB.Uninstall();
74 291
75 // No non-permanent packages should have ended up installed or cached so it should have unregistered. 292 // No non-permanent packages should have ended up installed or cached so it should have unregistered.
76 bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); 293 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();