diff options
Diffstat (limited to 'src/ext/Bal/mbahost/mbahost.cpp')
-rw-r--r-- | src/ext/Bal/mbahost/mbahost.cpp | 693 |
1 files changed, 0 insertions, 693 deletions
diff --git a/src/ext/Bal/mbahost/mbahost.cpp b/src/ext/Bal/mbahost/mbahost.cpp deleted file mode 100644 index 9d8acc8a..00000000 --- a/src/ext/Bal/mbahost/mbahost.cpp +++ /dev/null | |||
@@ -1,693 +0,0 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | #include "precomp.h" | ||
4 | |||
5 | static const DWORD NET452_RELEASE = 379893; | ||
6 | |||
7 | using namespace mscorlib; | ||
8 | |||
9 | extern "C" typedef HRESULT (WINAPI *PFN_CORBINDTOCURRENTRUNTIME)( | ||
10 | __in LPCWSTR pwszFileName, | ||
11 | __in REFCLSID rclsid, | ||
12 | __in REFIID riid, | ||
13 | __out LPVOID *ppv | ||
14 | ); | ||
15 | |||
16 | static MBASTATE vstate = { }; | ||
17 | |||
18 | |||
19 | // internal function declarations | ||
20 | |||
21 | static HRESULT GetAppDomain( | ||
22 | __in MBASTATE* pState | ||
23 | ); | ||
24 | static HRESULT LoadModulePaths( | ||
25 | __in MBASTATE* pState | ||
26 | ); | ||
27 | static HRESULT LoadMbaConfiguration( | ||
28 | __in MBASTATE* pState, | ||
29 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs | ||
30 | ); | ||
31 | static HRESULT CheckSupportedFrameworks( | ||
32 | __in LPCWSTR wzConfigPath | ||
33 | ); | ||
34 | static HRESULT UpdateSupportedRuntime( | ||
35 | __in IXMLDOMDocument* pixdManifest, | ||
36 | __in IXMLDOMNode* pixnSupportedFramework, | ||
37 | __out BOOL* pfUpdatedManifest | ||
38 | ); | ||
39 | static HRESULT LoadRuntime( | ||
40 | __in MBASTATE* pState | ||
41 | ); | ||
42 | static HRESULT CreateManagedBootstrapperApplication( | ||
43 | __in _AppDomain* pAppDomain, | ||
44 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
45 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
46 | ); | ||
47 | static HRESULT CreateManagedBootstrapperApplicationFactory( | ||
48 | __in _AppDomain* pAppDomain, | ||
49 | __out IBootstrapperApplicationFactory** ppAppFactory | ||
50 | ); | ||
51 | static HRESULT CreatePrerequisiteBA( | ||
52 | __in MBASTATE* pState, | ||
53 | __in IBootstrapperEngine* pEngine, | ||
54 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
55 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
56 | ); | ||
57 | static HRESULT VerifyNET4RuntimeIsSupported( | ||
58 | ); | ||
59 | |||
60 | |||
61 | // function definitions | ||
62 | |||
63 | extern "C" BOOL WINAPI DllMain( | ||
64 | IN HINSTANCE hInstance, | ||
65 | IN DWORD dwReason, | ||
66 | IN LPVOID /* pvReserved */ | ||
67 | ) | ||
68 | { | ||
69 | switch (dwReason) | ||
70 | { | ||
71 | case DLL_PROCESS_ATTACH: | ||
72 | ::DisableThreadLibraryCalls(hInstance); | ||
73 | vstate.hInstance = hInstance; | ||
74 | break; | ||
75 | |||
76 | case DLL_PROCESS_DETACH: | ||
77 | vstate.hInstance = NULL; | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | return TRUE; | ||
82 | } | ||
83 | |||
84 | // Note: This function assumes that COM was already initialized on the thread. | ||
85 | extern "C" HRESULT WINAPI BootstrapperApplicationCreate( | ||
86 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
87 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
88 | ) | ||
89 | { | ||
90 | HRESULT hr = S_OK; | ||
91 | IBootstrapperEngine* pEngine = NULL; | ||
92 | |||
93 | if (vstate.fStoppedRuntime) | ||
94 | { | ||
95 | BalExitWithRootFailure(hr, E_INVALIDSTATE, "Reloaded mbahost after stopping .NET runtime."); | ||
96 | } | ||
97 | |||
98 | hr = BalInitializeFromCreateArgs(pArgs, &pEngine); | ||
99 | ExitOnFailure(hr, "Failed to initialize Bal."); | ||
100 | |||
101 | if (!vstate.fInitialized) | ||
102 | { | ||
103 | hr = XmlInitialize(); | ||
104 | BalExitOnFailure(hr, "Failed to initialize XML."); | ||
105 | |||
106 | hr = LoadModulePaths(&vstate); | ||
107 | BalExitOnFailure(hr, "Failed to load the module paths."); | ||
108 | |||
109 | hr = LoadMbaConfiguration(&vstate, pArgs); | ||
110 | BalExitOnFailure(hr, "Failed to get the mba configuration."); | ||
111 | |||
112 | vstate.fInitialized = TRUE; | ||
113 | } | ||
114 | |||
115 | if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted) | ||
116 | { | ||
117 | BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application since it's configured to always run before loading the runtime."); | ||
118 | |||
119 | hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults); | ||
120 | BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application."); | ||
121 | |||
122 | ExitFunction(); | ||
123 | } | ||
124 | |||
125 | if (!vstate.fInitializedRuntime) | ||
126 | { | ||
127 | hr = LoadRuntime(&vstate); | ||
128 | |||
129 | vstate.fInitializedRuntime = SUCCEEDED(hr); | ||
130 | } | ||
131 | |||
132 | if (vstate.fInitializedRuntime) | ||
133 | { | ||
134 | hr = GetAppDomain(&vstate); | ||
135 | BalExitOnFailure(hr, "Failed to create the AppDomain for the managed bootstrapper application."); | ||
136 | |||
137 | BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading managed bootstrapper application."); | ||
138 | |||
139 | hr = CreateManagedBootstrapperApplication(vstate.pAppDomain, pArgs, pResults); | ||
140 | BalExitOnFailure(hr, "Failed to create the managed bootstrapper application."); | ||
141 | } | ||
142 | else // fallback to the prerequisite BA. | ||
143 | { | ||
144 | if (E_MBAHOST_NET452_ON_WIN7RTM == hr) | ||
145 | { | ||
146 | 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."); | ||
147 | vstate.prereqData.hrFatalError = hr; | ||
148 | } | ||
149 | else if (vstate.prereqData.fCompleted) | ||
150 | { | ||
151 | hr = E_PREREQBA_INFINITE_LOOP; | ||
152 | BalLogError(hr, "The prerequisites were already installed. The bootstrapper application will not be reloaded to prevent an infinite loop."); | ||
153 | vstate.prereqData.hrFatalError = hr; | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | vstate.prereqData.hrFatalError = S_OK; | ||
158 | } | ||
159 | |||
160 | BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because managed host could not be loaded, error: 0x%08x.", hr); | ||
161 | |||
162 | hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults); | ||
163 | BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application."); | ||
164 | } | ||
165 | |||
166 | LExit: | ||
167 | ReleaseNullObject(pEngine); | ||
168 | |||
169 | return hr; | ||
170 | } | ||
171 | |||
172 | extern "C" void WINAPI BootstrapperApplicationDestroy( | ||
173 | __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs, | ||
174 | __in BOOTSTRAPPER_DESTROY_RESULTS* pResults | ||
175 | ) | ||
176 | { | ||
177 | BOOTSTRAPPER_DESTROY_RESULTS childResults = { }; | ||
178 | |||
179 | if (vstate.pAppDomain) | ||
180 | { | ||
181 | HRESULT hr = vstate.pCLRHost->UnloadDomain(vstate.pAppDomain); | ||
182 | if (FAILED(hr)) | ||
183 | { | ||
184 | BalLogError(hr, "Failed to unload app domain."); | ||
185 | } | ||
186 | |||
187 | vstate.pAppDomain->Release(); | ||
188 | vstate.pAppDomain = NULL; | ||
189 | } | ||
190 | |||
191 | // pCLRHost can only be stopped once per process. | ||
192 | if (vstate.pCLRHost && !pArgs->fReload) | ||
193 | { | ||
194 | vstate.pCLRHost->Stop(); | ||
195 | vstate.pCLRHost->Release(); | ||
196 | vstate.pCLRHost = NULL; | ||
197 | vstate.fStoppedRuntime = TRUE; | ||
198 | } | ||
199 | |||
200 | if (vstate.hMbapreqModule) | ||
201 | { | ||
202 | PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vstate.hMbapreqModule, "PrereqBootstrapperApplicationDestroy")); | ||
203 | if (pfnDestroy) | ||
204 | { | ||
205 | (*pfnDestroy)(pArgs, &childResults); | ||
206 | } | ||
207 | |||
208 | ::FreeLibrary(vstate.hMbapreqModule); | ||
209 | vstate.hMbapreqModule = NULL; | ||
210 | } | ||
211 | |||
212 | BalUninitialize(); | ||
213 | |||
214 | // Need to keep track of state between reloads. | ||
215 | pResults->fDisableUnloading = TRUE; | ||
216 | } | ||
217 | |||
218 | // Gets the custom AppDomain for loading managed BA. | ||
219 | static HRESULT GetAppDomain( | ||
220 | __in MBASTATE* pState | ||
221 | ) | ||
222 | { | ||
223 | HRESULT hr = S_OK; | ||
224 | IUnknown *pUnk = NULL; | ||
225 | IAppDomainSetup* pAppDomainSetup = NULL; | ||
226 | BSTR bstrAppBase = NULL; | ||
227 | BSTR bstrConfigPath = NULL; | ||
228 | |||
229 | // Create the setup information for a new AppDomain to set the app base and config. | ||
230 | hr = pState->pCLRHost->CreateDomainSetup(&pUnk); | ||
231 | BalExitOnRootFailure(hr, "Failed to create the AppDomainSetup object."); | ||
232 | |||
233 | hr = pUnk->QueryInterface(__uuidof(IAppDomainSetup), reinterpret_cast<LPVOID*>(&pAppDomainSetup)); | ||
234 | BalExitOnRootFailure(hr, "Failed to query for the IAppDomainSetup interface."); | ||
235 | ReleaseNullObject(pUnk); | ||
236 | |||
237 | // Set properties on the AppDomainSetup object. | ||
238 | bstrAppBase = ::SysAllocString(pState->sczAppBase); | ||
239 | BalExitOnNull(bstrAppBase, hr, E_OUTOFMEMORY, "Failed to allocate the application base path for the AppDomainSetup."); | ||
240 | |||
241 | hr = pAppDomainSetup->put_ApplicationBase(bstrAppBase); | ||
242 | BalExitOnRootFailure(hr, "Failed to set the application base path for the AppDomainSetup."); | ||
243 | |||
244 | bstrConfigPath = ::SysAllocString(pState->sczConfigPath); | ||
245 | BalExitOnNull(bstrConfigPath, hr, E_OUTOFMEMORY, "Failed to allocate the application configuration file for the AppDomainSetup."); | ||
246 | |||
247 | hr = pAppDomainSetup->put_ConfigurationFile(bstrConfigPath); | ||
248 | BalExitOnRootFailure(hr, "Failed to set the configuration file path for the AppDomainSetup."); | ||
249 | |||
250 | // Create the AppDomain to load the factory type. | ||
251 | hr = pState->pCLRHost->CreateDomainEx(L"MBA", pAppDomainSetup, NULL, &pUnk); | ||
252 | BalExitOnRootFailure(hr, "Failed to create the MBA AppDomain."); | ||
253 | |||
254 | hr = pUnk->QueryInterface(__uuidof(_AppDomain), reinterpret_cast<LPVOID*>(&pState->pAppDomain)); | ||
255 | BalExitOnRootFailure(hr, "Failed to query for the _AppDomain interface."); | ||
256 | |||
257 | LExit: | ||
258 | ReleaseBSTR(bstrConfigPath); | ||
259 | ReleaseBSTR(bstrAppBase); | ||
260 | ReleaseNullObject(pUnk); | ||
261 | |||
262 | return hr; | ||
263 | } | ||
264 | |||
265 | static HRESULT LoadModulePaths( | ||
266 | __in MBASTATE* pState | ||
267 | ) | ||
268 | { | ||
269 | HRESULT hr = S_OK; | ||
270 | LPWSTR sczFullPath = NULL; | ||
271 | |||
272 | hr = PathForCurrentProcess(&sczFullPath, pState->hInstance); | ||
273 | BalExitOnFailure(hr, "Failed to get the full host path."); | ||
274 | |||
275 | hr = PathGetDirectory(sczFullPath, &pState->sczAppBase); | ||
276 | BalExitOnFailure(hr, "Failed to get the directory of the full process path."); | ||
277 | |||
278 | hr = PathConcat(pState->sczAppBase, MBA_CONFIG_FILE_NAME, &pState->sczConfigPath); | ||
279 | BalExitOnFailure(hr, "Failed to get the full path to the application configuration file."); | ||
280 | |||
281 | LExit: | ||
282 | ReleaseStr(sczFullPath); | ||
283 | |||
284 | return hr; | ||
285 | } | ||
286 | |||
287 | static HRESULT LoadMbaConfiguration( | ||
288 | __in MBASTATE* pState, | ||
289 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs | ||
290 | ) | ||
291 | { | ||
292 | HRESULT hr = S_OK; | ||
293 | IXMLDOMDocument* pixdManifest = NULL; | ||
294 | IXMLDOMNode* pixnHost = NULL; | ||
295 | BOOL fXmlFound = FALSE; | ||
296 | |||
297 | hr = XmlLoadDocumentFromFile(pArgs->pCommand->wzBootstrapperApplicationDataPath, &pixdManifest); | ||
298 | BalExitOnFailure(hr, "Failed to load BalManifest '%ls'", pArgs->pCommand->wzBootstrapperApplicationDataPath); | ||
299 | |||
300 | hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqOptions", &pixnHost); | ||
301 | BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to find WixMbaPrereqOptions element in bootstrapper application config."); | ||
302 | |||
303 | if (fXmlFound) | ||
304 | { | ||
305 | hr = XmlGetAttributeNumber(pixnHost, L"AlwaysInstallPrereqs", reinterpret_cast<DWORD*>(&pState->prereqData.fAlwaysInstallPrereqs)); | ||
306 | BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value."); | ||
307 | } | ||
308 | |||
309 | pState->prereqData.fPerformHelp = !pState->prereqData.fAlwaysInstallPrereqs; | ||
310 | |||
311 | LExit: | ||
312 | ReleaseObject(pixnHost); | ||
313 | ReleaseObject(pixdManifest); | ||
314 | |||
315 | return hr; | ||
316 | } | ||
317 | |||
318 | // Checks whether at least one of required supported frameworks is installed via the NETFX registry keys. | ||
319 | static HRESULT CheckSupportedFrameworks( | ||
320 | __in LPCWSTR wzConfigPath | ||
321 | ) | ||
322 | { | ||
323 | HRESULT hr = S_OK; | ||
324 | IXMLDOMDocument* pixdManifest = NULL; | ||
325 | IXMLDOMNodeList* pNodeList = NULL; | ||
326 | IXMLDOMNode* pNode = NULL; | ||
327 | DWORD cSupportedFrameworks = 0; | ||
328 | LPWSTR sczSupportedFrameworkVersion = NULL; | ||
329 | LPWSTR sczFrameworkRegistryKey = NULL; | ||
330 | HKEY hkFramework = NULL; | ||
331 | DWORD dwFrameworkInstalled = 0; | ||
332 | BOOL fUpdatedManifest = FALSE; | ||
333 | |||
334 | hr = XmlLoadDocumentFromFile(wzConfigPath, &pixdManifest); | ||
335 | BalExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath); | ||
336 | |||
337 | hr = XmlSelectNodes(pixdManifest, L"/configuration/wix.bootstrapper/host/supportedFramework", &pNodeList); | ||
338 | BalExitOnFailure(hr, "Failed to select all supportedFramework elements."); | ||
339 | |||
340 | hr = pNodeList->get_length(reinterpret_cast<long*>(&cSupportedFrameworks)); | ||
341 | BalExitOnFailure(hr, "Failed to get the supported framework count."); | ||
342 | |||
343 | if (cSupportedFrameworks) | ||
344 | { | ||
345 | while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL))) | ||
346 | { | ||
347 | hr = XmlGetAttributeEx(pNode, L"version", &sczSupportedFrameworkVersion); | ||
348 | BalExitOnRequiredXmlQueryFailure(hr, "Failed to get supportedFramework/@version."); | ||
349 | |||
350 | hr = StrAllocFormatted(&sczFrameworkRegistryKey, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\%ls", sczSupportedFrameworkVersion); | ||
351 | BalExitOnFailure(hr, "Failed to allocate path to supported framework Install registry key."); | ||
352 | |||
353 | hr = RegOpen(HKEY_LOCAL_MACHINE, sczFrameworkRegistryKey, KEY_READ, &hkFramework); | ||
354 | if (SUCCEEDED(hr)) | ||
355 | { | ||
356 | hr = RegReadNumber(hkFramework, L"Install", &dwFrameworkInstalled); | ||
357 | if (dwFrameworkInstalled) | ||
358 | { | ||
359 | hr = S_OK; | ||
360 | break; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | ReleaseNullObject(pNode); | ||
365 | } | ||
366 | |||
367 | // If we looped through all the supported frameworks but didn't find anything, ensure we return a failure. | ||
368 | if (S_FALSE == hr) | ||
369 | { | ||
370 | BalExitWithRootFailure(hr, E_NOTFOUND, "Failed to find a supported framework."); | ||
371 | } | ||
372 | |||
373 | hr = UpdateSupportedRuntime(pixdManifest, pNode, &fUpdatedManifest); | ||
374 | BalExitOnFailure(hr, "Failed to update supportedRuntime."); | ||
375 | } | ||
376 | // else no supported frameworks specified, so the startup/supportedRuntime must be enough. | ||
377 | |||
378 | if (fUpdatedManifest) | ||
379 | { | ||
380 | hr = XmlSaveDocument(pixdManifest, wzConfigPath); | ||
381 | BalExitOnFailure(hr, "Failed to save updated manifest over config file: %ls", wzConfigPath); | ||
382 | } | ||
383 | |||
384 | LExit: | ||
385 | ReleaseRegKey(hkFramework); | ||
386 | ReleaseStr(sczFrameworkRegistryKey); | ||
387 | ReleaseStr(sczSupportedFrameworkVersion); | ||
388 | ReleaseObject(pNode); | ||
389 | ReleaseObject(pNodeList); | ||
390 | ReleaseObject(pixdManifest); | ||
391 | |||
392 | return hr; | ||
393 | } | ||
394 | |||
395 | // Fixes the supportedRuntime element if necessary. | ||
396 | static HRESULT UpdateSupportedRuntime( | ||
397 | __in IXMLDOMDocument* pixdManifest, | ||
398 | __in IXMLDOMNode* pixnSupportedFramework, | ||
399 | __out BOOL* pfUpdatedManifest | ||
400 | ) | ||
401 | { | ||
402 | HRESULT hr = S_OK; | ||
403 | LPWSTR sczSupportedRuntimeVersion = NULL; | ||
404 | IXMLDOMNode* pixnStartup = NULL; | ||
405 | IXMLDOMNode* pixnSupportedRuntime = NULL; | ||
406 | BOOL fXmlFound = FALSE; | ||
407 | |||
408 | *pfUpdatedManifest = FALSE; | ||
409 | |||
410 | // If the runtime version attribute is not specified, don't update the manifest. | ||
411 | hr = XmlGetAttributeEx(pixnSupportedFramework, L"runtimeVersion", &sczSupportedRuntimeVersion); | ||
412 | BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get supportedFramework/@runtimeVersion."); | ||
413 | |||
414 | if (!fXmlFound) | ||
415 | { | ||
416 | ExitFunction(); | ||
417 | } | ||
418 | |||
419 | // Get the startup element. Fail if we can't find it since it'll be necessary to load the | ||
420 | // correct runtime. | ||
421 | hr = XmlSelectSingleNode(pixdManifest, L"/configuration/startup", &pixnStartup); | ||
422 | BalExitOnRequiredXmlQueryFailure(hr, "Failed to get startup element."); | ||
423 | |||
424 | // Remove any pre-existing supported runtimes because they'll just get in the way and create our new one. | ||
425 | hr = XmlRemoveChildren(pixnStartup, L"supportedRuntime"); | ||
426 | BalExitOnFailure(hr, "Failed to remove pre-existing supportedRuntime elements."); | ||
427 | |||
428 | hr = XmlCreateChild(pixnStartup, L"supportedRuntime", &pixnSupportedRuntime); | ||
429 | BalExitOnFailure(hr, "Failed to create supportedRuntime element."); | ||
430 | |||
431 | hr = XmlSetAttribute(pixnSupportedRuntime, L"version", sczSupportedRuntimeVersion); | ||
432 | BalExitOnFailure(hr, "Failed to set supportedRuntime/@version to '%ls'.", sczSupportedRuntimeVersion); | ||
433 | |||
434 | *pfUpdatedManifest = TRUE; | ||
435 | |||
436 | LExit: | ||
437 | ReleaseObject(pixnSupportedRuntime); | ||
438 | ReleaseObject(pixnStartup); | ||
439 | ReleaseStr(sczSupportedRuntimeVersion); | ||
440 | |||
441 | return hr; | ||
442 | } | ||
443 | |||
444 | // Gets the CLR host and caches it. | ||
445 | static HRESULT LoadRuntime( | ||
446 | __in MBASTATE* pState | ||
447 | ) | ||
448 | { | ||
449 | HRESULT hr = S_OK; | ||
450 | UINT uiMode = 0; | ||
451 | HMODULE hModule = NULL; | ||
452 | BOOL fFallbackToCorBindToCurrentRuntime = TRUE; | ||
453 | CLRCreateInstanceFnPtr pfnCLRCreateInstance = NULL; | ||
454 | ICLRMetaHostPolicy* pCLRMetaHostPolicy = NULL; | ||
455 | IStream* pCfgStream = NULL; | ||
456 | LPWSTR pwzVersion = NULL; | ||
457 | DWORD cchVersion = 0; | ||
458 | DWORD dwConfigFlags = 0; | ||
459 | ICLRRuntimeInfo* pCLRRuntimeInfo = NULL; | ||
460 | PFN_CORBINDTOCURRENTRUNTIME pfnCorBindToCurrentRuntime = NULL; | ||
461 | |||
462 | // Always set the error mode because we will always restore it below. | ||
463 | uiMode = ::SetErrorMode(0); | ||
464 | |||
465 | // Check that the supported framework is installed. | ||
466 | hr = CheckSupportedFrameworks(pState->sczConfigPath); | ||
467 | BalExitOnFailure(hr, "Failed to find supported framework."); | ||
468 | |||
469 | // Cache the CLR host to be shutdown later. This can occur on a different thread. | ||
470 | // Disable message boxes from being displayed on error and blocking execution. | ||
471 | ::SetErrorMode(uiMode | SEM_FAILCRITICALERRORS); | ||
472 | |||
473 | hr = LoadSystemLibrary(L"mscoree.dll", &hModule); | ||
474 | BalExitOnFailure(hr, "Failed to load mscoree.dll"); | ||
475 | |||
476 | pfnCLRCreateInstance = reinterpret_cast<CLRCreateInstanceFnPtr>(::GetProcAddress(hModule, "CLRCreateInstance")); | ||
477 | |||
478 | if (pfnCLRCreateInstance) | ||
479 | { | ||
480 | hr = pfnCLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, reinterpret_cast<LPVOID*>(&pCLRMetaHostPolicy)); | ||
481 | if (E_NOTIMPL != hr) | ||
482 | { | ||
483 | BalExitOnRootFailure(hr, "Failed to create instance of ICLRMetaHostPolicy."); | ||
484 | |||
485 | fFallbackToCorBindToCurrentRuntime = FALSE; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | if (fFallbackToCorBindToCurrentRuntime) | ||
490 | { | ||
491 | pfnCorBindToCurrentRuntime = reinterpret_cast<PFN_CORBINDTOCURRENTRUNTIME>(::GetProcAddress(hModule, "CorBindToCurrentRuntime")); | ||
492 | BalExitOnNullWithLastError(pfnCorBindToCurrentRuntime, hr, "Failed to get procedure address for CorBindToCurrentRuntime."); | ||
493 | |||
494 | hr = pfnCorBindToCurrentRuntime(pState->sczConfigPath, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&pState->pCLRHost)); | ||
495 | BalExitOnRootFailure(hr, "Failed to create the CLR host using the application configuration file path."); | ||
496 | } | ||
497 | else | ||
498 | { | ||
499 | |||
500 | hr = SHCreateStreamOnFileEx(pState->sczConfigPath, STGM_READ | STGM_SHARE_DENY_WRITE, 0, FALSE, NULL, &pCfgStream); | ||
501 | BalExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", pState->sczConfigPath); | ||
502 | |||
503 | hr = pCLRMetaHostPolicy->GetRequestedRuntime(METAHOST_POLICY_HIGHCOMPAT, NULL, pCfgStream, NULL, &cchVersion, NULL, NULL, &dwConfigFlags, IID_ICLRRuntimeInfo, reinterpret_cast<LPVOID*>(&pCLRRuntimeInfo)); | ||
504 | BalExitOnRootFailure(hr, "Failed to get the CLR runtime info using the application configuration file path."); | ||
505 | |||
506 | // .NET 4 RTM had a bug where it wouldn't set pcchVersion if pwzVersion was NULL. | ||
507 | if (!cchVersion) | ||
508 | { | ||
509 | hr = pCLRRuntimeInfo->GetVersionString(NULL, &cchVersion); | ||
510 | if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr) | ||
511 | { | ||
512 | BalExitOnFailure(hr, "Failed to get the length of the CLR version string."); | ||
513 | } | ||
514 | } | ||
515 | |||
516 | hr = StrAlloc(&pwzVersion, cchVersion); | ||
517 | ExitOnFailure(hr, "Failed to allocate the CLR version string."); | ||
518 | |||
519 | hr = pCLRRuntimeInfo->GetVersionString(pwzVersion, &cchVersion); | ||
520 | ExitOnFailure(hr, "Failed to get the CLR version string."); | ||
521 | |||
522 | if (CSTR_EQUAL == CompareString(LOCALE_NEUTRAL, 0, L"v4.0.30319", -1, pwzVersion, cchVersion)) | ||
523 | { | ||
524 | hr = VerifyNET4RuntimeIsSupported(); | ||
525 | BalExitOnFailure(hr, "Found unsupported .NET 4 Runtime."); | ||
526 | } | ||
527 | |||
528 | if (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_TRUE == (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_MASK & dwConfigFlags)) | ||
529 | { | ||
530 | hr = pCLRRuntimeInfo->BindAsLegacyV2Runtime(); | ||
531 | BalExitOnRootFailure(hr, "Failed to bind as legacy V2 runtime."); | ||
532 | } | ||
533 | |||
534 | hr = pCLRRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&pState->pCLRHost)); | ||
535 | BalExitOnRootFailure(hr, "Failed to get instance of ICorRuntimeHost."); | ||
536 | } | ||
537 | |||
538 | hr = pState->pCLRHost->Start(); | ||
539 | BalExitOnRootFailure(hr, "Failed to start the CLR host."); | ||
540 | |||
541 | LExit: | ||
542 | ReleaseStr(pwzVersion); | ||
543 | ReleaseNullObject(pCLRRuntimeInfo); | ||
544 | ReleaseNullObject(pCfgStream); | ||
545 | ReleaseNullObject(pCLRMetaHostPolicy); | ||
546 | |||
547 | // Unload the module so it's not in use when we install .NET. | ||
548 | if (FAILED(hr)) | ||
549 | { | ||
550 | ::FreeLibrary(hModule); | ||
551 | } | ||
552 | |||
553 | ::SetErrorMode(uiMode); // restore the previous error mode. | ||
554 | |||
555 | return hr; | ||
556 | } | ||
557 | |||
558 | // Creates the bootstrapper app and returns it for the engine. | ||
559 | static HRESULT CreateManagedBootstrapperApplication( | ||
560 | __in _AppDomain* pAppDomain, | ||
561 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
562 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
563 | ) | ||
564 | { | ||
565 | HRESULT hr = S_OK; | ||
566 | IBootstrapperApplicationFactory* pAppFactory = NULL; | ||
567 | |||
568 | hr = CreateManagedBootstrapperApplicationFactory(pAppDomain, &pAppFactory); | ||
569 | BalExitOnFailure(hr, "Failed to create the factory to create the bootstrapper application."); | ||
570 | |||
571 | hr = pAppFactory->Create(pArgs, pResults); | ||
572 | BalExitOnFailure(hr, "Failed to create the bootstrapper application."); | ||
573 | |||
574 | LExit: | ||
575 | ReleaseNullObject(pAppFactory); | ||
576 | |||
577 | return hr; | ||
578 | } | ||
579 | |||
580 | // Creates the app factory to create the managed app in the default AppDomain. | ||
581 | static HRESULT CreateManagedBootstrapperApplicationFactory( | ||
582 | __in _AppDomain* pAppDomain, | ||
583 | __out IBootstrapperApplicationFactory** ppAppFactory | ||
584 | ) | ||
585 | { | ||
586 | HRESULT hr = S_OK; | ||
587 | BSTR bstrAssemblyName = NULL; | ||
588 | BSTR bstrTypeName = NULL; | ||
589 | _ObjectHandle* pObj = NULL; | ||
590 | VARIANT vtBAFactory; | ||
591 | |||
592 | ::VariantInit(&vtBAFactory); | ||
593 | |||
594 | bstrAssemblyName = ::SysAllocString(MBA_ASSEMBLY_FULL_NAME); | ||
595 | BalExitOnNull(bstrAssemblyName, hr, E_OUTOFMEMORY, "Failed to allocate the full assembly name for the bootstrapper application factory."); | ||
596 | |||
597 | bstrTypeName = ::SysAllocString(MBA_ENTRY_TYPE); | ||
598 | BalExitOnNull(bstrTypeName, hr, E_OUTOFMEMORY, "Failed to allocate the full type name for the BA factory."); | ||
599 | |||
600 | hr = pAppDomain->CreateInstance(bstrAssemblyName, bstrTypeName, &pObj); | ||
601 | BalExitOnRootFailure(hr, "Failed to create the BA factory object."); | ||
602 | |||
603 | hr = pObj->Unwrap(&vtBAFactory); | ||
604 | BalExitOnRootFailure(hr, "Failed to unwrap the BA factory object into the host domain."); | ||
605 | BalExitOnNull(vtBAFactory.punkVal, hr, E_UNEXPECTED, "The variant did not contain the expected IUnknown pointer."); | ||
606 | |||
607 | hr = vtBAFactory.punkVal->QueryInterface(__uuidof(IBootstrapperApplicationFactory), reinterpret_cast<LPVOID*>(ppAppFactory)); | ||
608 | BalExitOnRootFailure(hr, "Failed to query for the bootstrapper app factory interface."); | ||
609 | |||
610 | LExit: | ||
611 | ReleaseVariant(vtBAFactory); | ||
612 | ReleaseNullObject(pObj); | ||
613 | ReleaseBSTR(bstrTypeName); | ||
614 | ReleaseBSTR(bstrAssemblyName); | ||
615 | |||
616 | return hr; | ||
617 | } | ||
618 | |||
619 | static HRESULT CreatePrerequisiteBA( | ||
620 | __in MBASTATE* pState, | ||
621 | __in IBootstrapperEngine* pEngine, | ||
622 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
623 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
624 | ) | ||
625 | { | ||
626 | HRESULT hr = S_OK; | ||
627 | LPWSTR sczMbapreqPath = NULL; | ||
628 | HMODULE hModule = NULL; | ||
629 | |||
630 | hr = PathConcat(pState->sczAppBase, L"mbapreq.dll", &sczMbapreqPath); | ||
631 | BalExitOnFailure(hr, "Failed to get path to pre-requisite BA."); | ||
632 | |||
633 | hModule = ::LoadLibraryExW(sczMbapreqPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); | ||
634 | BalExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL."); | ||
635 | |||
636 | PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "PrereqBootstrapperApplicationCreate")); | ||
637 | BalExitOnNullWithLastError(pfnCreate, hr, "Failed to get PrereqBootstrapperApplicationCreate entry-point from: %ls", sczMbapreqPath); | ||
638 | |||
639 | hr = pfnCreate(&pState->prereqData, pEngine, pArgs, pResults); | ||
640 | BalExitOnFailure(hr, "Failed to create prequisite bootstrapper app."); | ||
641 | |||
642 | pState->hMbapreqModule = hModule; | ||
643 | hModule = NULL; | ||
644 | |||
645 | LExit: | ||
646 | if (hModule) | ||
647 | { | ||
648 | ::FreeLibrary(hModule); | ||
649 | } | ||
650 | ReleaseStr(sczMbapreqPath); | ||
651 | |||
652 | return hr; | ||
653 | } | ||
654 | |||
655 | static HRESULT VerifyNET4RuntimeIsSupported( | ||
656 | ) | ||
657 | { | ||
658 | HRESULT hr = S_OK; | ||
659 | OS_VERSION osv = OS_VERSION_UNKNOWN; | ||
660 | DWORD dwServicePack = 0; | ||
661 | HKEY hKey = NULL; | ||
662 | DWORD er = ERROR_SUCCESS; | ||
663 | DWORD dwRelease = 0; | ||
664 | DWORD cchRelease = sizeof(dwRelease); | ||
665 | |||
666 | OsGetVersion(&osv, &dwServicePack); | ||
667 | if (OS_VERSION_WIN7 == osv && 0 == dwServicePack) | ||
668 | { | ||
669 | hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full", KEY_QUERY_VALUE, &hKey); | ||
670 | if (E_FILENOTFOUND == hr) | ||
671 | { | ||
672 | ExitFunction1(hr = S_OK); | ||
673 | } | ||
674 | BalExitOnFailure(hr, "Failed to open registry key for .NET 4."); | ||
675 | |||
676 | er = ::RegQueryValueExW(hKey, L"Release", NULL, NULL, reinterpret_cast<LPBYTE>(&dwRelease), &cchRelease); | ||
677 | if (ERROR_FILE_NOT_FOUND == er) | ||
678 | { | ||
679 | ExitFunction1(hr = S_OK); | ||
680 | } | ||
681 | BalExitOnWin32Error(er, hr, "Failed to get Release value."); | ||
682 | |||
683 | if (NET452_RELEASE <= dwRelease) | ||
684 | { | ||
685 | hr = E_MBAHOST_NET452_ON_WIN7RTM; | ||
686 | } | ||
687 | } | ||
688 | |||
689 | LExit: | ||
690 | ReleaseRegKey(hKey); | ||
691 | |||
692 | return hr; | ||
693 | } | ||