diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2022-05-13 13:50:50 -0500 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2022-05-14 11:12:31 -0500 |
commit | 6a6974a15deb6edf593736cdb8043bfb93064782 (patch) | |
tree | 0ae2afffcd02967ba3fe0f0a5d3e9273811f1e6f /src/ext/Bal/mbahost | |
parent | 7d56566b7c51c49ded526466dfae6af9e1709040 (diff) | |
download | wix-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.cpp | 289 | ||||
-rw-r--r-- | src/ext/Bal/mbahost/mbahost.h | 17 | ||||
-rw-r--r-- | src/ext/Bal/mbahost/mbahost.vcxproj | 3 | ||||
-rw-r--r-- | src/ext/Bal/mbahost/precomp.h | 17 |
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 | ||
6 | static const DWORD NET452_RELEASE = 379893; | 5 | static 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 | ||
17 | extern "C" typedef HRESULT(WINAPI *PFN_MBAPREQ_BOOTSTRAPPER_APPLICATION_CREATE)( | 16 | static 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 | |||
24 | static HINSTANCE vhInstance = NULL; | ||
25 | static ICorRuntimeHost *vpCLRHost = NULL; | ||
26 | static _AppDomain *vpAppDomain = NULL; | ||
27 | static HMODULE vhMbapreqModule = NULL; | ||
28 | 17 | ||
29 | 18 | ||
30 | // internal function declarations | 19 | // internal function declarations |
31 | 20 | ||
32 | static HRESULT GetAppDomain( | 21 | static HRESULT GetAppDomain( |
33 | __out _AppDomain** ppAppDomain | 22 | __in MBASTATE* pState |
34 | ); | 23 | ); |
35 | static HRESULT GetAppBase( | 24 | static HRESULT LoadModulePaths( |
36 | __out LPWSTR* psczAppBase | 25 | __in MBASTATE* pState |
37 | ); | 26 | ); |
38 | static HRESULT CheckSupportedFrameworks( | 27 | static 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 | ); |
46 | static HRESULT GetCLRHost( | 35 | static HRESULT LoadRuntime( |
47 | __in LPCWSTR wzConfigPath, | 36 | __in MBASTATE* pState |
48 | __out ICorRuntimeHost** ppCLRHost | ||
49 | ); | 37 | ); |
50 | static HRESULT CreateManagedBootstrapperApplication( | 38 | static 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 | ); |
59 | static HRESULT CreatePrerequisiteBA( | 47 | static 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 | ||
137 | extern "C" void WINAPI BootstrapperApplicationDestroy() | 152 | extern "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. |
172 | static HRESULT GetAppDomain( | 199 | static 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 | ||
230 | LExit: | 237 | LExit: |
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 | ||
241 | static HRESULT GetAppBase( | 245 | static 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 | |||
254 | LExit: | 261 | LExit: |
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. |
393 | static HRESULT GetCLRHost( | 400 | static 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 | ||
493 | LExit: | 496 | LExit: |
494 | ReleaseStr(pwzVersion); | 497 | ReleaseStr(pwzVersion); |
@@ -569,7 +572,7 @@ LExit: | |||
569 | } | 572 | } |
570 | 573 | ||
571 | static HRESULT CreatePrerequisiteBA( | 574 | static 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 | ||
597 | LExit: | 600 | LExit: |
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 | |||
5 | struct 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" | ||