diff options
Diffstat (limited to 'src/ext/Bal/dnchost/dnchost.cpp')
-rw-r--r-- | src/ext/Bal/dnchost/dnchost.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/ext/Bal/dnchost/dnchost.cpp b/src/ext/Bal/dnchost/dnchost.cpp new file mode 100644 index 00000000..8ca326fc --- /dev/null +++ b/src/ext/Bal/dnchost/dnchost.cpp | |||
@@ -0,0 +1,309 @@ | |||
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 DNCSTATE vstate = { }; | ||
6 | |||
7 | |||
8 | // internal function declarations | ||
9 | |||
10 | static HRESULT LoadModulePaths( | ||
11 | __in DNCSTATE* pState | ||
12 | ); | ||
13 | static HRESULT LoadDncConfiguration( | ||
14 | __in DNCSTATE* pState, | ||
15 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs | ||
16 | ); | ||
17 | static HRESULT LoadRuntime( | ||
18 | __in DNCSTATE* pState | ||
19 | ); | ||
20 | static HRESULT LoadManagedBootstrapperApplicationFactory( | ||
21 | __in DNCSTATE* pState | ||
22 | ); | ||
23 | static HRESULT CreatePrerequisiteBA( | ||
24 | __in HRESULT hrHostInitialization, | ||
25 | __in IBootstrapperEngine* pEngine, | ||
26 | __in LPCWSTR wzAppBase, | ||
27 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
28 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
29 | ); | ||
30 | |||
31 | |||
32 | // function definitions | ||
33 | |||
34 | extern "C" BOOL WINAPI DllMain( | ||
35 | IN HINSTANCE hInstance, | ||
36 | IN DWORD dwReason, | ||
37 | IN LPVOID /* pvReserved */ | ||
38 | ) | ||
39 | { | ||
40 | switch (dwReason) | ||
41 | { | ||
42 | case DLL_PROCESS_ATTACH: | ||
43 | ::DisableThreadLibraryCalls(hInstance); | ||
44 | vstate.hInstance = hInstance; | ||
45 | break; | ||
46 | |||
47 | case DLL_PROCESS_DETACH: | ||
48 | vstate.hInstance = NULL; | ||
49 | break; | ||
50 | } | ||
51 | |||
52 | return TRUE; | ||
53 | } | ||
54 | |||
55 | extern "C" HRESULT WINAPI BootstrapperApplicationCreate( | ||
56 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
57 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
58 | ) | ||
59 | { | ||
60 | HRESULT hr = S_OK; | ||
61 | HRESULT hrHostInitialization = S_OK; | ||
62 | IBootstrapperEngine* pEngine = NULL; | ||
63 | |||
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); | ||
69 | ExitOnFailure(hr, "Failed to initialize Bal."); | ||
70 | |||
71 | if (!vstate.fInitialized) | ||
72 | { | ||
73 | hr = XmlInitialize(); | ||
74 | BalExitOnFailure(hr, "Failed to initialize XML."); | ||
75 | |||
76 | hr = LoadModulePaths(&vstate); | ||
77 | BalExitOnFailure(hr, "Failed to get the host base path."); | ||
78 | |||
79 | hr = LoadDncConfiguration(&vstate, pArgs); | ||
80 | BalExitOnFailure(hr, "Failed to get the dnc configuration."); | ||
81 | |||
82 | vstate.fInitialized = TRUE; | ||
83 | } | ||
84 | |||
85 | if (!vstate.fInitializedRuntime) | ||
86 | { | ||
87 | hr = LoadRuntime(&vstate); | ||
88 | |||
89 | vstate.fInitializedRuntime = SUCCEEDED(hr); | ||
90 | } | ||
91 | |||
92 | if (vstate.fInitializedRuntime) | ||
93 | { | ||
94 | if (!vstate.pAppFactory) | ||
95 | { | ||
96 | hr = LoadManagedBootstrapperApplicationFactory(&vstate); | ||
97 | BalExitOnFailure(hr, "Failed to create the .NET Core bootstrapper application factory."); | ||
98 | } | ||
99 | |||
100 | BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading .NET Core %ls bootstrapper application.", DNCHOSTTYPE_FDD == vstate.type ? L"FDD" : L"SCD"); | ||
101 | |||
102 | hr = vstate.pAppFactory->Create(pArgs, pResults); | ||
103 | BalExitOnFailure(hr, "Failed to create the .NET Core bootstrapper application."); | ||
104 | } | ||
105 | else // fallback to the prerequisite BA. | ||
106 | { | ||
107 | if (DNCHOSTTYPE_SCD == vstate.type) | ||
108 | { | ||
109 | hrHostInitialization = E_DNCHOST_SCD_RUNTIME_FAILURE; | ||
110 | BalLogError(hr, "The self-contained .NET Core runtime failed to load. This is an unrecoverable error."); | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | hrHostInitialization = S_OK; | ||
115 | } | ||
116 | BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because .NET Core host could not be loaded, error: 0x%08x.", hr); | ||
117 | |||
118 | hr = CreatePrerequisiteBA(hrHostInitialization, pEngine, vstate.sczAppBase, pArgs, pResults); | ||
119 | BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application."); | ||
120 | } | ||
121 | |||
122 | LExit: | ||
123 | ReleaseNullObject(pEngine); | ||
124 | |||
125 | return hr; | ||
126 | } | ||
127 | |||
128 | extern "C" void WINAPI BootstrapperApplicationDestroy() | ||
129 | { | ||
130 | if (vstate.hMbapreqModule) | ||
131 | { | ||
132 | PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vstate.hMbapreqModule, "DncPrereqBootstrapperApplicationDestroy")); | ||
133 | if (pfnDestroy) | ||
134 | { | ||
135 | (*pfnDestroy)(); | ||
136 | } | ||
137 | |||
138 | ::FreeLibrary(vstate.hMbapreqModule); | ||
139 | vstate.hMbapreqModule = NULL; | ||
140 | } | ||
141 | |||
142 | BalUninitialize(); | ||
143 | } | ||
144 | |||
145 | static HRESULT LoadModulePaths( | ||
146 | __in DNCSTATE* pState | ||
147 | ) | ||
148 | { | ||
149 | HRESULT hr = S_OK; | ||
150 | |||
151 | hr = PathForCurrentProcess(&pState->sczModuleFullPath, pState->hInstance); | ||
152 | BalExitOnFailure(hr, "Failed to get the full host path."); | ||
153 | |||
154 | hr = PathGetDirectory(pState->sczModuleFullPath, &pState->sczAppBase); | ||
155 | BalExitOnFailure(hr, "Failed to get the directory of the full process path."); | ||
156 | |||
157 | hr = PathConcat(pState->sczAppBase, DNC_ASSEMBLY_FILE_NAME, &pState->sczManagedHostPath); | ||
158 | BalExitOnFailure(hr, "Failed to create managed host path."); | ||
159 | |||
160 | LExit: | ||
161 | return hr; | ||
162 | } | ||
163 | |||
164 | static HRESULT LoadDncConfiguration( | ||
165 | __in DNCSTATE* pState, | ||
166 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs | ||
167 | ) | ||
168 | { | ||
169 | HRESULT hr = S_OK; | ||
170 | IXMLDOMDocument* pixdManifest = NULL; | ||
171 | IXMLDOMNode* pixnHost = NULL; | ||
172 | LPWSTR sczPayloadName = NULL; | ||
173 | DWORD dwBool = 0; | ||
174 | |||
175 | hr = XmlLoadDocumentFromFile(pArgs->pCommand->wzBootstrapperApplicationDataPath, &pixdManifest); | ||
176 | BalExitOnFailure(hr, "Failed to load BalManifest '%ls'", pArgs->pCommand->wzBootstrapperApplicationDataPath); | ||
177 | |||
178 | hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBalBAFactoryAssembly", &pixnHost); | ||
179 | BalExitOnFailure(hr, "Failed to get WixBalBAFactoryAssembly element."); | ||
180 | |||
181 | if (S_FALSE == hr) | ||
182 | { | ||
183 | hr = E_NOTFOUND; | ||
184 | BalExitOnRootFailure(hr, "Failed to find WixBalBAFactoryAssembly element in bootstrapper application config."); | ||
185 | } | ||
186 | |||
187 | hr = XmlGetAttributeEx(pixnHost, L"FilePath", &sczPayloadName); | ||
188 | BalExitOnFailure(hr, "Failed to get WixBalBAFactoryAssembly/@FilePath."); | ||
189 | |||
190 | hr = PathConcat(pArgs->pCommand->wzBootstrapperWorkingFolder, sczPayloadName, &pState->sczBaFactoryAssemblyPath); | ||
191 | BalExitOnFailure(hr, "Failed to create BaFactoryAssemblyPath."); | ||
192 | |||
193 | LPCWSTR wzFileName = PathFile(pState->sczBaFactoryAssemblyPath); | ||
194 | LPCWSTR wzExtension = PathExtension(pState->sczBaFactoryAssemblyPath); | ||
195 | if (!wzExtension) | ||
196 | { | ||
197 | BalExitOnFailure(hr = E_FAIL, "BaFactoryAssemblyPath has no extension."); | ||
198 | } | ||
199 | |||
200 | hr = StrAllocString(&pState->sczBaFactoryAssemblyName, wzFileName, wzExtension - wzFileName); | ||
201 | BalExitOnFailure(hr, "Failed to copy BAFactoryAssembly payload Name."); | ||
202 | |||
203 | hr = StrAllocString(&pState->sczBaFactoryDepsJsonPath, pState->sczBaFactoryAssemblyPath, wzExtension - pState->sczBaFactoryAssemblyPath); | ||
204 | BalExitOnFailure(hr, "Failed to initialize deps json path."); | ||
205 | |||
206 | hr = StrAllocString(&pState->sczBaFactoryRuntimeConfigPath, pState->sczBaFactoryDepsJsonPath, 0); | ||
207 | BalExitOnFailure(hr, "Failed to initialize runtime config path."); | ||
208 | |||
209 | hr = StrAllocConcat(&pState->sczBaFactoryDepsJsonPath, L".deps.json", 0); | ||
210 | BalExitOnFailure(hr, "Failed to concat extension to deps json path."); | ||
211 | |||
212 | hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0); | ||
213 | BalExitOnFailure(hr, "Failed to concat extension to runtime config path."); | ||
214 | |||
215 | pState->type = DNCHOSTTYPE_FDD; | ||
216 | |||
217 | hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixDncOptions", &pixnHost); | ||
218 | if (S_FALSE == hr) | ||
219 | { | ||
220 | ExitFunction1(hr = S_OK); | ||
221 | } | ||
222 | BalExitOnFailure(hr, "Failed to find WixDncOptions element in bootstrapper application config."); | ||
223 | |||
224 | hr = XmlGetAttributeNumber(pixnHost, L"SelfContainedDeployment", &dwBool); | ||
225 | if (S_FALSE == hr) | ||
226 | { | ||
227 | hr = S_OK; | ||
228 | } | ||
229 | else if (SUCCEEDED(hr) && dwBool) | ||
230 | { | ||
231 | pState->type = DNCHOSTTYPE_SCD; | ||
232 | } | ||
233 | BalExitOnFailure(hr, "Failed to get SelfContainedDeployment value."); | ||
234 | |||
235 | LExit: | ||
236 | ReleaseStr(sczPayloadName); | ||
237 | ReleaseObject(pixnHost); | ||
238 | ReleaseObject(pixdManifest); | ||
239 | |||
240 | return hr; | ||
241 | } | ||
242 | |||
243 | static HRESULT LoadRuntime( | ||
244 | __in DNCSTATE* pState | ||
245 | ) | ||
246 | { | ||
247 | HRESULT hr = S_OK; | ||
248 | |||
249 | hr = DnchostLoadRuntime( | ||
250 | &pState->hostfxrState, | ||
251 | pState->sczModuleFullPath, | ||
252 | pState->sczManagedHostPath, | ||
253 | pState->sczBaFactoryDepsJsonPath, | ||
254 | pState->sczBaFactoryRuntimeConfigPath); | ||
255 | |||
256 | return hr; | ||
257 | } | ||
258 | |||
259 | static HRESULT LoadManagedBootstrapperApplicationFactory( | ||
260 | __in DNCSTATE* pState | ||
261 | ) | ||
262 | { | ||
263 | HRESULT hr = S_OK; | ||
264 | |||
265 | hr = DnchostCreateFactory( | ||
266 | &pState->hostfxrState, | ||
267 | pState->sczBaFactoryAssemblyName, | ||
268 | pState->sczBaFactoryAssemblyPath, | ||
269 | &pState->pAppFactory); | ||
270 | |||
271 | return hr; | ||
272 | } | ||
273 | |||
274 | static HRESULT CreatePrerequisiteBA( | ||
275 | __in HRESULT hrHostInitialization, | ||
276 | __in IBootstrapperEngine* pEngine, | ||
277 | __in LPCWSTR wzAppBase, | ||
278 | __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, | ||
279 | __inout BOOTSTRAPPER_CREATE_RESULTS* pResults | ||
280 | ) | ||
281 | { | ||
282 | HRESULT hr = S_OK; | ||
283 | LPWSTR sczDncpreqPath = NULL; | ||
284 | HMODULE hModule = NULL; | ||
285 | |||
286 | hr = PathConcat(wzAppBase, L"dncpreq.dll", &sczDncpreqPath); | ||
287 | BalExitOnFailure(hr, "Failed to get path to pre-requisite BA."); | ||
288 | |||
289 | hModule = ::LoadLibraryW(sczDncpreqPath); | ||
290 | BalExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL."); | ||
291 | |||
292 | PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "DncPrereqBootstrapperApplicationCreate")); | ||
293 | BalExitOnNullWithLastError(pfnCreate, hr, "Failed to get DncPrereqBootstrapperApplicationCreate entry-point from: %ls", sczDncpreqPath); | ||
294 | |||
295 | hr = pfnCreate(hrHostInitialization, pEngine, pArgs, pResults); | ||
296 | BalExitOnFailure(hr, "Failed to create prequisite bootstrapper app."); | ||
297 | |||
298 | vstate.hMbapreqModule = hModule; | ||
299 | hModule = NULL; | ||
300 | |||
301 | LExit: | ||
302 | if (hModule) | ||
303 | { | ||
304 | ::FreeLibrary(hModule); | ||
305 | } | ||
306 | ReleaseStr(sczDncpreqPath); | ||
307 | |||
308 | return hr; | ||
309 | } | ||