aboutsummaryrefslogtreecommitdiff
path: root/src/dnchost/dncutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dnchost/dncutil.cpp')
-rw-r--r--src/dnchost/dncutil.cpp359
1 files changed, 359 insertions, 0 deletions
diff --git a/src/dnchost/dncutil.cpp b/src/dnchost/dncutil.cpp
new file mode 100644
index 00000000..996bf086
--- /dev/null
+++ b/src/dnchost/dncutil.cpp
@@ -0,0 +1,359 @@
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// https://github.com/dotnet/runtime/blob/master/src/installer/corehost/error_codes.h
6#define HostApiBufferTooSmall 0x80008098
7
8// internal function declarations
9
10static HRESULT GetHostfxrPath(
11 __in HOSTFXR_STATE* pState,
12 __in LPCWSTR wzNativeHostPath
13 );
14static HRESULT LoadHostfxr(
15 __in HOSTFXR_STATE* pState
16 );
17static HRESULT InitializeHostfxr(
18 __in HOSTFXR_STATE* pState,
19 __in LPCWSTR wzManagedHostPath,
20 __in LPCWSTR wzDepsJsonPath,
21 __in LPCWSTR wzRuntimeConfigPath
22 );
23static HRESULT InitializeCoreClr(
24 __in HOSTFXR_STATE* pState,
25 __in LPCWSTR wzNativeHostPath
26 );
27static HRESULT LoadCoreClr(
28 __in HOSTFXR_STATE* pState,
29 __in LPCWSTR wzCoreClrPath
30 );
31static HRESULT StartCoreClr(
32 __in HOSTFXR_STATE* pState,
33 __in LPCWSTR wzNativeHostPath,
34 __in size_t cProperties,
35 __in LPCWSTR* propertyKeys,
36 __in LPCWSTR* propertyValues
37 );
38
39
40// function definitions
41
42HRESULT DnchostLoadRuntime(
43 __in HOSTFXR_STATE* pState,
44 __in LPCWSTR wzNativeHostPath,
45 __in LPCWSTR wzManagedHostPath,
46 __in LPCWSTR wzDepsJsonPath,
47 __in LPCWSTR wzRuntimeConfigPath
48 )
49{
50 HRESULT hr = S_OK;
51
52 hr = GetHostfxrPath(pState, wzNativeHostPath);
53 BalExitOnFailure(hr, "Failed to find hostfxr.");
54
55 hr = LoadHostfxr(pState);
56 BalExitOnFailure(hr, "Failed to load hostfxr.");
57
58 hr = InitializeHostfxr(pState, wzManagedHostPath, wzDepsJsonPath, wzRuntimeConfigPath);
59 BalExitOnFailure(hr, "Failed to initialize hostfxr.");
60
61 hr = InitializeCoreClr(pState, wzNativeHostPath);
62 BalExitOnFailure(hr, "Failed to initialize coreclr.");
63
64LExit:
65 return hr;
66}
67
68HRESULT DnchostCreateFactory(
69 __in HOSTFXR_STATE* pState,
70 __in LPCWSTR wzBaFactoryAssemblyName,
71 __in LPCWSTR wzBaFactoryAssemblyPath,
72 __out IBootstrapperApplicationFactory** ppAppFactory
73 )
74{
75 HRESULT hr = S_OK;
76 PFNCREATEBAFACTORY pfnCreateBAFactory = NULL;
77
78 hr = pState->pfnCoreclrCreateDelegate(
79 pState->pClrHandle,
80 pState->dwDomainId,
81 DNC_ASSEMBLY_FULL_NAME,
82 DNC_ENTRY_TYPE,
83 DNC_STATIC_ENTRY_METHOD,
84 reinterpret_cast<void**>(&pfnCreateBAFactory));
85 BalExitOnFailure(hr, "Failed to create delegate in app domain.");
86
87 *ppAppFactory = pfnCreateBAFactory(wzBaFactoryAssemblyName, wzBaFactoryAssemblyPath);
88
89LExit:
90 return hr;
91}
92
93static HRESULT GetHostfxrPath(
94 __in HOSTFXR_STATE* pState,
95 __in LPCWSTR wzNativeHostPath
96 )
97{
98 HRESULT hr = S_OK;
99 get_hostfxr_parameters getHostfxrParameters = { };
100 int nrc = 0;
101 size_t cchHostFxrPath = MAX_PATH;
102
103 getHostfxrParameters.size = sizeof(get_hostfxr_parameters);
104 getHostfxrParameters.assembly_path = wzNativeHostPath;
105
106 // get_hostfxr_path does a full search on every call, so
107 // minimize the number of calls
108 // need to loop
109 for (;;)
110 {
111 cchHostFxrPath *= 2;
112 hr = StrAlloc(&pState->sczHostfxrPath, cchHostFxrPath);
113 BalExitOnFailure(hr, "Failed to allocate hostFxrPath.");
114
115 nrc = get_hostfxr_path(pState->sczHostfxrPath, &cchHostFxrPath, &getHostfxrParameters);
116 if (HostApiBufferTooSmall != nrc)
117 {
118 break;
119 }
120 }
121 if (0 != nrc)
122 {
123 BalExitOnFailure(hr = nrc, "GetHostfxrPath failed");
124 }
125
126LExit:
127 return hr;
128}
129
130static HRESULT LoadHostfxr(
131 __in HOSTFXR_STATE* pState
132 )
133{
134 HRESULT hr = S_OK;
135 HMODULE hHostfxr;
136
137 hHostfxr = ::LoadLibraryExW(pState->sczHostfxrPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
138 BalExitOnNullWithLastError(hHostfxr, hr, "Failed to load hostfxr from '%ls'.", pState->sczHostfxrPath);
139
140 pState->pfnHostfxrInitializeForApp = reinterpret_cast<hostfxr_initialize_for_dotnet_command_line_fn>(::GetProcAddress(hHostfxr, "hostfxr_initialize_for_dotnet_command_line"));
141 BalExitOnNullWithLastError(pState->pfnHostfxrInitializeForApp, hr, "Failed to get procedure address for hostfxr_initialize_for_dotnet_command_line.");
142
143 pState->pfnHostfxrGetRuntimeProperties = reinterpret_cast<hostfxr_get_runtime_properties_fn>(::GetProcAddress(hHostfxr, "hostfxr_get_runtime_properties"));
144 BalExitOnNullWithLastError(pState->pfnHostfxrGetRuntimeProperties, hr, "Failed to get procedure address for hostfxr_get_runtime_properties.");
145
146 pState->pfnHostfxrSetErrorWriter = reinterpret_cast<hostfxr_set_error_writer_fn>(::GetProcAddress(hHostfxr, "hostfxr_set_error_writer"));
147 BalExitOnNullWithLastError(pState->pfnHostfxrSetErrorWriter, hr, "Failed to get procedure address for hostfxr_set_error_writer.");
148
149 pState->pfnHostfxrClose = reinterpret_cast<hostfxr_close_fn>(::GetProcAddress(hHostfxr, "hostfxr_close"));
150 BalExitOnNullWithLastError(pState->pfnHostfxrClose, hr, "Failed to get procedure address for hostfxr_close.");
151
152LExit:
153 // Never unload the module since it isn't meant to be unloaded.
154
155 return hr;
156}
157
158static void HOSTFXR_CALLTYPE DnchostErrorWriter(
159 __in LPCWSTR wzMessage
160 )
161{
162 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "error from hostfxr: %ls", wzMessage);
163}
164
165static HRESULT InitializeHostfxr(
166 __in HOSTFXR_STATE* pState,
167 __in LPCWSTR wzManagedHostPath,
168 __in LPCWSTR wzDepsJsonPath,
169 __in LPCWSTR wzRuntimeConfigPath
170 )
171{
172 HRESULT hr = S_OK;
173
174 pState->pfnHostfxrSetErrorWriter(static_cast<hostfxr_error_writer_fn>(&DnchostErrorWriter));
175
176 LPCWSTR argv[] = {
177 L"exec",
178 L"--depsfile",
179 wzDepsJsonPath,
180 L"--runtimeconfig",
181 wzRuntimeConfigPath,
182 wzManagedHostPath,
183 };
184 hr = pState->pfnHostfxrInitializeForApp(sizeof(argv)/sizeof(LPWSTR), argv, NULL, &pState->hostContextHandle);
185 BalExitOnFailure(hr, "HostfxrInitializeForApp failed");
186
187LExit:
188 return hr;
189}
190
191static HRESULT InitializeCoreClr(
192 __in HOSTFXR_STATE* pState,
193 __in LPCWSTR wzNativeHostPath
194 )
195{
196 HRESULT hr = S_OK;
197 int32_t rc = 0;
198 LPCWSTR* rgPropertyKeys = NULL;
199 LPCWSTR* rgPropertyValues = NULL;
200 size_t cProperties = 0;
201 LPWSTR* rgDirectories = NULL;
202 UINT cDirectories = 0;
203 LPWSTR sczCoreClrPath = NULL;
204
205 // We are not using hostfxr as it was intended to be used. We need to initialize hostfxr so that it properly initializes hostpolicy -
206 // there are pieces of the framework such as AssemblyDependencyResolver that won't work without that. We also need hostfxr to find a
207 // compatible framework for framework-dependent deployed BAs. We had to use hostfxr_initialize_for_dotnet_command_line since
208 // hostfxr_initialize_for_runtime_config doesn't currently (3.x) support self-contained deployed BAs. That means we're supposed to
209 // start the runtime through hostfxr_run_app, but that method shuts down the runtime before returning. We actually want to call
210 // hostfxr_get_runtime_delegate, but that method currently requires hostfxr to be initialized through
211 // hostfxr_initialize_for_runtime_config. So we're forced to locate coreclr.dll and manually load the runtime ourselves.
212
213 // Unfortunately, that's not the only problem. hostfxr has global state that tracks whether it started the runtime. While we keep our
214 // hostfxr_handle open, everyone that calls the hostfxr_initialize_* methods will block until we have started the runtime through
215 // hostfxr or closed our handle. If we close the handle, then hostfxr could potentially try to load a second runtime into the
216 // process, which is not supported. We're going to just keep our handle open since no one else in the process should be trying to
217 // start the runtime anyway.
218
219 rc = pState->pfnHostfxrGetRuntimeProperties(pState->hostContextHandle, &cProperties, rgPropertyKeys, rgPropertyValues);
220 if (HostApiBufferTooSmall != rc)
221 {
222 BalExitOnFailure(hr = rc, "HostfxrGetRuntimeProperties failed to return required size.");
223 }
224
225 rgPropertyKeys = static_cast<LPCWSTR*>(MemAlloc(sizeof(LPWSTR) * cProperties, TRUE));
226 rgPropertyValues = static_cast<LPCWSTR*>(MemAlloc(sizeof(LPWSTR) * cProperties, TRUE));
227 if (!rgPropertyKeys || !rgPropertyValues)
228 {
229 BalExitOnFailure(hr = E_OUTOFMEMORY, "Failed to allocate buffers for runtime properties.");
230 }
231
232 hr = pState->pfnHostfxrGetRuntimeProperties(pState->hostContextHandle, &cProperties, rgPropertyKeys, rgPropertyValues);
233 BalExitOnFailure(hr, "HostfxrGetRuntimeProperties failed.");
234
235 for (DWORD i = 0; i < cProperties; ++i)
236 {
237 if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, 0, rgPropertyKeys[i], -1, L"NATIVE_DLL_SEARCH_DIRECTORIES", -1))
238 {
239 hr = StrSplitAllocArray(&rgDirectories, &cDirectories, rgPropertyValues[i], L";");
240 BalExitOnFailure(hr, "Failed to split NATIVE_DLL_SEARCH_DIRECTORIES '%ls'", rgPropertyValues[i]);
241 }
242 }
243
244 for (DWORD i = 0; i < cDirectories; ++i)
245 {
246 hr = PathConcat(rgDirectories[i], L"coreclr.dll", &sczCoreClrPath);
247 BalExitOnFailure(hr, "Failed to allocate path to coreclr.");
248
249 if (::PathFileExists(sczCoreClrPath))
250 {
251 break;
252 }
253 else
254 {
255 ReleaseNullStr(sczCoreClrPath);
256 }
257 }
258
259 if (!sczCoreClrPath)
260 {
261 for (DWORD i = 0; i < cProperties; ++i)
262 {
263 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "%ls: %ls", rgPropertyKeys[i], rgPropertyValues[i]);
264 }
265 BalExitOnFailure(hr = E_FILENOTFOUND, "Failed to locate coreclr.dll.");
266 }
267
268 hr = LoadCoreClr(pState, sczCoreClrPath);
269 BalExitOnFailure(hr, "Failed to load coreclr.");
270
271 hr = StartCoreClr(pState, wzNativeHostPath, cProperties, rgPropertyKeys, rgPropertyValues);
272 BalExitOnFailure(hr, "Failed to start coreclr.");
273
274LExit:
275 MemFree(rgDirectories);
276 MemFree(rgPropertyValues);
277 MemFree(rgPropertyKeys);
278 ReleaseStr(sczCoreClrPath);
279
280 return hr;
281}
282
283static HRESULT LoadCoreClr(
284 __in HOSTFXR_STATE* pState,
285 __in LPCWSTR wzCoreClrPath
286 )
287{
288 HRESULT hr = S_OK;
289 HMODULE hModule = NULL;
290
291 hModule = ::LoadLibraryExW(wzCoreClrPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
292 BalExitOnNullWithLastError(hModule, hr, "Failed to load coreclr.dll from '%ls'.", wzCoreClrPath);
293
294 pState->pfnCoreclrInitialize = reinterpret_cast<coreclr_initialize_ptr>(::GetProcAddress(hModule, "coreclr_initialize"));
295 BalExitOnNullWithLastError(pState->pfnCoreclrInitialize, hr, "Failed to get procedure address for coreclr_initialize.");
296
297 pState->pfnCoreclrCreateDelegate = reinterpret_cast<coreclr_create_delegate_ptr>(::GetProcAddress(hModule, "coreclr_create_delegate"));
298 BalExitOnNullWithLastError(pState->pfnCoreclrCreateDelegate, hr, "Failed to get procedure address for coreclr_create_delegate.");
299
300LExit:
301 // Never unload the module since coreclr doesn't support it.
302
303 return hr;
304}
305
306static HRESULT StartCoreClr(
307 __in HOSTFXR_STATE* pState,
308 __in LPCWSTR wzNativeHostPath,
309 __in size_t cProperties,
310 __in LPCWSTR* propertyKeys,
311 __in LPCWSTR* propertyValues
312 )
313{
314 HRESULT hr = S_OK;
315 LPSTR szNativeHostPath = NULL;
316 LPSTR* rgPropertyKeys = NULL;
317 LPSTR* rgPropertyValues = NULL;
318
319 rgPropertyKeys = static_cast<LPSTR*>(MemAlloc(sizeof(LPSTR) * cProperties, TRUE));
320 rgPropertyValues = static_cast<LPSTR*>(MemAlloc(sizeof(LPSTR) * cProperties, TRUE));
321 if (!rgPropertyKeys || !rgPropertyValues)
322 {
323 BalExitOnFailure(hr = E_OUTOFMEMORY, "Failed to allocate buffers for runtime properties.");
324 }
325
326 hr = StrAnsiAllocString(&szNativeHostPath, wzNativeHostPath, 0, CP_UTF8);
327 BalExitOnFailure(hr, "Failed to convert module path to UTF8: %ls", wzNativeHostPath);
328
329 for (DWORD i = 0; i < cProperties; ++i)
330 {
331 hr = StrAnsiAllocString(&rgPropertyKeys[i], propertyKeys[i], 0, CP_UTF8);
332 BalExitOnFailure(hr, "Failed to convert property key to UTF8: %ls", propertyKeys[i]);
333
334 hr = StrAnsiAllocString(&rgPropertyValues[i], propertyValues[i], 0, CP_UTF8);
335 BalExitOnFailure(hr, "Failed to convert property value to UTF8: %ls", propertyValues[i]);
336 }
337
338 hr = pState->pfnCoreclrInitialize(szNativeHostPath, "MBA", cProperties, (LPCSTR*)rgPropertyKeys, (LPCSTR*)rgPropertyValues, &pState->pClrHandle, &pState->dwDomainId);
339 BalExitOnFailure(hr, "CoreclrInitialize failed.");
340
341LExit:
342 for (DWORD i = 0; i < cProperties; ++i)
343 {
344 if (rgPropertyKeys)
345 {
346 ReleaseStr(rgPropertyKeys[i]);
347 }
348
349 if (rgPropertyValues)
350 {
351 ReleaseStr(rgPropertyValues[i]);
352 }
353 }
354 ReleaseMem(rgPropertyValues);
355 ReleaseMem(rgPropertyKeys);
356 ReleaseStr(szNativeHostPath);
357
358 return hr;
359}