aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Bal/mbahost
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 /src/ext/Bal/mbahost
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.
Diffstat (limited to 'src/ext/Bal/mbahost')
-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
4 files changed, 176 insertions, 150 deletions
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"