aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-05-13 13:50:50 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-05-14 11:12:31 -0500
commit6a6974a15deb6edf593736cdb8043bfb93064782 (patch)
tree0ae2afffcd02967ba3fe0f0a5d3e9273811f1e6f
parent7d56566b7c51c49ded526466dfae6af9e1709040 (diff)
downloadwix-6a6974a15deb6edf593736cdb8043bfb93064782.tar.gz
wix-6a6974a15deb6edf593736cdb8043bfb93064782.tar.bz2
wix-6a6974a15deb6edf593736cdb8043bfb93064782.zip
Move infinite loop detection into the hosts.
Tell the BA during Destroy whether it will be reloaded, and let the BA decide then whether it's module should be unloaded. Show error when infinite prereq loop detected. Only clip the exit code if they're Win32 errors. Set related bundle type to none to avoid downgrades during preqba.
-rw-r--r--src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h18
-rw-r--r--src/api/burn/balutil/inc/BAFunctions.h17
-rw-r--r--src/api/burn/balutil/inc/balutil.h1
-rw-r--r--src/burn/engine/engine.cpp4
-rw-r--r--src/burn/engine/userexperience.cpp15
-rw-r--r--src/burn/engine/userexperience.h4
-rw-r--r--src/ext/Bal/Samples/bafunctions/bafunctions.cpp2
-rw-r--r--src/ext/Bal/dnchost/dnchost.cpp51
-rw-r--r--src/ext/Bal/dnchost/dnchost.h8
-rw-r--r--src/ext/Bal/dnchost/dnchost.vcxproj2
-rw-r--r--src/ext/Bal/dnchost/precomp.h2
-rw-r--r--src/ext/Bal/mbahost/mbahost.cpp289
-rw-r--r--src/ext/Bal/mbahost/mbahost.h17
-rw-r--r--src/ext/Bal/mbahost/mbahost.vcxproj3
-rw-r--r--src/ext/Bal/mbahost/precomp.h17
-rw-r--r--src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp4
-rw-r--r--src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp2
-rw-r--r--src/ext/Bal/test/examples/TestEngine/TestEngine.cpp16
-rw-r--r--src/ext/Bal/test/examples/TestEngine/TestEngine.h6
-rw-r--r--src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp2
-rw-r--r--src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/dncpreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/Resources/mbapreq.wxl1
-rw-r--r--src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp320
-rw-r--r--src/ext/Bal/wixstdba/inc/preqba.h16
-rw-r--r--src/ext/Bal/wixstdba/precomp.h66
-rw-r--r--src/ext/Bal/wixstdba/wixstdba.cpp54
-rw-r--r--src/ext/Bal/wixstdba/wixstdba.def6
-rw-r--r--src/ext/Bal/wixstdba/wixstdba.vcxproj1
-rw-r--r--src/test/burn/TestBA/TestBA.cs8
-rw-r--r--src/test/burn/TestData/Manual/BafThmutilTesting/precomp.cpp2
-rw-r--r--src/test/burn/WixToolset.WixBA/WixBA.cs9
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs6
55 files changed, 500 insertions, 493 deletions
diff --git a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
index 228cb6ff..ea3be214 100644
--- a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+++ b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
@@ -1494,7 +1494,22 @@ extern "C" typedef HRESULT(WINAPI *PFN_BOOTSTRAPPER_APPLICATION_PROC)(
1494 __in_opt LPVOID pvContext 1494 __in_opt LPVOID pvContext
1495 ); 1495 );
1496 1496
1497extern "C" typedef void (WINAPI *PFN_BOOTSTRAPPER_APPLICATION_DESTROY)(); 1497struct BOOTSTRAPPER_DESTROY_ARGS
1498{
1499 DWORD cbSize;
1500 BOOL fReload;
1501};
1502
1503struct BOOTSTRAPPER_DESTROY_RESULTS
1504{
1505 DWORD cbSize;
1506 BOOL fDisableUnloading; // indicates the BA dll must not be unloaded after BootstrapperApplicationDestroy.
1507};
1508
1509extern "C" typedef void (WINAPI *PFN_BOOTSTRAPPER_APPLICATION_DESTROY)(
1510 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
1511 __inout BOOTSTRAPPER_DESTROY_RESULTS* pResults
1512 );
1498 1513
1499 1514
1500 1515
@@ -1512,7 +1527,6 @@ struct BOOTSTRAPPER_CREATE_RESULTS
1512 DWORD cbSize; 1527 DWORD cbSize;
1513 PFN_BOOTSTRAPPER_APPLICATION_PROC pfnBootstrapperApplicationProc; 1528 PFN_BOOTSTRAPPER_APPLICATION_PROC pfnBootstrapperApplicationProc;
1514 LPVOID pvBootstrapperApplicationProcContext; 1529 LPVOID pvBootstrapperApplicationProcContext;
1515 BOOL fDisableUnloading; // indicates the BA dll must not be unloaded after BootstrapperApplicationDestroy.
1516}; 1530};
1517 1531
1518extern "C" typedef HRESULT(WINAPI *PFN_BOOTSTRAPPER_APPLICATION_CREATE)( 1532extern "C" typedef HRESULT(WINAPI *PFN_BOOTSTRAPPER_APPLICATION_CREATE)(
diff --git a/src/api/burn/balutil/inc/BAFunctions.h b/src/api/burn/balutil/inc/BAFunctions.h
index c1057ab6..b23dd02e 100644
--- a/src/api/burn/balutil/inc/BAFunctions.h
+++ b/src/api/burn/balutil/inc/BAFunctions.h
@@ -126,6 +126,18 @@ struct BA_FUNCTIONS_CREATE_RESULTS
126 LPVOID pvBAFunctionsProcContext; 126 LPVOID pvBAFunctionsProcContext;
127}; 127};
128 128
129struct BA_FUNCTIONS_DESTROY_ARGS
130{
131 DWORD cbSize;
132 BOOL fReload;
133};
134
135struct BA_FUNCTIONS_DESTROY_RESULTS
136{
137 DWORD cbSize;
138 BOOL fDisableUnloading; // indicates the BAFunctions dll must not be unloaded after BAFunctionsDestroy.
139};
140
129struct BA_FUNCTIONS_ONTHEMECONTROLLOADED_ARGS 141struct BA_FUNCTIONS_ONTHEMECONTROLLOADED_ARGS
130{ 142{
131 DWORD cbSize; 143 DWORD cbSize;
@@ -218,7 +230,10 @@ typedef HRESULT(WINAPI *PFN_BA_FUNCTIONS_CREATE)(
218 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults 230 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults
219 ); 231 );
220 232
221typedef void (WINAPI *PFN_BA_FUNCTIONS_DESTROY)(); 233typedef void (WINAPI *PFN_BA_FUNCTIONS_DESTROY)(
234 __in const BA_FUNCTIONS_DESTROY_ARGS* pArgs,
235 __inout BA_FUNCTIONS_DESTROY_RESULTS* pResults
236 );
222 237
223#ifdef __cplusplus 238#ifdef __cplusplus
224} 239}
diff --git a/src/api/burn/balutil/inc/balutil.h b/src/api/burn/balutil/inc/balutil.h
index 2e370db7..33f1a6de 100644
--- a/src/api/burn/balutil/inc/balutil.h
+++ b/src/api/burn/balutil/inc/balutil.h
@@ -39,6 +39,7 @@ static const HRESULT E_WIXSTDBA_CONDITION_FAILED = MAKE_HRESULT(SEVERITY_ERROR,
39 39
40static const HRESULT E_MBAHOST_NET452_ON_WIN7RTM = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIX, 1000); 40static const HRESULT E_MBAHOST_NET452_ON_WIN7RTM = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIX, 1000);
41static const HRESULT E_DNCHOST_SCD_RUNTIME_FAILURE = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIX, 1001); 41static const HRESULT E_DNCHOST_SCD_RUNTIME_FAILURE = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIX, 1001);
42static const HRESULT E_PREREQBA_INFINITE_LOOP = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIX, 1002);
42 43
43 44
44/******************************************************************* 45/*******************************************************************
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp
index ee848acf..a408ed4a 100644
--- a/src/burn/engine/engine.cpp
+++ b/src/burn/engine/engine.cpp
@@ -796,7 +796,7 @@ LExit:
796 else if (BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER == shutdownAction) 796 else if (BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER == shutdownAction)
797 { 797 {
798 LogId(REPORT_STANDARD, MSG_BA_REQUESTED_RELOAD); 798 LogId(REPORT_STANDARD, MSG_BA_REQUESTED_RELOAD);
799 *pfReloadApp = TRUE; 799 *pfReloadApp = SUCCEEDED(hr);
800 } 800 }
801 else if (BOOTSTRAPPER_SHUTDOWN_ACTION_SKIP_CLEANUP == shutdownAction) 801 else if (BOOTSTRAPPER_SHUTDOWN_ACTION_SKIP_CLEANUP == shutdownAction)
802 { 802 {
@@ -806,7 +806,7 @@ LExit:
806 } 806 }
807 807
808 // Unload BA. 808 // Unload BA.
809 UserExperienceUnload(&pEngineState->userExperience); 809 UserExperienceUnload(&pEngineState->userExperience, *pfReloadApp);
810 810
811 return hr; 811 return hr;
812} 812}
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp
index 4325a6ee..87ef4de1 100644
--- a/src/burn/engine/userexperience.cpp
+++ b/src/burn/engine/userexperience.cpp
@@ -122,7 +122,6 @@ extern "C" HRESULT UserExperienceLoad(
122 122
123 pUserExperience->pfnBAProc = results.pfnBootstrapperApplicationProc; 123 pUserExperience->pfnBAProc = results.pfnBootstrapperApplicationProc;
124 pUserExperience->pvBAProcContext = results.pvBootstrapperApplicationProcContext; 124 pUserExperience->pvBAProcContext = results.pvBootstrapperApplicationProcContext;
125 pUserExperience->fDisableUnloading = results.fDisableUnloading;
126 125
127LExit: 126LExit:
128 return hr; 127 return hr;
@@ -133,10 +132,18 @@ LExit:
133 132
134*******************************************************************/ 133*******************************************************************/
135extern "C" HRESULT UserExperienceUnload( 134extern "C" HRESULT UserExperienceUnload(
136 __in BURN_USER_EXPERIENCE* pUserExperience 135 __in BURN_USER_EXPERIENCE* pUserExperience,
136 __in BOOL fReload
137 ) 137 )
138{ 138{
139 HRESULT hr = S_OK; 139 HRESULT hr = S_OK;
140 BOOTSTRAPPER_DESTROY_ARGS args = { };
141 BOOTSTRAPPER_DESTROY_RESULTS results = { };
142
143 args.cbSize = sizeof(BOOTSTRAPPER_DESTROY_ARGS);
144 args.fReload = fReload;
145
146 results.cbSize = sizeof(BOOTSTRAPPER_DESTROY_RESULTS);
140 147
141 if (pUserExperience->hUXModule) 148 if (pUserExperience->hUXModule)
142 { 149 {
@@ -144,11 +151,11 @@ extern "C" HRESULT UserExperienceUnload(
144 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = (PFN_BOOTSTRAPPER_APPLICATION_DESTROY)::GetProcAddress(pUserExperience->hUXModule, "BootstrapperApplicationDestroy"); 151 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = (PFN_BOOTSTRAPPER_APPLICATION_DESTROY)::GetProcAddress(pUserExperience->hUXModule, "BootstrapperApplicationDestroy");
145 if (pfnDestroy) 152 if (pfnDestroy)
146 { 153 {
147 pfnDestroy(); 154 pfnDestroy(&args, &results);
148 } 155 }
149 156
150 // Free BA DLL if it supports it. 157 // Free BA DLL if it supports it.
151 if (!pUserExperience->fDisableUnloading && !::FreeLibrary(pUserExperience->hUXModule)) 158 if (!results.fDisableUnloading && !::FreeLibrary(pUserExperience->hUXModule))
152 { 159 {
153 hr = HRESULT_FROM_WIN32(::GetLastError()); 160 hr = HRESULT_FROM_WIN32(::GetLastError());
154 TraceError(hr, "Failed to unload BA DLL."); 161 TraceError(hr, "Failed to unload BA DLL.");
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h
index e7489710..94b73f7d 100644
--- a/src/burn/engine/userexperience.h
+++ b/src/burn/engine/userexperience.h
@@ -22,7 +22,6 @@ typedef struct _BURN_USER_EXPERIENCE
22 HMODULE hUXModule; 22 HMODULE hUXModule;
23 PFN_BOOTSTRAPPER_APPLICATION_PROC pfnBAProc; 23 PFN_BOOTSTRAPPER_APPLICATION_PROC pfnBAProc;
24 LPVOID pvBAProcContext; 24 LPVOID pvBAProcContext;
25 BOOL fDisableUnloading;
26 LPWSTR sczTempDirectory; 25 LPWSTR sczTempDirectory;
27 26
28 CRITICAL_SECTION csEngineActive; // Changing the engine active state in the user experience must be 27 CRITICAL_SECTION csEngineActive; // Changing the engine active state in the user experience must be
@@ -61,7 +60,8 @@ HRESULT UserExperienceLoad(
61 __in BOOTSTRAPPER_COMMAND* pCommand 60 __in BOOTSTRAPPER_COMMAND* pCommand
62 ); 61 );
63HRESULT UserExperienceUnload( 62HRESULT UserExperienceUnload(
64 __in BURN_USER_EXPERIENCE* pUserExperience 63 __in BURN_USER_EXPERIENCE* pUserExperience,
64 __in BOOL fReload
65 ); 65 );
66HRESULT UserExperienceEnsureWorkingFolder( 66HRESULT UserExperienceEnsureWorkingFolder(
67 __in BURN_CACHE* pCache, 67 __in BURN_CACHE* pCache,
diff --git a/src/ext/Bal/Samples/bafunctions/bafunctions.cpp b/src/ext/Bal/Samples/bafunctions/bafunctions.cpp
index b20f4230..fc9d1177 100644
--- a/src/ext/Bal/Samples/bafunctions/bafunctions.cpp
+++ b/src/ext/Bal/Samples/bafunctions/bafunctions.cpp
@@ -40,6 +40,8 @@ LExit:
40} 40}
41 41
42extern "C" void WINAPI BAFunctionsDestroy( 42extern "C" void WINAPI BAFunctionsDestroy(
43 __in const BA_FUNCTIONS_DESTROY_ARGS* /*pArgs*/,
44 __inout BA_FUNCTIONS_DESTROY_RESULTS* /*pResults*/
43 ) 45 )
44{ 46{
45 BalUninitialize(); 47 BalUninitialize();
diff --git a/src/ext/Bal/dnchost/dnchost.cpp b/src/ext/Bal/dnchost/dnchost.cpp
index 644ba30e..6c066f43 100644
--- a/src/ext/Bal/dnchost/dnchost.cpp
+++ b/src/ext/Bal/dnchost/dnchost.cpp
@@ -21,9 +21,8 @@ static HRESULT LoadManagedBootstrapperApplicationFactory(
21 __in DNCSTATE* pState 21 __in DNCSTATE* pState
22 ); 22 );
23static HRESULT CreatePrerequisiteBA( 23static HRESULT CreatePrerequisiteBA(
24 __in HRESULT hrHostInitialization, 24 __in DNCSTATE* pState,
25 __in IBootstrapperEngine* pEngine, 25 __in IBootstrapperEngine* pEngine,
26 __in LPCWSTR wzAppBase,
27 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 26 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
28 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults 27 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
29 ); 28 );
@@ -58,13 +57,8 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
58 ) 57 )
59{ 58{
60 HRESULT hr = S_OK; 59 HRESULT hr = S_OK;
61 HRESULT hrHostInitialization = S_OK;
62 IBootstrapperEngine* pEngine = NULL; 60 IBootstrapperEngine* pEngine = NULL;
63 61
64 // coreclr.dll doesn't support unloading, so the rest of the .NET Core hosting stack doesn't support it either.
65 // This means we also can't unload.
66 pResults->fDisableUnloading = TRUE;
67
68 hr = BalInitializeFromCreateArgs(pArgs, &pEngine); 62 hr = BalInitializeFromCreateArgs(pArgs, &pEngine);
69 ExitOnFailure(hr, "Failed to initialize Bal."); 63 ExitOnFailure(hr, "Failed to initialize Bal.");
70 64
@@ -106,16 +100,22 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
106 { 100 {
107 if (DNCHOSTTYPE_SCD == vstate.type) 101 if (DNCHOSTTYPE_SCD == vstate.type)
108 { 102 {
109 hrHostInitialization = E_DNCHOST_SCD_RUNTIME_FAILURE; 103 vstate.prereqData.hrHostInitialization = E_DNCHOST_SCD_RUNTIME_FAILURE;
110 BalLogError(hr, "The self-contained .NET Core runtime failed to load. This is an unrecoverable error."); 104 BalLogError(hr, "The self-contained .NET Core runtime failed to load. This is an unrecoverable error.");
111 } 105 }
106 else if (vstate.prereqData.fCompleted)
107 {
108 hr = E_PREREQBA_INFINITE_LOOP;
109 BalLogError(hr, "The prerequisites were already installed. The bootstrapper application will not be reloaded to prevent an infinite loop.");
110 vstate.prereqData.hrHostInitialization = hr;
111 }
112 else 112 else
113 { 113 {
114 hrHostInitialization = S_OK; 114 vstate.prereqData.hrHostInitialization = S_OK;
115 } 115 }
116 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because .NET Core host could not be loaded, error: 0x%08x.", hr); 116 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because .NET Core host could not be loaded, error: 0x%08x.", hr);
117 117
118 hr = CreatePrerequisiteBA(hrHostInitialization, pEngine, vstate.sczAppBase, pArgs, pResults); 118 hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults);
119 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application."); 119 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
120 } 120 }
121 121
@@ -125,14 +125,21 @@ LExit:
125 return hr; 125 return hr;
126} 126}
127 127
128extern "C" void WINAPI BootstrapperApplicationDestroy() 128extern "C" void WINAPI BootstrapperApplicationDestroy(
129 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
130 __in BOOTSTRAPPER_DESTROY_RESULTS* pResults
131 )
129{ 132{
133 BOOTSTRAPPER_DESTROY_RESULTS childResults = { };
134
135 childResults.cbSize = sizeof(BOOTSTRAPPER_DESTROY_RESULTS);
136
130 if (vstate.hMbapreqModule) 137 if (vstate.hMbapreqModule)
131 { 138 {
132 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vstate.hMbapreqModule, "DncPrereqBootstrapperApplicationDestroy")); 139 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vstate.hMbapreqModule, "PrereqBootstrapperApplicationDestroy"));
133 if (pfnDestroy) 140 if (pfnDestroy)
134 { 141 {
135 (*pfnDestroy)(); 142 (*pfnDestroy)(pArgs, &childResults);
136 } 143 }
137 144
138 ::FreeLibrary(vstate.hMbapreqModule); 145 ::FreeLibrary(vstate.hMbapreqModule);
@@ -140,6 +147,9 @@ extern "C" void WINAPI BootstrapperApplicationDestroy()
140 } 147 }
141 148
142 BalUninitialize(); 149 BalUninitialize();
150
151 // Need to keep track of state between reloads.
152 pResults->fDisableUnloading = TRUE;
143} 153}
144 154
145static HRESULT LoadModulePaths( 155static HRESULT LoadModulePaths(
@@ -262,9 +272,8 @@ static HRESULT LoadManagedBootstrapperApplicationFactory(
262} 272}
263 273
264static HRESULT CreatePrerequisiteBA( 274static HRESULT CreatePrerequisiteBA(
265 __in HRESULT hrHostInitialization, 275 __in DNCSTATE* pState,
266 __in IBootstrapperEngine* pEngine, 276 __in IBootstrapperEngine* pEngine,
267 __in LPCWSTR wzAppBase,
268 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 277 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
269 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults 278 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
270 ) 279 )
@@ -273,19 +282,19 @@ static HRESULT CreatePrerequisiteBA(
273 LPWSTR sczDncpreqPath = NULL; 282 LPWSTR sczDncpreqPath = NULL;
274 HMODULE hModule = NULL; 283 HMODULE hModule = NULL;
275 284
276 hr = PathConcat(wzAppBase, L"dncpreq.dll", &sczDncpreqPath); 285 hr = PathConcat(pState->sczAppBase, L"dncpreq.dll", &sczDncpreqPath);
277 BalExitOnFailure(hr, "Failed to get path to pre-requisite BA."); 286 BalExitOnFailure(hr, "Failed to get path to pre-requisite BA.");
278 287
279 hModule = ::LoadLibraryW(sczDncpreqPath); 288 hModule = ::LoadLibraryExW(sczDncpreqPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
280 BalExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL."); 289 BalExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL.");
281 290
282 PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "DncPrereqBootstrapperApplicationCreate")); 291 PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "PrereqBootstrapperApplicationCreate"));
283 BalExitOnNullWithLastError(pfnCreate, hr, "Failed to get DncPrereqBootstrapperApplicationCreate entry-point from: %ls", sczDncpreqPath); 292 BalExitOnNullWithLastError(pfnCreate, hr, "Failed to get PrereqBootstrapperApplicationCreate entry-point from: %ls", sczDncpreqPath);
284 293
285 hr = pfnCreate(hrHostInitialization, pEngine, pArgs, pResults); 294 hr = pfnCreate(&pState->prereqData, pEngine, pArgs, pResults);
286 BalExitOnFailure(hr, "Failed to create prequisite bootstrapper app."); 295 BalExitOnFailure(hr, "Failed to create prequisite bootstrapper app.");
287 296
288 vstate.hMbapreqModule = hModule; 297 pState->hMbapreqModule = hModule;
289 hModule = NULL; 298 hModule = NULL;
290 299
291LExit: 300LExit:
diff --git a/src/ext/Bal/dnchost/dnchost.h b/src/ext/Bal/dnchost/dnchost.h
index b0ba9638..000cf43d 100644
--- a/src/ext/Bal/dnchost/dnchost.h
+++ b/src/ext/Bal/dnchost/dnchost.h
@@ -9,13 +9,6 @@ enum DNCHOSTTYPE
9 DNCHOSTTYPE_SCD, 9 DNCHOSTTYPE_SCD,
10}; 10};
11 11
12extern "C" typedef HRESULT(WINAPI* PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE)(
13 __in HRESULT hrHostInitialization,
14 __in IBootstrapperEngine* pEngine,
15 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
16 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
17 );
18
19struct DNCSTATE 12struct DNCSTATE
20{ 13{
21 BOOL fInitialized; 14 BOOL fInitialized;
@@ -31,4 +24,5 @@ struct DNCSTATE
31 HOSTFXR_STATE hostfxrState; 24 HOSTFXR_STATE hostfxrState;
32 IBootstrapperApplicationFactory* pAppFactory; 25 IBootstrapperApplicationFactory* pAppFactory;
33 HMODULE hMbapreqModule; 26 HMODULE hMbapreqModule;
27 PREQBA_DATA prereqData;
34}; 28};
diff --git a/src/ext/Bal/dnchost/dnchost.vcxproj b/src/ext/Bal/dnchost/dnchost.vcxproj
index ca0c09d6..b258ccae 100644
--- a/src/ext/Bal/dnchost/dnchost.vcxproj
+++ b/src/ext/Bal/dnchost/dnchost.vcxproj
@@ -50,7 +50,7 @@
50 <NetHostPlatform>$(Platform)</NetHostPlatform> 50 <NetHostPlatform>$(Platform)</NetHostPlatform>
51 <NetHostPlatform Condition=" '$(NetHostPlatform)'=='Win32' ">x86</NetHostPlatform> 51 <NetHostPlatform Condition=" '$(NetHostPlatform)'=='Win32' ">x86</NetHostPlatform>
52 <NetHostPath>..\..\..\..\packages\runtime.win-$(NetHostPlatform).Microsoft.NETCore.DotNetAppHost.6.0.4\runtimes\win-$(NetHostPlatform)\native\</NetHostPath> 52 <NetHostPath>..\..\..\..\packages\runtime.win-$(NetHostPlatform).Microsoft.NETCore.DotNetAppHost.6.0.4\runtimes\win-$(NetHostPlatform)\native\</NetHostPath>
53 <ProjectAdditionalIncludeDirectories>$(BaseOutputPath)obj;$(NetHostPath)</ProjectAdditionalIncludeDirectories> 53 <ProjectAdditionalIncludeDirectories>$(BaseOutputPath)obj;$(NetHostPath);..\wixstdba\inc</ProjectAdditionalIncludeDirectories>
54 <ProjectAdditionalLinkLibraries>shlwapi.lib;$(NetHostPath)libnethost.lib</ProjectAdditionalLinkLibraries> 54 <ProjectAdditionalLinkLibraries>shlwapi.lib;$(NetHostPath)libnethost.lib</ProjectAdditionalLinkLibraries>
55 </PropertyGroup> 55 </PropertyGroup>
56 56
diff --git a/src/ext/Bal/dnchost/precomp.h b/src/ext/Bal/dnchost/precomp.h
index 7aefc4e3..5f365fba 100644
--- a/src/ext/Bal/dnchost/precomp.h
+++ b/src/ext/Bal/dnchost/precomp.h
@@ -25,6 +25,8 @@
25#include <hostfxr.h> 25#include <hostfxr.h>
26#include <coreclr_delegates.h> 26#include <coreclr_delegates.h>
27 27
28#include <preqba.h>
29
28#include "coreclrhost.h" 30#include "coreclrhost.h"
29#include "dncutil.h" 31#include "dncutil.h"
30#include "dnchost.h" 32#include "dnchost.h"
diff --git a/src/ext/Bal/mbahost/mbahost.cpp b/src/ext/Bal/mbahost/mbahost.cpp
index a9585389..3de77a05 100644
--- a/src/ext/Bal/mbahost/mbahost.cpp
+++ b/src/ext/Bal/mbahost/mbahost.cpp
@@ -1,7 +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. 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#include "precomp.h" 3#include "precomp.h"
4#include <WixToolset.Mba.Host.h> // includes the generated assembly name macros.
5 4
6static const DWORD NET452_RELEASE = 379893; 5static const DWORD NET452_RELEASE = 379893;
7 6
@@ -14,26 +13,16 @@ extern "C" typedef HRESULT (WINAPI *PFN_CORBINDTOCURRENTRUNTIME)(
14 __out LPVOID *ppv 13 __out LPVOID *ppv
15 ); 14 );
16 15
17extern "C" typedef HRESULT(WINAPI *PFN_MBAPREQ_BOOTSTRAPPER_APPLICATION_CREATE)( 16static MBASTATE vstate = { };
18 __in HRESULT hrHostInitialization,
19 __in IBootstrapperEngine* pEngine,
20 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
21 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
22 );
23
24static HINSTANCE vhInstance = NULL;
25static ICorRuntimeHost *vpCLRHost = NULL;
26static _AppDomain *vpAppDomain = NULL;
27static HMODULE vhMbapreqModule = NULL;
28 17
29 18
30// internal function declarations 19// internal function declarations
31 20
32static HRESULT GetAppDomain( 21static HRESULT GetAppDomain(
33 __out _AppDomain** ppAppDomain 22 __in MBASTATE* pState
34 ); 23 );
35static HRESULT GetAppBase( 24static HRESULT LoadModulePaths(
36 __out LPWSTR* psczAppBase 25 __in MBASTATE* pState
37 ); 26 );
38static HRESULT CheckSupportedFrameworks( 27static HRESULT CheckSupportedFrameworks(
39 __in LPCWSTR wzConfigPath 28 __in LPCWSTR wzConfigPath
@@ -43,9 +32,8 @@ static HRESULT UpdateSupportedRuntime(
43 __in IXMLDOMNode* pixnSupportedFramework, 32 __in IXMLDOMNode* pixnSupportedFramework,
44 __out BOOL* pfUpdatedManifest 33 __out BOOL* pfUpdatedManifest
45 ); 34 );
46static HRESULT GetCLRHost( 35static HRESULT LoadRuntime(
47 __in LPCWSTR wzConfigPath, 36 __in MBASTATE* pState
48 __out ICorRuntimeHost** ppCLRHost
49 ); 37 );
50static HRESULT CreateManagedBootstrapperApplication( 38static HRESULT CreateManagedBootstrapperApplication(
51 __in _AppDomain* pAppDomain, 39 __in _AppDomain* pAppDomain,
@@ -57,7 +45,7 @@ static HRESULT CreateManagedBootstrapperApplicationFactory(
57 __out IBootstrapperApplicationFactory** ppAppFactory 45 __out IBootstrapperApplicationFactory** ppAppFactory
58 ); 46 );
59static HRESULT CreatePrerequisiteBA( 47static HRESULT CreatePrerequisiteBA(
60 __in HRESULT hrHostInitialization, 48 __in MBASTATE* pState,
61 __in IBootstrapperEngine* pEngine, 49 __in IBootstrapperEngine* pEngine,
62 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 50 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
63 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults 51 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
@@ -78,11 +66,11 @@ extern "C" BOOL WINAPI DllMain(
78 { 66 {
79 case DLL_PROCESS_ATTACH: 67 case DLL_PROCESS_ATTACH:
80 ::DisableThreadLibraryCalls(hInstance); 68 ::DisableThreadLibraryCalls(hInstance);
81 vhInstance = hInstance; 69 vstate.hInstance = hInstance;
82 break; 70 break;
83 71
84 case DLL_PROCESS_DETACH: 72 case DLL_PROCESS_DETACH:
85 vhInstance = NULL; 73 vstate.hInstance = NULL;
86 break; 74 break;
87 } 75 }
88 76
@@ -96,18 +84,39 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
96 ) 84 )
97{ 85{
98 HRESULT hr = S_OK; 86 HRESULT hr = S_OK;
99 HRESULT hrHostInitialization = S_OK;
100 IBootstrapperEngine* pEngine = NULL; 87 IBootstrapperEngine* pEngine = NULL;
101 88
89 if (vstate.fStoppedRuntime)
90 {
91 BalExitWithRootFailure(hr, E_INVALIDSTATE, "Reloaded mbahost after stopping .NET runtime.");
92 }
93
102 hr = BalInitializeFromCreateArgs(pArgs, &pEngine); 94 hr = BalInitializeFromCreateArgs(pArgs, &pEngine);
103 ExitOnFailure(hr, "Failed to initialize Bal."); 95 ExitOnFailure(hr, "Failed to initialize Bal.");
104 96
105 hr = GetAppDomain(&vpAppDomain); 97 if (!vstate.fInitialized)
106 if (SUCCEEDED(hr)) 98 {
99 hr = LoadModulePaths(&vstate);
100 BalExitOnFailure(hr, "Failed to load the module paths.");
101
102 vstate.fInitialized = TRUE;
103 }
104
105 if (!vstate.fInitializedRuntime)
106 {
107 hr = LoadRuntime(&vstate);
108
109 vstate.fInitializedRuntime = SUCCEEDED(hr);
110 }
111
112 if (vstate.fInitializedRuntime)
107 { 113 {
114 hr = GetAppDomain(&vstate);
115 BalExitOnFailure(hr, "Failed to create the AppDomain for the managed bootstrapper application.");
116
108 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading managed bootstrapper application."); 117 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading managed bootstrapper application.");
109 118
110 hr = CreateManagedBootstrapperApplication(vpAppDomain, pArgs, pResults); 119 hr = CreateManagedBootstrapperApplication(vstate.pAppDomain, pArgs, pResults);
111 BalExitOnFailure(hr, "Failed to create the managed bootstrapper application."); 120 BalExitOnFailure(hr, "Failed to create the managed bootstrapper application.");
112 } 121 }
113 else // fallback to the prerequisite BA. 122 else // fallback to the prerequisite BA.
@@ -115,16 +124,22 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
115 if (E_MBAHOST_NET452_ON_WIN7RTM == hr) 124 if (E_MBAHOST_NET452_ON_WIN7RTM == hr)
116 { 125 {
117 BalLogError(hr, "The Burn engine cannot run with an MBA under the .NET 4 CLR on Windows 7 RTM with .NET 4.5.2 (or greater) installed."); 126 BalLogError(hr, "The Burn engine cannot run with an MBA under the .NET 4 CLR on Windows 7 RTM with .NET 4.5.2 (or greater) installed.");
118 hrHostInitialization = hr; 127 vstate.prereqData.hrHostInitialization = hr;
128 }
129 else if (vstate.prereqData.fCompleted)
130 {
131 hr = E_PREREQBA_INFINITE_LOOP;
132 BalLogError(hr, "The prerequisites were already installed. The bootstrapper application will not be reloaded to prevent an infinite loop.");
133 vstate.prereqData.hrHostInitialization = hr;
119 } 134 }
120 else 135 else
121 { 136 {
122 hrHostInitialization = S_OK; 137 vstate.prereqData.hrHostInitialization = S_OK;
123 } 138 }
124 139
125 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because managed host could not be loaded, error: 0x%08x.", hr); 140 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because managed host could not be loaded, error: 0x%08x.", hr);
126 141
127 hr = CreatePrerequisiteBA(hrHostInitialization, pEngine, pArgs, pResults); 142 hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults);
128 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application."); 143 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
129 } 144 }
130 145
@@ -134,73 +149,65 @@ LExit:
134 return hr; 149 return hr;
135} 150}
136 151
137extern "C" void WINAPI BootstrapperApplicationDestroy() 152extern "C" void WINAPI BootstrapperApplicationDestroy(
153 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
154 __in BOOTSTRAPPER_DESTROY_RESULTS* pResults
155 )
138{ 156{
139 if (vpAppDomain) 157 BOOTSTRAPPER_DESTROY_RESULTS childResults = { };
158
159 if (vstate.pAppDomain)
140 { 160 {
141 HRESULT hr = vpCLRHost->UnloadDomain(vpAppDomain); 161 HRESULT hr = vstate.pCLRHost->UnloadDomain(vstate.pAppDomain);
142 if (FAILED(hr)) 162 if (FAILED(hr))
143 { 163 {
144 BalLogError(hr, "Failed to unload app domain."); 164 BalLogError(hr, "Failed to unload app domain.");
145 } 165 }
146 166
147 vpAppDomain->Release(); 167 vstate.pAppDomain->Release();
168 vstate.pAppDomain = NULL;
148 } 169 }
149 170
150 if (vpCLRHost) 171 // pCLRHost can only be stopped once per process.
172 if (vstate.pCLRHost && !pArgs->fReload)
151 { 173 {
152 vpCLRHost->Stop(); 174 vstate.pCLRHost->Stop();
153 vpCLRHost->Release(); 175 vstate.pCLRHost->Release();
176 vstate.pCLRHost = NULL;
177 vstate.fStoppedRuntime = TRUE;
154 } 178 }
155 179
156 if (vhMbapreqModule) 180 if (vstate.hMbapreqModule)
157 { 181 {
158 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vhMbapreqModule, "MbaPrereqBootstrapperApplicationDestroy")); 182 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vstate.hMbapreqModule, "PrereqBootstrapperApplicationDestroy"));
159 if (pfnDestroy) 183 if (pfnDestroy)
160 { 184 {
161 (*pfnDestroy)(); 185 (*pfnDestroy)(pArgs, &childResults);
162 } 186 }
163 187
164 ::FreeLibrary(vhMbapreqModule); 188 ::FreeLibrary(vstate.hMbapreqModule);
165 vhMbapreqModule = NULL; 189 vstate.hMbapreqModule = NULL;
166 } 190 }
167 191
168 BalUninitialize(); 192 BalUninitialize();
193
194 // Need to keep track of state between reloads.
195 pResults->fDisableUnloading = TRUE;
169} 196}
170 197
171// Gets the custom AppDomain for loading managed BA. 198// Gets the custom AppDomain for loading managed BA.
172static HRESULT GetAppDomain( 199static HRESULT GetAppDomain(
173 __out _AppDomain **ppAppDomain 200 __in MBASTATE* pState
174 ) 201 )
175{ 202{
176 HRESULT hr = S_OK; 203 HRESULT hr = S_OK;
177 ICorRuntimeHost *pCLRHost = NULL;
178 IUnknown *pUnk = NULL; 204 IUnknown *pUnk = NULL;
179 LPWSTR sczAppBase = NULL; 205 IAppDomainSetup* pAppDomainSetup = NULL;
180 LPWSTR sczConfigPath = NULL;
181 IAppDomainSetup *pAppDomainSetup;
182 BSTR bstrAppBase = NULL; 206 BSTR bstrAppBase = NULL;
183 BSTR bstrConfigPath = NULL; 207 BSTR bstrConfigPath = NULL;
184 208
185 hr = GetAppBase(&sczAppBase);
186 ExitOnFailure(hr, "Failed to get the host base path.");
187
188 hr = PathConcat(sczAppBase, MBA_CONFIG_FILE_NAME, &sczConfigPath);
189 ExitOnFailure(hr, "Failed to get the full path to the application configuration file.");
190
191 // Check that the supported framework is installed.
192 hr = CheckSupportedFrameworks(sczConfigPath);
193 ExitOnFailure(hr, "Failed to find supported framework.");
194
195 // Load the CLR.
196 hr = GetCLRHost(sczConfigPath, &pCLRHost);
197 ExitOnFailure(hr, "Failed to create the CLR host.");
198
199 hr = pCLRHost->Start();
200 ExitOnRootFailure(hr, "Failed to start the CLR host.");
201
202 // Create the setup information for a new AppDomain to set the app base and config. 209 // Create the setup information for a new AppDomain to set the app base and config.
203 hr = pCLRHost->CreateDomainSetup(&pUnk); 210 hr = pState->pCLRHost->CreateDomainSetup(&pUnk);
204 ExitOnRootFailure(hr, "Failed to create the AppDomainSetup object."); 211 ExitOnRootFailure(hr, "Failed to create the AppDomainSetup object.");
205 212
206 hr = pUnk->QueryInterface(__uuidof(IAppDomainSetup), reinterpret_cast<LPVOID*>(&pAppDomainSetup)); 213 hr = pUnk->QueryInterface(__uuidof(IAppDomainSetup), reinterpret_cast<LPVOID*>(&pAppDomainSetup));
@@ -208,49 +215,49 @@ static HRESULT GetAppDomain(
208 ReleaseNullObject(pUnk); 215 ReleaseNullObject(pUnk);
209 216
210 // Set properties on the AppDomainSetup object. 217 // Set properties on the AppDomainSetup object.
211 bstrAppBase = ::SysAllocString(sczAppBase); 218 bstrAppBase = ::SysAllocString(pState->sczAppBase);
212 ExitOnNull(bstrAppBase, hr, E_OUTOFMEMORY, "Failed to allocate the application base path for the AppDomainSetup."); 219 ExitOnNull(bstrAppBase, hr, E_OUTOFMEMORY, "Failed to allocate the application base path for the AppDomainSetup.");
213 220
214 hr = pAppDomainSetup->put_ApplicationBase(bstrAppBase); 221 hr = pAppDomainSetup->put_ApplicationBase(bstrAppBase);
215 ExitOnRootFailure(hr, "Failed to set the application base path for the AppDomainSetup."); 222 ExitOnRootFailure(hr, "Failed to set the application base path for the AppDomainSetup.");
216 223
217 bstrConfigPath = ::SysAllocString(sczConfigPath); 224 bstrConfigPath = ::SysAllocString(pState->sczConfigPath);
218 ExitOnNull(bstrConfigPath, hr, E_OUTOFMEMORY, "Failed to allocate the application configuration file for the AppDomainSetup."); 225 ExitOnNull(bstrConfigPath, hr, E_OUTOFMEMORY, "Failed to allocate the application configuration file for the AppDomainSetup.");
219 226
220 hr = pAppDomainSetup->put_ConfigurationFile(bstrConfigPath); 227 hr = pAppDomainSetup->put_ConfigurationFile(bstrConfigPath);
221 ExitOnRootFailure(hr, "Failed to set the configuration file path for the AppDomainSetup."); 228 ExitOnRootFailure(hr, "Failed to set the configuration file path for the AppDomainSetup.");
222 229
223 // Create the AppDomain to load the factory type. 230 // Create the AppDomain to load the factory type.
224 hr = pCLRHost->CreateDomainEx(L"MBA", pAppDomainSetup, NULL, &pUnk); 231 hr = pState->pCLRHost->CreateDomainEx(L"MBA", pAppDomainSetup, NULL, &pUnk);
225 ExitOnRootFailure(hr, "Failed to create the MBA AppDomain."); 232 ExitOnRootFailure(hr, "Failed to create the MBA AppDomain.");
226 233
227 hr = pUnk->QueryInterface(__uuidof(_AppDomain), reinterpret_cast<LPVOID*>(ppAppDomain)); 234 hr = pUnk->QueryInterface(__uuidof(_AppDomain), reinterpret_cast<LPVOID*>(&pState->pAppDomain));
228 ExitOnRootFailure(hr, "Failed to query for the _AppDomain interface."); 235 ExitOnRootFailure(hr, "Failed to query for the _AppDomain interface.");
229 236
230LExit: 237LExit:
231 ReleaseBSTR(bstrConfigPath); 238 ReleaseBSTR(bstrConfigPath);
232 ReleaseBSTR(bstrAppBase); 239 ReleaseBSTR(bstrAppBase);
233 ReleaseStr(sczConfigPath);
234 ReleaseStr(sczAppBase);
235 ReleaseNullObject(pUnk); 240 ReleaseNullObject(pUnk);
236 ReleaseNullObject(pCLRHost);
237 241
238 return hr; 242 return hr;
239} 243}
240 244
241static HRESULT GetAppBase( 245static HRESULT LoadModulePaths(
242 __out LPWSTR *psczAppBase 246 __in MBASTATE* pState
243 ) 247 )
244{ 248{
245 HRESULT hr = S_OK; 249 HRESULT hr = S_OK;
246 LPWSTR sczFullPath = NULL; 250 LPWSTR sczFullPath = NULL;
247 251
248 hr = PathForCurrentProcess(&sczFullPath, vhInstance); 252 hr = PathForCurrentProcess(&sczFullPath, pState->hInstance);
249 ExitOnFailure(hr, "Failed to get the full host path."); 253 ExitOnFailure(hr, "Failed to get the full host path.");
250 254
251 hr = PathGetDirectory(sczFullPath, psczAppBase); 255 hr = PathGetDirectory(sczFullPath, &pState->sczAppBase);
252 ExitOnFailure(hr, "Failed to get the directory of the full process path."); 256 ExitOnFailure(hr, "Failed to get the directory of the full process path.");
253 257
258 hr = PathConcat(pState->sczAppBase, MBA_CONFIG_FILE_NAME, &pState->sczConfigPath);
259 ExitOnFailure(hr, "Failed to get the full path to the application configuration file.");
260
254LExit: 261LExit:
255 ReleaseStr(sczFullPath); 262 ReleaseStr(sczFullPath);
256 263
@@ -390,9 +397,8 @@ LExit:
390} 397}
391 398
392// Gets the CLR host and caches it. 399// Gets the CLR host and caches it.
393static HRESULT GetCLRHost( 400static HRESULT LoadRuntime(
394 __in LPCWSTR wzConfigPath, 401 __in MBASTATE* pState
395 __out ICorRuntimeHost **ppCLRHost
396 ) 402 )
397{ 403{
398 HRESULT hr = S_OK; 404 HRESULT hr = S_OK;
@@ -411,84 +417,81 @@ static HRESULT GetCLRHost(
411 // Always set the error mode because we will always restore it below. 417 // Always set the error mode because we will always restore it below.
412 uiMode = ::SetErrorMode(0); 418 uiMode = ::SetErrorMode(0);
413 419
414 // Cache the CLR host to be shutdown later. This can occur on a different thread. 420 // Check that the supported framework is installed.
415 if (!vpCLRHost) 421 hr = CheckSupportedFrameworks(pState->sczConfigPath);
416 { 422 ExitOnFailure(hr, "Failed to find supported framework.");
417 // Disable message boxes from being displayed on error and blocking execution.
418 ::SetErrorMode(uiMode | SEM_FAILCRITICALERRORS);
419 423
420 hr = LoadSystemLibrary(L"mscoree.dll", &hModule); 424 // Cache the CLR host to be shutdown later. This can occur on a different thread.
421 ExitOnFailure(hr, "Failed to load mscoree.dll"); 425 // Disable message boxes from being displayed on error and blocking execution.
426 ::SetErrorMode(uiMode | SEM_FAILCRITICALERRORS);
422 427
423 pfnCLRCreateInstance = reinterpret_cast<CLRCreateInstanceFnPtr>(::GetProcAddress(hModule, "CLRCreateInstance")); 428 hr = LoadSystemLibrary(L"mscoree.dll", &hModule);
424 429 ExitOnFailure(hr, "Failed to load mscoree.dll");
425 if (pfnCLRCreateInstance)
426 {
427 hr = pfnCLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, reinterpret_cast<LPVOID*>(&pCLRMetaHostPolicy));
428 if (E_NOTIMPL != hr)
429 {
430 ExitOnRootFailure(hr, "Failed to create instance of ICLRMetaHostPolicy.");
431 430
432 fFallbackToCorBindToCurrentRuntime = FALSE; 431 pfnCLRCreateInstance = reinterpret_cast<CLRCreateInstanceFnPtr>(::GetProcAddress(hModule, "CLRCreateInstance"));
433 }
434 }
435 432
436 if (fFallbackToCorBindToCurrentRuntime) 433 if (pfnCLRCreateInstance)
434 {
435 hr = pfnCLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, reinterpret_cast<LPVOID*>(&pCLRMetaHostPolicy));
436 if (E_NOTIMPL != hr)
437 { 437 {
438 pfnCorBindToCurrentRuntime = reinterpret_cast<PFN_CORBINDTOCURRENTRUNTIME>(::GetProcAddress(hModule, "CorBindToCurrentRuntime")); 438 ExitOnRootFailure(hr, "Failed to create instance of ICLRMetaHostPolicy.");
439 ExitOnNullWithLastError(pfnCorBindToCurrentRuntime, hr, "Failed to get procedure address for CorBindToCurrentRuntime.");
440 439
441 hr = pfnCorBindToCurrentRuntime(wzConfigPath, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&vpCLRHost)); 440 fFallbackToCorBindToCurrentRuntime = FALSE;
442 ExitOnRootFailure(hr, "Failed to create the CLR host using the application configuration file path.");
443 } 441 }
444 else 442 }
445 {
446
447 hr = SHCreateStreamOnFileEx(wzConfigPath, STGM_READ | STGM_SHARE_DENY_WRITE, 0, FALSE, NULL, &pCfgStream);
448 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath);
449 443
450 hr = pCLRMetaHostPolicy->GetRequestedRuntime(METAHOST_POLICY_HIGHCOMPAT, NULL, pCfgStream, NULL, &cchVersion, NULL, NULL, &dwConfigFlags, IID_ICLRRuntimeInfo, reinterpret_cast<LPVOID*>(&pCLRRuntimeInfo)); 444 if (fFallbackToCorBindToCurrentRuntime)
451 ExitOnRootFailure(hr, "Failed to get the CLR runtime info using the application configuration file path."); 445 {
446 pfnCorBindToCurrentRuntime = reinterpret_cast<PFN_CORBINDTOCURRENTRUNTIME>(::GetProcAddress(hModule, "CorBindToCurrentRuntime"));
447 ExitOnNullWithLastError(pfnCorBindToCurrentRuntime, hr, "Failed to get procedure address for CorBindToCurrentRuntime.");
452 448
453 // .NET 4 RTM had a bug where it wouldn't set pcchVersion if pwzVersion was NULL. 449 hr = pfnCorBindToCurrentRuntime(pState->sczConfigPath, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&pState->pCLRHost));
454 if (!cchVersion) 450 ExitOnRootFailure(hr, "Failed to create the CLR host using the application configuration file path.");
455 { 451 }
456 hr = pCLRRuntimeInfo->GetVersionString(NULL, &cchVersion); 452 else
457 if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr) 453 {
458 {
459 ExitOnFailure(hr, "Failed to get the length of the CLR version string.");
460 }
461 }
462 454
463 hr = StrAlloc(&pwzVersion, cchVersion); 455 hr = SHCreateStreamOnFileEx(pState->sczConfigPath, STGM_READ | STGM_SHARE_DENY_WRITE, 0, FALSE, NULL, &pCfgStream);
464 ExitOnFailure(hr, "Failed to allocate the CLR version string."); 456 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", pState->sczConfigPath);
465 457
466 hr = pCLRRuntimeInfo->GetVersionString(pwzVersion, &cchVersion); 458 hr = pCLRMetaHostPolicy->GetRequestedRuntime(METAHOST_POLICY_HIGHCOMPAT, NULL, pCfgStream, NULL, &cchVersion, NULL, NULL, &dwConfigFlags, IID_ICLRRuntimeInfo, reinterpret_cast<LPVOID*>(&pCLRRuntimeInfo));
467 ExitOnFailure(hr, "Failed to get the CLR version string."); 459 ExitOnRootFailure(hr, "Failed to get the CLR runtime info using the application configuration file path.");
468 460
469 if (CSTR_EQUAL == CompareString(LOCALE_NEUTRAL, 0, L"v4.0.30319", -1, pwzVersion, cchVersion)) 461 // .NET 4 RTM had a bug where it wouldn't set pcchVersion if pwzVersion was NULL.
462 if (!cchVersion)
463 {
464 hr = pCLRRuntimeInfo->GetVersionString(NULL, &cchVersion);
465 if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
470 { 466 {
471 hr = VerifyNET4RuntimeIsSupported(); 467 ExitOnFailure(hr, "Failed to get the length of the CLR version string.");
472 ExitOnFailure(hr, "Found unsupported .NET 4 Runtime.");
473 } 468 }
469 }
474 470
475 if (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_TRUE == (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_MASK & dwConfigFlags)) 471 hr = StrAlloc(&pwzVersion, cchVersion);
476 { 472 ExitOnFailure(hr, "Failed to allocate the CLR version string.");
477 hr = pCLRRuntimeInfo->BindAsLegacyV2Runtime();
478 ExitOnRootFailure(hr, "Failed to bind as legacy V2 runtime.");
479 }
480 473
481 hr = pCLRRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&vpCLRHost)); 474 hr = pCLRRuntimeInfo->GetVersionString(pwzVersion, &cchVersion);
482 ExitOnRootFailure(hr, "Failed to get instance of ICorRuntimeHost."); 475 ExitOnFailure(hr, "Failed to get the CLR version string.");
476
477 if (CSTR_EQUAL == CompareString(LOCALE_NEUTRAL, 0, L"v4.0.30319", -1, pwzVersion, cchVersion))
478 {
479 hr = VerifyNET4RuntimeIsSupported();
480 ExitOnFailure(hr, "Found unsupported .NET 4 Runtime.");
481 }
483 482
484 // TODO: use ICLRRuntimeHost instead of ICorRuntimeHost on .NET 4 since the former is faster and the latter is deprecated 483 if (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_TRUE == (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_MASK & dwConfigFlags))
485 //hr = pCLRRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, reinterpret_cast<LPVOID*>(&pCLRRuntimeHost)); 484 {
486 //ExitOnRootFailure(hr, "Failed to get instance of ICLRRuntimeHost."); 485 hr = pCLRRuntimeInfo->BindAsLegacyV2Runtime();
486 ExitOnRootFailure(hr, "Failed to bind as legacy V2 runtime.");
487 } 487 }
488
489 hr = pCLRRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&pState->pCLRHost));
490 ExitOnRootFailure(hr, "Failed to get instance of ICorRuntimeHost.");
488 } 491 }
489 492
490 vpCLRHost->AddRef(); 493 hr = pState->pCLRHost->Start();
491 *ppCLRHost = vpCLRHost; 494 ExitOnRootFailure(hr, "Failed to start the CLR host.");
492 495
493LExit: 496LExit:
494 ReleaseStr(pwzVersion); 497 ReleaseStr(pwzVersion);
@@ -569,7 +572,7 @@ LExit:
569} 572}
570 573
571static HRESULT CreatePrerequisiteBA( 574static HRESULT CreatePrerequisiteBA(
572 __in HRESULT hrHostInitialization, 575 __in MBASTATE* pState,
573 __in IBootstrapperEngine* pEngine, 576 __in IBootstrapperEngine* pEngine,
574 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 577 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
575 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults 578 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
@@ -579,19 +582,19 @@ static HRESULT CreatePrerequisiteBA(
579 LPWSTR sczMbapreqPath = NULL; 582 LPWSTR sczMbapreqPath = NULL;
580 HMODULE hModule = NULL; 583 HMODULE hModule = NULL;
581 584
582 hr = PathRelativeToModule(&sczMbapreqPath, L"mbapreq.dll", vhInstance); 585 hr = PathConcat(pState->sczAppBase, L"mbapreq.dll", &sczMbapreqPath);
583 ExitOnFailure(hr, "Failed to get path to pre-requisite BA."); 586 BalExitOnFailure(hr, "Failed to get path to pre-requisite BA.");
584 587
585 hModule = ::LoadLibraryW(sczMbapreqPath); 588 hModule = ::LoadLibraryExW(sczMbapreqPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
586 ExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL."); 589 ExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL.");
587 590
588 PFN_MBAPREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_MBAPREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "MbaPrereqBootstrapperApplicationCreate")); 591 PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "PrereqBootstrapperApplicationCreate"));
589 ExitOnNullWithLastError(pfnCreate, hr, "Failed to get MbaPrereqBootstrapperApplicationCreate entry-point from: %ls", sczMbapreqPath); 592 ExitOnNullWithLastError(pfnCreate, hr, "Failed to get PrereqBootstrapperApplicationCreate entry-point from: %ls", sczMbapreqPath);
590 593
591 hr = pfnCreate(hrHostInitialization, pEngine, pArgs, pResults); 594 hr = pfnCreate(&pState->prereqData, pEngine, pArgs, pResults);
592 ExitOnFailure(hr, "Failed to create prequisite bootstrapper app."); 595 ExitOnFailure(hr, "Failed to create prequisite bootstrapper app.");
593 596
594 vhMbapreqModule = hModule; 597 pState->hMbapreqModule = hModule;
595 hModule = NULL; 598 hModule = NULL;
596 599
597LExit: 600LExit:
diff --git a/src/ext/Bal/mbahost/mbahost.h b/src/ext/Bal/mbahost/mbahost.h
new file mode 100644
index 00000000..19cf8311
--- /dev/null
+++ b/src/ext/Bal/mbahost/mbahost.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
5struct MBASTATE
6{
7 BOOL fInitialized;
8 BOOL fInitializedRuntime;
9 BOOL fStoppedRuntime;
10 HINSTANCE hInstance;
11 LPWSTR sczAppBase;
12 LPWSTR sczConfigPath;
13 mscorlib::_AppDomain* pAppDomain;
14 ICorRuntimeHost* pCLRHost;
15 HMODULE hMbapreqModule;
16 PREQBA_DATA prereqData;
17};
diff --git a/src/ext/Bal/mbahost/mbahost.vcxproj b/src/ext/Bal/mbahost/mbahost.vcxproj
index cd90776b..a8fbbcc2 100644
--- a/src/ext/Bal/mbahost/mbahost.vcxproj
+++ b/src/ext/Bal/mbahost/mbahost.vcxproj
@@ -41,7 +41,7 @@
41 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> 41 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
42 42
43 <PropertyGroup> 43 <PropertyGroup>
44 <ProjectAdditionalIncludeDirectories>$(BaseOutputPath)obj</ProjectAdditionalIncludeDirectories> 44 <ProjectAdditionalIncludeDirectories>$(BaseOutputPath)obj;..\wixstdba\inc</ProjectAdditionalIncludeDirectories>
45 <ProjectAdditionalLinkLibraries>shlwapi.lib</ProjectAdditionalLinkLibraries> 45 <ProjectAdditionalLinkLibraries>shlwapi.lib</ProjectAdditionalLinkLibraries>
46 </PropertyGroup> 46 </PropertyGroup>
47 47
@@ -52,6 +52,7 @@
52 </ClCompile> 52 </ClCompile>
53 </ItemGroup> 53 </ItemGroup>
54 <ItemGroup> 54 <ItemGroup>
55 <ClInclude Include="mbahost.h" />
55 <ClInclude Include="precomp.h" /> 56 <ClInclude Include="precomp.h" />
56 </ItemGroup> 57 </ItemGroup>
57 <ItemGroup> 58 <ItemGroup>
diff --git a/src/ext/Bal/mbahost/precomp.h b/src/ext/Bal/mbahost/precomp.h
index d29a23f3..a07f2fc0 100644
--- a/src/ext/Bal/mbahost/precomp.h
+++ b/src/ext/Bal/mbahost/precomp.h
@@ -16,10 +16,15 @@
16#include <strutil.h> 16#include <strutil.h>
17#include <xmlutil.h> 17#include <xmlutil.h>
18 18
19#include "BootstrapperEngine.h" 19#include <BootstrapperEngine.h>
20#include "BootstrapperApplication.h" 20#include <BootstrapperApplication.h>
21#include "IBootstrapperEngine.h" 21#include <IBootstrapperEngine.h>
22#include "IBootstrapperApplication.h" 22#include <IBootstrapperApplication.h>
23#include "IBootstrapperApplicationFactory.h" 23#include <IBootstrapperApplicationFactory.h>
24 24
25#include "balutil.h" 25#include <balutil.h>
26
27#include <preqba.h>
28#include <WixToolset.Mba.Host.h> // includes the generated assembly name macros.
29
30#include "mbahost.h"
diff --git a/src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp b/src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp
index 46fd9afa..3f290b86 100644
--- a/src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp
+++ b/src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp
@@ -31,7 +31,7 @@ HRESULT RunReloadEngine(
31 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER); 31 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER);
32 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown."); 32 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
33 33
34 pTestEngine->UnloadBA(); 34 pTestEngine->UnloadBA(TRUE);
35 35
36 hr = pTestEngine->LoadBA(wzBAFilePath); 36 hr = pTestEngine->LoadBA(wzBAFilePath);
37 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to load BA."); 37 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to load BA.");
@@ -48,7 +48,7 @@ HRESULT RunReloadEngine(
48 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RESTART); 48 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RESTART);
49 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown."); 49 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
50 50
51 pTestEngine->UnloadBA(); 51 pTestEngine->UnloadBA(FALSE);
52 52
53LExit: 53LExit:
54 return hr; 54 return hr;
diff --git a/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp b/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp
index 3b876e4e..b5c8c462 100644
--- a/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp
+++ b/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp
@@ -31,7 +31,7 @@ HRESULT RunShutdownEngine(
31 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER); 31 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER);
32 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown."); 32 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
33 33
34 pTestEngine->UnloadBA(); 34 pTestEngine->UnloadBA(FALSE);
35 35
36LExit: 36LExit:
37 return hr; 37 return hr;
diff --git a/src/ext/Bal/test/examples/TestEngine/TestEngine.cpp b/src/ext/Bal/test/examples/TestEngine/TestEngine.cpp
index 4c7ec1c3..5c6ed398 100644
--- a/src/ext/Bal/test/examples/TestEngine/TestEngine.cpp
+++ b/src/ext/Bal/test/examples/TestEngine/TestEngine.cpp
@@ -147,10 +147,18 @@ HRESULT TestEngine::SimulateQuit(
147 return BAEngineQuit(&args, &results); 147 return BAEngineQuit(&args, &results);
148} 148}
149 149
150void TestEngine::UnloadBA() 150void TestEngine::UnloadBA(
151 __in BOOL fReload
152 )
151{ 153{
152 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = NULL; 154 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = NULL;
153 BOOL fDisableUnloading = m_pCreateResults && m_pCreateResults->fDisableUnloading; 155 BOOTSTRAPPER_DESTROY_ARGS args = { };
156 BOOTSTRAPPER_DESTROY_RESULTS results = { };
157
158 args.cbSize = sizeof(args);
159 args.fReload = fReload;
160
161 results.cbSize = sizeof(results);
154 162
155 ReleaseNullMem(m_pCreateResults); 163 ReleaseNullMem(m_pCreateResults);
156 164
@@ -158,12 +166,12 @@ void TestEngine::UnloadBA()
158 166
159 if (pfnDestroy) 167 if (pfnDestroy)
160 { 168 {
161 pfnDestroy(); 169 pfnDestroy(&args, &results);
162 } 170 }
163 171
164 if (m_hBAModule) 172 if (m_hBAModule)
165 { 173 {
166 if (!fDisableUnloading) 174 if (!results.fDisableUnloading)
167 { 175 {
168 ::FreeLibrary(m_hBAModule); 176 ::FreeLibrary(m_hBAModule);
169 } 177 }
diff --git a/src/ext/Bal/test/examples/TestEngine/TestEngine.h b/src/ext/Bal/test/examples/TestEngine/TestEngine.h
index 44e813bd..248e979a 100644
--- a/src/ext/Bal/test/examples/TestEngine/TestEngine.h
+++ b/src/ext/Bal/test/examples/TestEngine/TestEngine.h
@@ -44,7 +44,9 @@ public:
44 __in DWORD dwExitCode 44 __in DWORD dwExitCode
45 ); 45 );
46 46
47 void UnloadBA(); 47 void UnloadBA(
48 __in BOOL fReload
49 );
48 50
49private: 51private:
50 HRESULT BAEngineLog( 52 HRESULT BAEngineLog(
@@ -77,4 +79,4 @@ private:
77 HMODULE m_hBAModule; 79 HMODULE m_hBAModule;
78 BOOTSTRAPPER_CREATE_RESULTS* m_pCreateResults; 80 BOOTSTRAPPER_CREATE_RESULTS* m_pCreateResults;
79 DWORD m_dwThreadId; 81 DWORD m_dwThreadId;
80}; \ No newline at end of file 82};
diff --git a/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp b/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp
index 2f80ba75..64b618f4 100644
--- a/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp
+++ b/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp
@@ -28,7 +28,7 @@ HRESULT RunWaitForQuitEngine(
28 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER); 28 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER);
29 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown."); 29 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
30 30
31 pTestEngine->UnloadBA(); 31 pTestEngine->UnloadBA(FALSE);
32 32
33LExit: 33LExit:
34 return hr; 34 return hr;
diff --git a/src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl
index 19e79bac..f574bb9b 100644
--- a/src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl
@@ -29,5 +29,6 @@
29 <String Id="FailureRestartButton">重新啟動(&amp;R)</String> 29 <String Id="FailureRestartButton">重新啟動(&amp;R)</String>
30 <String Id="FailureCloseButton">關閉(&amp;C)</String> 30 <String Id="FailureCloseButton">關閉(&amp;C)</String>
31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
32 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
32 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 33 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
33</WixLocalization> 34</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl
index e6e6f469..11d9f85a 100644
--- a/src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Restartovat</String> 32 <String Id="FailureRestartButton">&amp;Restartovat</String>
33 <String Id="FailureCloseButton">&amp;Zavřít</String> 33 <String Id="FailureCloseButton">&amp;Zavřít</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl
index 98518edc..50412e12 100644
--- a/src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Genstart</String> 32 <String Id="FailureRestartButton">&amp;Genstart</String>
33 <String Id="FailureCloseButton">&amp;Luk</String> 33 <String Id="FailureCloseButton">&amp;Luk</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl
index e60b0c9a..4df66298 100644
--- a/src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl
@@ -35,5 +35,6 @@
35 <String Id="FailureRestartButton">&amp;Neu starten</String> 35 <String Id="FailureRestartButton">&amp;Neu starten</String>
36 <String Id="FailureCloseButton">&amp;Schließen</String> 36 <String Id="FailureCloseButton">&amp;Schließen</String>
37 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 37 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
38 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
38 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 39 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
39</WixLocalization> 40</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl
index ea5dc130..05ac553f 100644
--- a/src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl
@@ -34,5 +34,6 @@
34 <String Id="FailureRestartButton">&amp;Επανεκκίνηση</String> 34 <String Id="FailureRestartButton">&amp;Επανεκκίνηση</String>
35 <String Id="FailureCloseButton">&amp;Κλείσιμο</String> 35 <String Id="FailureCloseButton">&amp;Κλείσιμο</String>
36 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 36 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
37 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
37 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 38 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
38</WixLocalization> 39</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl
index 803cacf5..2b7c0519 100644
--- a/src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Käynnistä uudelleen</String> 32 <String Id="FailureRestartButton">&amp;Käynnistä uudelleen</String>
33 <String Id="FailureCloseButton">&amp;Sulje</String> 33 <String Id="FailureCloseButton">&amp;Sulje</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl
index fb927f2b..3ae1cbd9 100644
--- a/src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Redémarrer</String> 32 <String Id="FailureRestartButton">&amp;Redémarrer</String>
33 <String Id="FailureCloseButton">&amp;Fermer</String> 33 <String Id="FailureCloseButton">&amp;Fermer</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl
index 78c008b2..f491d6f2 100644
--- a/src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Újraindítás</String> 32 <String Id="FailureRestartButton">&amp;Újraindítás</String>
33 <String Id="FailureCloseButton">&amp;Bezárás</String> 33 <String Id="FailureCloseButton">&amp;Bezárás</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl
index b7966340..50bc73e8 100644
--- a/src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl
@@ -33,5 +33,6 @@
33 <String Id="FailureRestartButton">&amp;Riavvia</String> 33 <String Id="FailureRestartButton">&amp;Riavvia</String>
34 <String Id="FailureCloseButton">&amp;Chiudi</String> 34 <String Id="FailureCloseButton">&amp;Chiudi</String>
35 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 35 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
36 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 37 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
37</WixLocalization> 38</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl
index 9b7aa323..106c704a 100644
--- a/src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl
@@ -29,5 +29,6 @@
29 <String Id="FailureRestartButton">再起動(&amp;R)</String> 29 <String Id="FailureRestartButton">再起動(&amp;R)</String>
30 <String Id="FailureCloseButton">閉じる(&amp;C)</String> 30 <String Id="FailureCloseButton">閉じる(&amp;C)</String>
31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
32 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
32 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 33 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
33</WixLocalization> 34</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl
index 445d445b..24655588 100644
--- a/src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl
@@ -29,5 +29,6 @@
29 <String Id="FailureRestartButton">다시 시작(&amp;R)</String> 29 <String Id="FailureRestartButton">다시 시작(&amp;R)</String>
30 <String Id="FailureCloseButton">닫기(&amp;C)</String> 30 <String Id="FailureCloseButton">닫기(&amp;C)</String>
31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
32 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
32 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 33 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
33</WixLocalization> 34</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl
index 60ba996e..d2e572fc 100644
--- a/src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Opnieuw opstarten</String> 32 <String Id="FailureRestartButton">&amp;Opnieuw opstarten</String>
33 <String Id="FailureCloseButton">&amp;Sluiten</String> 33 <String Id="FailureCloseButton">&amp;Sluiten</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl
index e0718b8d..cb6036ee 100644
--- a/src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Start på nytt</String> 32 <String Id="FailureRestartButton">&amp;Start på nytt</String>
33 <String Id="FailureCloseButton">&amp;Lukk</String> 33 <String Id="FailureCloseButton">&amp;Lukk</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl
index 8b4eb758..41832b13 100644
--- a/src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Uruchom ponownie</String> 32 <String Id="FailureRestartButton">&amp;Uruchom ponownie</String>
33 <String Id="FailureCloseButton">&amp;Zamknij</String> 33 <String Id="FailureCloseButton">&amp;Zamknij</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl
index 0155eb39..08968f93 100644
--- a/src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl
@@ -31,5 +31,6 @@
31 <String Id="FailureRestartButton">&amp;Reiniciar</String> 31 <String Id="FailureRestartButton">&amp;Reiniciar</String>
32 <String Id="FailureCloseButton">&amp;Fechar</String> 32 <String Id="FailureCloseButton">&amp;Fechar</String>
33 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 33 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
34 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
34 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
35</WixLocalization> 36</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl
index 87350745..271d5563 100644
--- a/src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl
@@ -31,5 +31,6 @@
31 <String Id="FailureRestartButton">&amp;Перезагрузить</String> 31 <String Id="FailureRestartButton">&amp;Перезагрузить</String>
32 <String Id="FailureCloseButton">&amp;Закрыть</String> 32 <String Id="FailureCloseButton">&amp;Закрыть</String>
33 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 33 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
34 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
34 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
35</WixLocalization> 36</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl
index 7645a37f..ce6f6eda 100644
--- a/src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Reštartovať</String> 32 <String Id="FailureRestartButton">&amp;Reštartovať</String>
33 <String Id="FailureCloseButton">&amp;Zavrieť</String> 33 <String Id="FailureCloseButton">&amp;Zavrieť</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl
index b00205d8..2d0581b1 100644
--- a/src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Starta om</String> 32 <String Id="FailureRestartButton">&amp;Starta om</String>
33 <String Id="FailureCloseButton">&amp;Stäng</String> 33 <String Id="FailureCloseButton">&amp;Stäng</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl
index 00c3c187..c48a44da 100644
--- a/src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Yeniden Başlat</String> 32 <String Id="FailureRestartButton">&amp;Yeniden Başlat</String>
33 <String Id="FailureCloseButton">&amp;Kapat</String> 33 <String Id="FailureCloseButton">&amp;Kapat</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl
index 72d48267..0398a7f1 100644
--- a/src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl
@@ -32,5 +32,6 @@
32 <String Id="FailureRestartButton">&amp;Ponovni zagon</String> 32 <String Id="FailureRestartButton">&amp;Ponovni zagon</String>
33 <String Id="FailureCloseButton">&amp;Zapri</String> 33 <String Id="FailureCloseButton">&amp;Zapri</String>
34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 34 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
35 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
36</WixLocalization> 37</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl
index 365ee7e6..09f09cb3 100644
--- a/src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl
@@ -29,5 +29,6 @@
29 <String Id="FailureRestartButton">重启(&amp;R)</String> 29 <String Id="FailureRestartButton">重启(&amp;R)</String>
30 <String Id="FailureCloseButton">关闭(&amp;C)</String> 30 <String Id="FailureCloseButton">关闭(&amp;C)</String>
31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
32 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
32 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 33 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
33</WixLocalization> 34</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl
index 442a5571..f22822d8 100644
--- a/src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl
@@ -31,5 +31,6 @@
31 <String Id="FailureRestartButton">&amp;Reiniciar</String> 31 <String Id="FailureRestartButton">&amp;Reiniciar</String>
32 <String Id="FailureCloseButton">&amp;Fechar</String> 32 <String Id="FailureCloseButton">&amp;Fechar</String>
33 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 33 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
34 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
34 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 35 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
35</WixLocalization> 36</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl
index 37c0dc05..edbf01c4 100644
--- a/src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl
@@ -33,5 +33,6 @@
33 <String Id="FailureRestartButton">&amp;Reiniciar</String> 33 <String Id="FailureRestartButton">&amp;Reiniciar</String>
34 <String Id="FailureCloseButton">&amp;Cerrar</String> 34 <String Id="FailureCloseButton">&amp;Cerrar</String>
35 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 35 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
36 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
36 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 37 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
37</WixLocalization> 38</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/dncpreq.wxl b/src/ext/Bal/wixstdba/Resources/dncpreq.wxl
index a53b1c83..22fcd3dc 100644
--- a/src/ext/Bal/wixstdba/Resources/dncpreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/dncpreq.wxl
@@ -29,5 +29,6 @@
29 <String Id="FailureRestartButton">&amp;Restart</String> 29 <String Id="FailureRestartButton">&amp;Restart</String>
30 <String Id="FailureCloseButton">&amp;Close</String> 30 <String Id="FailureCloseButton">&amp;Close</String>
31 <String Id="SCDRUNTIMEFAILUREErrorMessage">[WixBundleName] cannot run on this machine. Install the latest updates and/or the latest OS to run in a supported environment.</String> 31 <String Id="SCDRUNTIMEFAILUREErrorMessage">[WixBundleName] cannot run on this machine. Install the latest updates and/or the latest OS to run in a supported environment.</String>
32 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Core runtime even though all of the prerequisites are installed.</String>
32 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 33 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
33</WixLocalization> 34</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/mbapreq.wxl
index 5d410888..77859d31 100644
--- a/src/ext/Bal/wixstdba/Resources/mbapreq.wxl
+++ b/src/ext/Bal/wixstdba/Resources/mbapreq.wxl
@@ -29,5 +29,6 @@
29 <String Id="FailureRestartButton">&amp;Restart</String> 29 <String Id="FailureRestartButton">&amp;Restart</String>
30 <String Id="FailureCloseButton">&amp;Close</String> 30 <String Id="FailureCloseButton">&amp;Close</String>
31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String> 31 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
32 <String Id="PREREQBAINFINITELOOPErrorMessage">[WixBundleName] failed to load the .NET Framework runtime even though all of the prerequisites are installed.</String>
32 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String> 33 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
33</WixLocalization> 34</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
index dd00a563..3774f49c 100644
--- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
@@ -123,14 +123,6 @@ enum WIXSTDBA_CONTROL
123 LAST_WIXSTDBA_CONTROL, 123 LAST_WIXSTDBA_CONTROL,
124}; 124};
125 125
126typedef struct _WIXSTDBA_PACKAGE_INFO
127{
128 LPWSTR sczPackageId;
129 BOOL fWasAlreadyInstalled;
130 BOOL fPlannedToBeInstalled;
131 BOOL fSuccessfullyInstalled;
132} WIXSTDBA_PACKAGE_INFO;
133
134 126
135static HRESULT DAPI EvaluateVariableConditionCallback( 127static HRESULT DAPI EvaluateVariableConditionCallback(
136 __in_z LPCWSTR wzCondition, 128 __in_z LPCWSTR wzCondition,
@@ -229,10 +221,7 @@ public: // IBootstrapperApplication
229 { 221 {
230 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were successfully installed. The bootstrapper application will be reloaded."); 222 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were successfully installed. The bootstrapper application will be reloaded.");
231 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER; 223 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER;
232 } 224 m_pPrereqData->fCompleted = TRUE;
233 else if (m_fPrereqAlreadyInstalled)
234 {
235 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were already installed. The bootstrapper application will not be reloaded to prevent an infinite loop.");
236 } 225 }
237 else if (m_fPrereq) 226 else if (m_fPrereq)
238 { 227 {
@@ -311,38 +300,14 @@ public: // IBootstrapperApplication
311 300
312 if (!fMissingFromCache) 301 if (!fMissingFromCache)
313 { 302 {
314 if (SUCCEEDED(BalInfoAddRelatedBundleAsPackage(&m_Bundle.packages, wzBundleId, relationType, fPerMachine, &pPackage))) 303 BalInfoAddRelatedBundleAsPackage(&m_Bundle.packages, wzBundleId, relationType, fPerMachine, &pPackage);
315 { 304 // Best effort
316 InitializePackageInfoForPackage(pPackage);
317 }
318 } 305 }
319 306
320 return CBalBaseBootstrapperApplication::OnDetectRelatedBundle(wzBundleId, relationType, wzBundleTag, fPerMachine, wzVersion, fMissingFromCache, pfCancel); 307 return CBalBaseBootstrapperApplication::OnDetectRelatedBundle(wzBundleId, relationType, wzBundleTag, fPerMachine, wzVersion, fMissingFromCache, pfCancel);
321 } 308 }
322 309
323 310
324 virtual STDMETHODIMP OnDetectPackageComplete(
325 __in LPCWSTR wzPackageId,
326 __in HRESULT /*hrStatus*/,
327 __in BOOTSTRAPPER_PACKAGE_STATE state,
328 __in BOOL /*fCached*/
329 )
330 {
331 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
332 BAL_INFO_PACKAGE* pPackage = NULL;
333
334 if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state &&
335 SUCCEEDED(GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage)) &&
336 pPackageInfo)
337 {
338 // If the package is already installed, remember that.
339 pPackageInfo->fWasAlreadyInstalled = TRUE;
340 }
341
342 return S_OK;
343 }
344
345
346 virtual STDMETHODIMP OnDetectComplete( 311 virtual STDMETHODIMP OnDetectComplete(
347 __in HRESULT hrStatus, 312 __in HRESULT hrStatus,
348 __in BOOL /*fEligibleForCleanup*/ 313 __in BOOL /*fEligibleForCleanup*/
@@ -366,29 +331,10 @@ public: // IBootstrapperApplication
366 if (fEvaluateConditions) 331 if (fEvaluateConditions)
367 { 332 {
368 hrStatus = EvaluateConditions(); 333 hrStatus = EvaluateConditions();
369 }
370 334
371 if (FAILED(hrStatus)) 335 if (FAILED(hrStatus))
372 {
373 fSkipToPlan = FALSE;
374 }
375 else
376 {
377 if (m_fPrereq)
378 { 336 {
379 m_fPrereqAlreadyInstalled = TRUE; 337 fSkipToPlan = FALSE;
380
381 // At this point we have to assume that all prerequisite packages need to be installed, so set to false if any of them aren't installed.
382 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
383 {
384 BAL_INFO_PACKAGE* pPackage = &m_Bundle.packages.rgPackages[i];
385 WIXSTDBA_PACKAGE_INFO* pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
386 if (pPackage->fPrereqPackage && pPackageInfo && !pPackageInfo->fWasAlreadyInstalled)
387 {
388 m_fPrereqAlreadyInstalled = FALSE;
389 break;
390 }
391 }
392 } 338 }
393 } 339 }
394 340
@@ -403,20 +349,20 @@ public: // IBootstrapperApplication
403 } 349 }
404 350
405 351
406 virtual STDMETHODIMP OnPlanRelatedBundle( 352 virtual STDMETHODIMP OnPlanRelatedBundleType(
407 __in_z LPCWSTR wzBundleId, 353 __in_z LPCWSTR wzBundleId,
408 __in BOOTSTRAPPER_REQUEST_STATE recommendedState, 354 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE recommendedType,
409 __inout_z BOOTSTRAPPER_REQUEST_STATE* pRequestedState, 355 __inout BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE* pRequestedType,
410 __inout BOOL* pfCancel 356 __inout BOOL* pfCancel
411 ) 357 )
412 { 358 {
413 // If we're only installing prerequisites, do not touch related bundles. 359 // If we're only installing prerequisites, do not touch related bundles.
414 if (m_fPrereq) 360 if (m_fPrereq)
415 { 361 {
416 *pRequestedState = BOOTSTRAPPER_REQUEST_STATE_NONE; 362 *pRequestedType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE;
417 } 363 }
418 364
419 return CBalBaseBootstrapperApplication::OnPlanRelatedBundle(wzBundleId, recommendedState, pRequestedState, pfCancel); 365 return CBalBaseBootstrapperApplication::OnPlanRelatedBundleType(wzBundleId, recommendedType, pRequestedType, pfCancel);
420 } 366 }
421 367
422 368
@@ -434,7 +380,6 @@ public: // IBootstrapperApplication
434 ) 380 )
435 { 381 {
436 HRESULT hr = S_OK; 382 HRESULT hr = S_OK;
437 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
438 BAL_INFO_PACKAGE* pPackage = NULL; 383 BAL_INFO_PACKAGE* pPackage = NULL;
439 384
440 // If we're planning to install prerequisites, install them. The prerequisites need to be installed 385 // If we're planning to install prerequisites, install them. The prerequisites need to be installed
@@ -443,10 +388,11 @@ public: // IBootstrapperApplication
443 { 388 {
444 // Only install prerequisite packages, and check the InstallCondition on them. 389 // Only install prerequisite packages, and check the InstallCondition on them.
445 BOOL fInstall = FALSE; 390 BOOL fInstall = FALSE;
446 hr = GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage); 391
447 if (SUCCEEDED(hr) && pPackage->fPrereqPackage && pPackageInfo) 392 hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
393 if (SUCCEEDED(hr) && pPackage->fPrereqPackage)
448 { 394 {
449 pPackageInfo->fPlannedToBeInstalled = fInstall = BOOTSTRAPPER_PACKAGE_CONDITION_FALSE != installCondition; 395 fInstall = BOOTSTRAPPER_PACKAGE_CONDITION_FALSE != installCondition;
450 } 396 }
451 397
452 if (fInstall) 398 if (fInstall)
@@ -503,7 +449,6 @@ public: // IBootstrapperApplication
503 ) 449 )
504 { 450 {
505 HRESULT hr = S_OK; 451 HRESULT hr = S_OK;
506 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
507 BAL_INFO_PACKAGE* pPackage = NULL; 452 BAL_INFO_PACKAGE* pPackage = NULL;
508 BOOL fShowInternalUI = FALSE; 453 BOOL fShowInternalUI = FALSE;
509 INSTALLUILEVEL uiLevel = INSTALLUILEVEL_NOCHANGE; 454 INSTALLUILEVEL uiLevel = INSTALLUILEVEL_NOCHANGE;
@@ -521,7 +466,7 @@ public: // IBootstrapperApplication
521 466
522 if (INSTALLUILEVEL_NOCHANGE != uiLevel) 467 if (INSTALLUILEVEL_NOCHANGE != uiLevel)
523 { 468 {
524 hr = GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage); 469 hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
525 if (SUCCEEDED(hr) && pPackage->sczDisplayInternalUICondition) 470 if (SUCCEEDED(hr) && pPackage->sczDisplayInternalUICondition)
526 { 471 {
527 hr = BalEvaluateCondition(pPackage->sczDisplayInternalUICondition, &fShowInternalUI); 472 hr = BalEvaluateCondition(pPackage->sczDisplayInternalUICondition, &fShowInternalUI);
@@ -545,23 +490,6 @@ public: // IBootstrapperApplication
545 { 490 {
546 HRESULT hr = S_OK; 491 HRESULT hr = S_OK;
547 492
548 if (m_fPrereq)
549 {
550 m_fPrereqAlreadyInstalled = TRUE;
551
552 // Now that we've planned the packages, we can focus on the prerequisite packages that are supposed to be installed.
553 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
554 {
555 BAL_INFO_PACKAGE* pPackage = &m_Bundle.packages.rgPackages[i];
556 WIXSTDBA_PACKAGE_INFO* pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
557 if (pPackage->fPrereqPackage && pPackageInfo && !pPackageInfo->fWasAlreadyInstalled && pPackageInfo->fPlannedToBeInstalled)
558 {
559 m_fPrereqAlreadyInstalled = FALSE;
560 break;
561 }
562 }
563 }
564
565 SetState(WIXSTDBA_STATE_PLANNED, hrStatus); 493 SetState(WIXSTDBA_STATE_PLANNED, hrStatus);
566 494
567 if (SUCCEEDED(hrStatus)) 495 if (SUCCEEDED(hrStatus))
@@ -1033,13 +961,10 @@ public: // IBootstrapperApplication
1033 961
1034 hr = __super::OnExecutePackageComplete(wzPackageId, hrStatus, restart, recommendation, pAction); 962 hr = __super::OnExecutePackageComplete(wzPackageId, hrStatus, restart, recommendation, pAction);
1035 963
1036 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL; 964 BAL_INFO_PACKAGE* pPackage = NULL;
1037 BAL_INFO_PACKAGE* pPackage; 965 HRESULT hrPrereq = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
1038 HRESULT hrPrereq = GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage); 966 if (SUCCEEDED(hrPrereq))
1039 if (SUCCEEDED(hrPrereq) && pPackageInfo)
1040 { 967 {
1041 pPackageInfo->fSuccessfullyInstalled = SUCCEEDED(hrStatus);
1042
1043 // If the prerequisite required a restart (any restart) then do an immediate 968 // If the prerequisite required a restart (any restart) then do an immediate
1044 // restart to ensure that the bundle will get launched again post reboot. 969 // restart to ensure that the bundle will get launched again post reboot.
1045 if (m_fPrereq && pPackage->fPrereqPackage && BOOTSTRAPPER_APPLY_RESTART_NONE != restart) 970 if (m_fPrereq && pPackage->fPrereqPackage && BOOTSTRAPPER_APPLY_RESTART_NONE != restart)
@@ -1157,28 +1082,7 @@ public: // IBootstrapperApplication
1157 1082
1158 if (m_fPrereq) 1083 if (m_fPrereq)
1159 { 1084 {
1160 m_fPrereqInstalled = TRUE; 1085 m_fPrereqInstalled = SUCCEEDED(hrStatus);
1161 BOOL fInstalledAPackage = FALSE;
1162
1163 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
1164 {
1165 BAL_INFO_PACKAGE* pPackage = &m_Bundle.packages.rgPackages[i];
1166 WIXSTDBA_PACKAGE_INFO* pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
1167 if (pPackage->fPrereqPackage && pPackageInfo && pPackageInfo->fPlannedToBeInstalled && !pPackageInfo->fWasAlreadyInstalled)
1168 {
1169 if (pPackageInfo->fSuccessfullyInstalled)
1170 {
1171 fInstalledAPackage = TRUE;
1172 }
1173 else
1174 {
1175 m_fPrereqInstalled = FALSE;
1176 break;
1177 }
1178 }
1179 }
1180
1181 m_fPrereqInstalled = m_fPrereqInstalled && fInstalledAPackage;
1182 } 1086 }
1183 1087
1184 // If we are showing UI, wait a beat before moving to the final screen. 1088 // If we are showing UI, wait a beat before moving to the final screen.
@@ -1223,10 +1127,10 @@ public: // IBootstrapperApplication
1223 { 1127 {
1224 BAL_INFO_PACKAGE* pPackage = NULL; 1128 BAL_INFO_PACKAGE* pPackage = NULL;
1225 1129
1226 if (SUCCEEDED(hrStatus) && wzNewPackageId && 1130 if (SUCCEEDED(hrStatus) && wzNewPackageId)
1227 SUCCEEDED(BalInfoAddUpdateBundleAsPackage(&m_Bundle.packages, wzNewPackageId, wzPreviousPackageId, &pPackage)))
1228 { 1131 {
1229 InitializePackageInfoForPackage(pPackage); 1132 BalInfoAddUpdateBundleAsPackage(&m_Bundle.packages, wzNewPackageId, wzPreviousPackageId, &pPackage);
1133 // Best effort
1230 } 1134 }
1231 1135
1232 return S_OK; 1136 return S_OK;
@@ -2201,6 +2105,36 @@ public: //CBalBaseBootstrapperApplication
2201 return hr; 2105 return hr;
2202 } 2106 }
2203 2107
2108 void Uninitialize(
2109 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
2110 __in BOOTSTRAPPER_DESTROY_RESULTS* /*pResults*/
2111 )
2112 {
2113 if (m_hBAFModule)
2114 {
2115 BA_FUNCTIONS_DESTROY_ARGS args = { };
2116 BA_FUNCTIONS_DESTROY_RESULTS results = { };
2117
2118 args.cbSize = sizeof(BA_FUNCTIONS_DESTROY_ARGS);
2119 args.fReload = pArgs->fReload;
2120
2121 results.cbSize = sizeof(BA_FUNCTIONS_DESTROY_RESULTS);
2122
2123 PFN_BA_FUNCTIONS_DESTROY pfnBAFunctionsDestroy = reinterpret_cast<PFN_BA_FUNCTIONS_DESTROY>(::GetProcAddress(m_hBAFModule, "BAFunctionsDestroy"));
2124 if (pfnBAFunctionsDestroy)
2125 {
2126 pfnBAFunctionsDestroy(&args, &results);
2127 }
2128
2129 if (!results.fDisableUnloading)
2130 {
2131 ::FreeLibrary(m_hBAFModule);
2132 m_hBAFModule = NULL;
2133 }
2134 }
2135 }
2136
2137
2204private: 2138private:
2205 // 2139 //
2206 // UiThreadProc - entrypoint for UI thread. 2140 // UiThreadProc - entrypoint for UI thread.
@@ -2214,6 +2148,7 @@ private:
2214 BOOL fComInitialized = FALSE; 2148 BOOL fComInitialized = FALSE;
2215 BOOL fRet = FALSE; 2149 BOOL fRet = FALSE;
2216 MSG msg = { }; 2150 MSG msg = { };
2151 DWORD dwQuit = 0;
2217 2152
2218 // Initialize COM and theme. 2153 // Initialize COM and theme.
2219 hr = ::CoInitialize(NULL); 2154 hr = ::CoInitialize(NULL);
@@ -2274,8 +2209,6 @@ private:
2274 pThis->DestroyMainWindow(); 2209 pThis->DestroyMainWindow();
2275 pThis->UninitializeTaskbarButton(); 2210 pThis->UninitializeTaskbarButton();
2276 2211
2277 // initiate engine shutdown
2278 DWORD dwQuit = HRESULT_CODE(hr);
2279 if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->m_restartResult) 2212 if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->m_restartResult)
2280 { 2213 {
2281 dwQuit = ERROR_SUCCESS_REBOOT_INITIATED; 2214 dwQuit = ERROR_SUCCESS_REBOOT_INITIATED;
@@ -2284,6 +2217,17 @@ private:
2284 { 2217 {
2285 dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED; 2218 dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED;
2286 } 2219 }
2220 else if (SEVERITY_ERROR == HRESULT_SEVERITY(hr) && FACILITY_WIN32 == HRESULT_FACILITY(hr))
2221 {
2222 // Convert Win32 HRESULTs back to the error code.
2223 dwQuit = HRESULT_CODE(hr);
2224 }
2225 else
2226 {
2227 dwQuit = hr;
2228 }
2229
2230 // initiate engine shutdown
2287 pThis->m_pEngine->Quit(dwQuit); 2231 pThis->m_pEngine->Quit(dwQuit);
2288 2232
2289 ReleaseTheme(pThis->m_pTheme); 2233 ReleaseTheme(pThis->m_pTheme);
@@ -2335,9 +2279,6 @@ private:
2335 GetBundleFileVersion(); 2279 GetBundleFileVersion();
2336 // don't fail if we couldn't get the version info; best-effort only 2280 // don't fail if we couldn't get the version info; best-effort only
2337 2281
2338 hr = InitializePackageInfo();
2339 BalExitOnFailure(hr, "Failed to initialize wixstdba package information.");
2340
2341 if (m_fPrereq) 2282 if (m_fPrereq)
2342 { 2283 {
2343 hr = InitializePrerequisiteInformation(); 2284 hr = InitializePrerequisiteInformation();
@@ -2521,38 +2462,6 @@ private:
2521 } 2462 }
2522 2463
2523 2464
2524 HRESULT InitializePackageInfo()
2525 {
2526 HRESULT hr = S_OK;
2527 BAL_INFO_PACKAGE* pPackage = NULL;
2528
2529 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
2530 {
2531 pPackage = &m_Bundle.packages.rgPackages[i];
2532
2533 hr = InitializePackageInfoForPackage(pPackage);
2534 BalExitOnFailure(hr, "Failed to initialize wixstdba package info for package: %ls.", pPackage->sczId);
2535 }
2536
2537 LExit:
2538 return hr;
2539 }
2540
2541
2542 HRESULT InitializePackageInfoForPackage(
2543 __in BAL_INFO_PACKAGE* pPackage
2544 )
2545 {
2546 HRESULT hr = S_OK;
2547
2548 pPackage->pvCustomData = MemAlloc(sizeof(WIXSTDBA_PACKAGE_INFO), TRUE);
2549 BalExitOnNull(pPackage->pvCustomData, hr, E_OUTOFMEMORY, "Failed to allocate memory for wixstdba package info.");
2550
2551 LExit:
2552 return hr;
2553 }
2554
2555
2556 HRESULT InitializePrerequisiteInformation() 2465 HRESULT InitializePrerequisiteInformation()
2557 { 2466 {
2558 HRESULT hr = S_OK; 2467 HRESULT hr = S_OK;
@@ -2673,35 +2582,6 @@ private:
2673 return hr; 2582 return hr;
2674 } 2583 }
2675 2584
2676 HRESULT GetPackageInfo(
2677 __in_z LPCWSTR wzPackageId,
2678 __out WIXSTDBA_PACKAGE_INFO** ppPackageInfo,
2679 __out BAL_INFO_PACKAGE** ppPackage
2680 )
2681 {
2682 HRESULT hr = E_NOTFOUND;
2683 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
2684 BAL_INFO_PACKAGE* pPackage = NULL;
2685
2686 Assert(wzPackageId && *wzPackageId);
2687 Assert(ppPackage);
2688 Assert(ppPackageInfo);
2689
2690 hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
2691 if (E_NOTFOUND != hr)
2692 {
2693 ExitOnFailure(hr, "Failed trying to find the requested package.");
2694
2695 pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
2696 }
2697
2698 *ppPackageInfo = pPackageInfo;
2699 *ppPackage = pPackage;
2700
2701 LExit:
2702 return hr;
2703 }
2704
2705 2585
2706 // 2586 //
2707 // Get the file version of the bootstrapper and record in bootstrapper log file 2587 // Get the file version of the bootstrapper and record in bootstrapper log file
@@ -3408,6 +3288,23 @@ private:
3408 } 3288 }
3409 } 3289 }
3410 } 3290 }
3291 else if (E_PREREQBA_INFINITE_LOOP == m_hrFinal)
3292 {
3293 HRESULT hr = StrAllocString(&sczUnformattedText, L"#(loc.PREREQBAINFINITELOOPErrorMessage)", 0);
3294 if (FAILED(hr))
3295 {
3296 BalLogError(hr, "Failed to initialize PREREQBAINFINITELOOPErrorMessage loc identifier.");
3297 }
3298 else
3299 {
3300 hr = LocLocalizeString(m_pWixLoc, &sczUnformattedText);
3301 if (FAILED(hr))
3302 {
3303 BalLogError(hr, "Failed to localize PREREQBAINFINITELOOPErrorMessage: %ls", sczUnformattedText);
3304 ReleaseNullStr(sczUnformattedText);
3305 }
3306 }
3307 }
3411 else // try to get the error message from the error code. 3308 else // try to get the error message from the error code.
3412 { 3309 {
3413 StrAllocFromError(&sczUnformattedText, m_hrFinal, NULL); 3310 StrAllocFromError(&sczUnformattedText, m_hrFinal, NULL);
@@ -3424,14 +3321,9 @@ private:
3424 StrAllocString(&sczText, sczUnformattedText, 0); 3321 StrAllocString(&sczText, sczUnformattedText, 0);
3425 } 3322 }
3426 } 3323 }
3427 else if (E_MBAHOST_NET452_ON_WIN7RTM == m_hrFinal) 3324 else if (E_MBAHOST_NET452_ON_WIN7RTM == m_hrFinal ||
3428 { 3325 E_DNCHOST_SCD_RUNTIME_FAILURE == m_hrFinal ||
3429 if (sczUnformattedText) 3326 E_PREREQBA_INFINITE_LOOP == m_hrFinal)
3430 {
3431 BalFormatString(sczUnformattedText, &sczText);
3432 }
3433 }
3434 else if (E_DNCHOST_SCD_RUNTIME_FAILURE == m_hrFinal)
3435 { 3327 {
3436 if (sczUnformattedText) 3328 if (sczUnformattedText)
3437 { 3329 {
@@ -4180,8 +4072,7 @@ public:
4180 // 4072 //
4181 CWixStandardBootstrapperApplication( 4073 CWixStandardBootstrapperApplication(
4182 __in HMODULE hModule, 4074 __in HMODULE hModule,
4183 __in BOOL fPrereq, 4075 __in_opt PREQBA_DATA* pPrereqData,
4184 __in HRESULT hrHostInitialization,
4185 __in IBootstrapperEngine* pEngine 4076 __in IBootstrapperEngine* pEngine
4186 ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000) 4077 ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000)
4187 { 4078 {
@@ -4210,7 +4101,7 @@ public:
4210 m_hWnd = NULL; 4101 m_hWnd = NULL;
4211 4102
4212 m_state = WIXSTDBA_STATE_INITIALIZING; 4103 m_state = WIXSTDBA_STATE_INITIALIZING;
4213 m_hrFinal = hrHostInitialization; 4104 m_hrFinal = pPrereqData ? pPrereqData->hrHostInitialization : S_OK;
4214 4105
4215 m_restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE; 4106 m_restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE;
4216 m_fRestartRequired = FALSE; 4107 m_fRestartRequired = FALSE;
@@ -4231,9 +4122,9 @@ public:
4231 m_fShowingInternalUiThisPackage = FALSE; 4122 m_fShowingInternalUiThisPackage = FALSE;
4232 m_fTriedToLaunchElevated = FALSE; 4123 m_fTriedToLaunchElevated = FALSE;
4233 4124
4234 m_fPrereq = fPrereq; 4125 m_pPrereqData = pPrereqData;
4126 m_fPrereq = NULL != pPrereqData;
4235 m_fPrereqInstalled = FALSE; 4127 m_fPrereqInstalled = FALSE;
4236 m_fPrereqAlreadyInstalled = FALSE;
4237 4128
4238 pEngine->AddRef(); 4129 pEngine->AddRef();
4239 m_pEngine = pEngine; 4130 m_pEngine = pEngine;
@@ -4418,11 +4309,6 @@ public:
4418 AssertSz(!m_pTaskbarList, "Taskbar should have been released before destructor."); 4309 AssertSz(!m_pTaskbarList, "Taskbar should have been released before destructor.");
4419 AssertSz(!m_pTheme, "Theme should have been released before destructor."); 4310 AssertSz(!m_pTheme, "Theme should have been released before destructor.");
4420 4311
4421 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
4422 {
4423 ReleaseMem(m_Bundle.packages.rgPackages[i].pvCustomData);
4424 }
4425
4426 ::DeleteCriticalSection(&m_csShowingInternalUiThisPackage); 4312 ::DeleteCriticalSection(&m_csShowingInternalUiThisPackage);
4427 ReleaseStr(m_sczFailedMessage); 4313 ReleaseStr(m_sczFailedMessage);
4428 ReleaseStr(m_sczConfirmCloseMessage); 4314 ReleaseStr(m_sczConfirmCloseMessage);
@@ -4436,18 +4322,6 @@ public:
4436 ReleaseStr(m_sczBundleVersion); 4322 ReleaseStr(m_sczBundleVersion);
4437 ReleaseStr(m_sczAfterForcedRestartPackage); 4323 ReleaseStr(m_sczAfterForcedRestartPackage);
4438 ReleaseNullObject(m_pEngine); 4324 ReleaseNullObject(m_pEngine);
4439
4440 if (m_hBAFModule)
4441 {
4442 PFN_BA_FUNCTIONS_DESTROY pfnBAFunctionsDestroy = reinterpret_cast<PFN_BA_FUNCTIONS_DESTROY>(::GetProcAddress(m_hBAFModule, "BAFunctionsDestroy"));
4443 if (pfnBAFunctionsDestroy)
4444 {
4445 pfnBAFunctionsDestroy();
4446 }
4447
4448 ::FreeLibrary(m_hBAFModule);
4449 m_hBAFModule = NULL;
4450 }
4451 } 4325 }
4452 4326
4453private: 4327private:
@@ -4529,9 +4403,9 @@ private:
4529 BOOL m_fSupportCacheOnly; 4403 BOOL m_fSupportCacheOnly;
4530 BOOL m_fRequestedCacheOnly; 4404 BOOL m_fRequestedCacheOnly;
4531 4405
4406 PREQBA_DATA* m_pPrereqData;
4532 BOOL m_fPrereq; 4407 BOOL m_fPrereq;
4533 BOOL m_fPrereqInstalled; 4408 BOOL m_fPrereqInstalled;
4534 BOOL m_fPrereqAlreadyInstalled;
4535 4409
4536 ITaskbarList3* m_pTaskbarList; 4410 ITaskbarList3* m_pTaskbarList;
4537 UINT m_uTaskbarButtonCreatedMessage; 4411 UINT m_uTaskbarButtonCreatedMessage;
@@ -4551,8 +4425,7 @@ private:
4551// 4425//
4552HRESULT CreateBootstrapperApplication( 4426HRESULT CreateBootstrapperApplication(
4553 __in HMODULE hModule, 4427 __in HMODULE hModule,
4554 __in BOOL fPrereq, 4428 __in_opt PREQBA_DATA* pPrereqData,
4555 __in HRESULT hrHostInitialization,
4556 __in IBootstrapperEngine* pEngine, 4429 __in IBootstrapperEngine* pEngine,
4557 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 4430 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
4558 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults, 4431 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults,
@@ -4567,7 +4440,7 @@ HRESULT CreateBootstrapperApplication(
4567 BalExitOnFailure(hr = E_INVALIDARG, "Engine requested Unknown display type."); 4440 BalExitOnFailure(hr = E_INVALIDARG, "Engine requested Unknown display type.");
4568 } 4441 }
4569 4442
4570 pApplication = new CWixStandardBootstrapperApplication(hModule, fPrereq, hrHostInitialization, pEngine); 4443 pApplication = new CWixStandardBootstrapperApplication(hModule, pPrereqData, pEngine);
4571 BalExitOnNull(pApplication, hr, E_OUTOFMEMORY, "Failed to create new standard bootstrapper application object."); 4444 BalExitOnNull(pApplication, hr, E_OUTOFMEMORY, "Failed to create new standard bootstrapper application object.");
4572 4445
4573 hr = pApplication->Initialize(pArgs); 4446 hr = pApplication->Initialize(pArgs);
@@ -4584,6 +4457,17 @@ LExit:
4584} 4457}
4585 4458
4586 4459
4460void DestroyBootstrapperApplication(
4461 __in IBootstrapperApplication* pApplication,
4462 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
4463 __inout BOOTSTRAPPER_DESTROY_RESULTS* pResults
4464 )
4465{
4466 CWixStandardBootstrapperApplication* pBA = (CWixStandardBootstrapperApplication*)pApplication;
4467 pBA->Uninitialize(pArgs, pResults);
4468}
4469
4470
4587static HRESULT DAPI EvaluateVariableConditionCallback( 4471static HRESULT DAPI EvaluateVariableConditionCallback(
4588 __in_z LPCWSTR wzCondition, 4472 __in_z LPCWSTR wzCondition,
4589 __out BOOL* pf, 4473 __out BOOL* pf,
diff --git a/src/ext/Bal/wixstdba/inc/preqba.h b/src/ext/Bal/wixstdba/inc/preqba.h
new file mode 100644
index 00000000..93a547ed
--- /dev/null
+++ b/src/ext/Bal/wixstdba/inc/preqba.h
@@ -0,0 +1,16 @@
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
5struct PREQBA_DATA
6{
7 HRESULT hrHostInitialization;
8 BOOL fCompleted;
9};
10
11extern "C" typedef HRESULT(WINAPI* PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE)(
12 __in PREQBA_DATA* pPreqData,
13 __in IBootstrapperEngine* pEngine,
14 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
15 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
16 );
diff --git a/src/ext/Bal/wixstdba/precomp.h b/src/ext/Bal/wixstdba/precomp.h
index ba56ae6d..290c125b 100644
--- a/src/ext/Bal/wixstdba/precomp.h
+++ b/src/ext/Bal/wixstdba/precomp.h
@@ -17,43 +17,49 @@
17#include <strsafe.h> 17#include <strsafe.h>
18#include <stddef.h> 18#include <stddef.h>
19 19
20#include "dutil.h" 20#include <dutil.h>
21#include "apputil.h" 21#include <apputil.h>
22#include "memutil.h" 22#include <memutil.h>
23#include "dictutil.h" 23#include <dictutil.h>
24#include "dirutil.h" 24#include <dirutil.h>
25#include "fileutil.h" 25#include <fileutil.h>
26#include "locutil.h" 26#include <locutil.h>
27#include "logutil.h" 27#include <logutil.h>
28#include "pathutil.h" 28#include <pathutil.h>
29#include "resrutil.h" 29#include <resrutil.h>
30#include "shelutil.h" 30#include <shelutil.h>
31#include "strutil.h" 31#include <strutil.h>
32#include "wndutil.h" 32#include <wndutil.h>
33#include "thmutil.h" 33#include <thmutil.h>
34#include "verutil.h" 34#include <verutil.h>
35#include "uriutil.h" 35#include <uriutil.h>
36#include "xmlutil.h" 36#include <xmlutil.h>
37
38#include "BootstrapperEngine.h"
39#include "BootstrapperApplication.h"
40#include "IBootstrapperEngine.h"
41#include "IBootstrapperApplication.h"
42
43#include "balutil.h"
44#include "balinfo.h"
45#include "balcondition.h"
46
47#include "BAFunctions.h"
48 37
38#include <BootstrapperEngine.h>
39#include <BootstrapperApplication.h>
40#include <IBootstrapperEngine.h>
41#include <IBootstrapperApplication.h>
42
43#include <balutil.h>
44#include <balinfo.h>
45#include <balcondition.h>
46
47#include <BAFunctions.h>
48
49#include "inc\preqba.h"
49#include "wixstdba.messages.h" 50#include "wixstdba.messages.h"
50 51
51HRESULT CreateBootstrapperApplication( 52HRESULT CreateBootstrapperApplication(
52 __in HMODULE hModule, 53 __in HMODULE hModule,
53 __in BOOL fPrereq, 54 __in_opt PREQBA_DATA* pPrereqData,
54 __in HRESULT hrHostInitialization,
55 __in IBootstrapperEngine* pEngine, 55 __in IBootstrapperEngine* pEngine,
56 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 56 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
57 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults, 57 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults,
58 __out IBootstrapperApplication** ppApplication 58 __out IBootstrapperApplication** ppApplication
59 ); 59 );
60
61void DestroyBootstrapperApplication(
62 __in IBootstrapperApplication* pApplication,
63 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
64 __inout BOOTSTRAPPER_DESTROY_RESULTS* pResults
65 );
diff --git a/src/ext/Bal/wixstdba/wixstdba.cpp b/src/ext/Bal/wixstdba/wixstdba.cpp
index a96f1738..47f3f677 100644
--- a/src/ext/Bal/wixstdba/wixstdba.cpp
+++ b/src/ext/Bal/wixstdba/wixstdba.cpp
@@ -50,7 +50,7 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
50 hr = BalInitializeFromCreateArgs(pArgs, &pEngine); 50 hr = BalInitializeFromCreateArgs(pArgs, &pEngine);
51 ExitOnFailure(hr, "Failed to initialize Bal."); 51 ExitOnFailure(hr, "Failed to initialize Bal.");
52 52
53 hr = CreateBootstrapperApplication(vhInstance, FALSE, S_OK, pEngine, pArgs, pResults, &vpApplication); 53 hr = CreateBootstrapperApplication(vhInstance, NULL, pEngine, pArgs, pResults, &vpApplication);
54 BalExitOnFailure(hr, "Failed to create bootstrapper application interface."); 54 BalExitOnFailure(hr, "Failed to create bootstrapper application interface.");
55 55
56LExit: 56LExit:
@@ -60,45 +60,24 @@ LExit:
60} 60}
61 61
62 62
63extern "C" void WINAPI BootstrapperApplicationDestroy() 63extern "C" void WINAPI BootstrapperApplicationDestroy(
64{ 64 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
65 ReleaseNullObject(vpApplication); 65 __in BOOTSTRAPPER_DESTROY_RESULTS* pResults
66 BalUninitialize();
67 DutilUninitialize();
68}
69
70
71extern "C" HRESULT WINAPI DncPrereqBootstrapperApplicationCreate(
72 __in HRESULT hrHostInitialization,
73 __in IBootstrapperEngine* pEngine,
74 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
75 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
76 ) 66 )
77{ 67{
78 HRESULT hr = S_OK; 68 if (vpApplication)
79 69 {
80 DutilInitialize(&WixstdbaTraceError); 70 DestroyBootstrapperApplication(vpApplication, pArgs, pResults);
81 71 }
82 BalInitialize(pEngine);
83
84 hr = CreateBootstrapperApplication(vhInstance, TRUE, hrHostInitialization, pEngine, pArgs, pResults, &vpApplication);
85 BalExitOnFailure(hr, "Failed to create .NET Core prerequisite bootstrapper application interface.");
86
87LExit:
88 return hr;
89}
90
91 72
92extern "C" void WINAPI DncPrereqBootstrapperApplicationDestroy()
93{
94 ReleaseNullObject(vpApplication); 73 ReleaseNullObject(vpApplication);
95 BalUninitialize(); 74 BalUninitialize();
96 DutilUninitialize(); 75 DutilUninitialize();
97} 76}
98 77
99 78
100extern "C" HRESULT WINAPI MbaPrereqBootstrapperApplicationCreate( 79extern "C" HRESULT WINAPI PrereqBootstrapperApplicationCreate(
101 __in HRESULT hrHostInitialization, 80 __in_opt PREQBA_DATA* pPrereqData,
102 __in IBootstrapperEngine* pEngine, 81 __in IBootstrapperEngine* pEngine,
103 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, 82 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
104 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults 83 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
@@ -110,19 +89,20 @@ extern "C" HRESULT WINAPI MbaPrereqBootstrapperApplicationCreate(
110 89
111 BalInitialize(pEngine); 90 BalInitialize(pEngine);
112 91
113 hr = CreateBootstrapperApplication(vhInstance, TRUE, hrHostInitialization, pEngine, pArgs, pResults, &vpApplication); 92 hr = CreateBootstrapperApplication(vhInstance, pPrereqData, pEngine, pArgs, pResults, &vpApplication);
114 BalExitOnFailure(hr, "Failed to create managed prerequisite bootstrapper application interface."); 93 BalExitOnFailure(hr, "Failed to create prerequisite bootstrapper application interface.");
115 94
116LExit: 95LExit:
117 return hr; 96 return hr;
118} 97}
119 98
120 99
121extern "C" void WINAPI MbaPrereqBootstrapperApplicationDestroy() 100extern "C" void WINAPI PrereqBootstrapperApplicationDestroy(
101 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
102 __in BOOTSTRAPPER_DESTROY_RESULTS* pResults
103 )
122{ 104{
123 ReleaseNullObject(vpApplication); 105 BootstrapperApplicationDestroy(pArgs, pResults);
124 BalUninitialize();
125 DutilUninitialize();
126} 106}
127 107
128static void CALLBACK WixstdbaTraceError( 108static void CALLBACK WixstdbaTraceError(
diff --git a/src/ext/Bal/wixstdba/wixstdba.def b/src/ext/Bal/wixstdba/wixstdba.def
index ba9980d3..e377196b 100644
--- a/src/ext/Bal/wixstdba/wixstdba.def
+++ b/src/ext/Bal/wixstdba/wixstdba.def
@@ -4,7 +4,5 @@
4EXPORTS 4EXPORTS
5 BootstrapperApplicationCreate 5 BootstrapperApplicationCreate
6 BootstrapperApplicationDestroy 6 BootstrapperApplicationDestroy
7 DncPrereqBootstrapperApplicationCreate 7 PrereqBootstrapperApplicationCreate
8 DncPrereqBootstrapperApplicationDestroy 8 PrereqBootstrapperApplicationDestroy
9 MbaPrereqBootstrapperApplicationCreate
10 MbaPrereqBootstrapperApplicationDestroy
diff --git a/src/ext/Bal/wixstdba/wixstdba.vcxproj b/src/ext/Bal/wixstdba/wixstdba.vcxproj
index a43cc345..9273c1ed 100644
--- a/src/ext/Bal/wixstdba/wixstdba.vcxproj
+++ b/src/ext/Bal/wixstdba/wixstdba.vcxproj
@@ -52,6 +52,7 @@
52 <ClCompile Include="wixstdba.cpp" /> 52 <ClCompile Include="wixstdba.cpp" />
53 </ItemGroup> 53 </ItemGroup>
54 <ItemGroup> 54 <ItemGroup>
55 <ClInclude Include="inc\preqba.h" />
55 <ClInclude Include="precomp.h" /> 56 <ClInclude Include="precomp.h" />
56 <ClInclude Include="resource.h" /> 57 <ClInclude Include="resource.h" />
57 </ItemGroup> 58 </ItemGroup>
diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs
index 5f492efd..1548c05b 100644
--- a/src/test/burn/TestBA/TestBA.cs
+++ b/src/test/burn/TestBA/TestBA.cs
@@ -171,7 +171,13 @@ namespace WixToolset.Test.BA
171 this.dummyWindow.Dispose(); 171 this.dummyWindow.Dispose();
172 } 172 }
173 173
174 this.Engine.Quit(this.result & 0xFFFF); // return plain old Win32 error, not HRESULT. 174 var exitCode = this.result;
175 if ((exitCode & 0xFFFF0000) == unchecked(0x80070000))
176 {
177 exitCode &= 0xFFFF; // return plain old Win32 error, not HRESULT.
178 }
179
180 this.Engine.Quit(exitCode);
175 } 181 }
176 182
177 protected override void OnDetectUpdateBegin(DetectUpdateBeginEventArgs args) 183 protected override void OnDetectUpdateBegin(DetectUpdateBeginEventArgs args)
diff --git a/src/test/burn/TestData/Manual/BafThmutilTesting/precomp.cpp b/src/test/burn/TestData/Manual/BafThmutilTesting/precomp.cpp
index b20f4230..fc9d1177 100644
--- a/src/test/burn/TestData/Manual/BafThmutilTesting/precomp.cpp
+++ b/src/test/burn/TestData/Manual/BafThmutilTesting/precomp.cpp
@@ -40,6 +40,8 @@ LExit:
40} 40}
41 41
42extern "C" void WINAPI BAFunctionsDestroy( 42extern "C" void WINAPI BAFunctionsDestroy(
43 __in const BA_FUNCTIONS_DESTROY_ARGS* /*pArgs*/,
44 __inout BA_FUNCTIONS_DESTROY_RESULTS* /*pResults*/
43 ) 45 )
44{ 46{
45 BalUninitialize(); 47 BalUninitialize();
diff --git a/src/test/burn/WixToolset.WixBA/WixBA.cs b/src/test/burn/WixToolset.WixBA/WixBA.cs
index 68288f2d..60426ca8 100644
--- a/src/test/burn/WixToolset.WixBA/WixBA.cs
+++ b/src/test/burn/WixToolset.WixBA/WixBA.cs
@@ -179,7 +179,14 @@ namespace WixToolset.WixBA
179 Threading.Dispatcher.Run(); 179 Threading.Dispatcher.Run();
180 180
181 this.PostTelemetry(); 181 this.PostTelemetry();
182 this.Engine.Quit(WixBA.Model.Result); 182
183 var exitCode = WixBA.Model.Result;
184 if ((exitCode & 0xFFFF0000) == unchecked(0x80070000))
185 {
186 exitCode &= 0xFFFF; // return plain old Win32 error, not HRESULT.
187 }
188
189 this.Engine.Quit(exitCode);
183 } 190 }
184 191
185 private void PostTelemetry() 192 private void PostTelemetry()
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs
index ec828f89..52e165b4 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs
@@ -12,6 +12,8 @@ namespace WixToolsetTest.BurnE2E
12 { 12 {
13 public PrereqBaTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } 13 public PrereqBaTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
14 14
15 const int E_PREREQBA_INFINITE_LOOP = -2_114_714_646;
16
15 /// <summary> 17 /// <summary>
16 /// 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,
17 /// with an MSI package to represent the prerequisite package. 19 /// with an MSI package to represent the prerequisite package.
@@ -32,7 +34,7 @@ namespace WixToolsetTest.BurnE2E
32 // Source file should *not* be installed 34 // Source file should *not* be installed
33 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); 35 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
34 36
35 bundleA.Install(); 37 bundleA.Install(E_PREREQBA_INFINITE_LOOP);
36 38
37 // Part of the test is Install actually completing. 39 // Part of the test is Install actually completing.
38 40
@@ -63,7 +65,7 @@ namespace WixToolsetTest.BurnE2E
63 // Source file should *not* be installed 65 // Source file should *not* be installed
64 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}"); 66 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}");
65 67
66 bundleB.Install(); 68 bundleB.Install(E_PREREQBA_INFINITE_LOOP);
67 69
68 // Part of the test is Install actually completing. 70 // Part of the test is Install actually completing.
69 71