extern "C" __declspec(dllexport) HRESULT __stdcall CallApplicationMain(PCALL_APPLICATION_MAIN_DATA data) { HRESULT hr = S_OK; errno_t errno = 0; FnGetCLRRuntimeHost pfnGetCLRRuntimeHost = nullptr; ICLRRuntimeHost2* pCLRRuntimeHost = nullptr; TCHAR szCurrentDirectory[MAX_PATH]; TCHAR szCoreClrDirectory[MAX_PATH]; TCHAR lpCoreClrModulePath[MAX_PATH]; size_t cchTrustedPlatformAssemblies = 0; LPWSTR pwszTrustedPlatformAssemblies = nullptr; Win32KDisable(); if (data->runtimeDirectory) { errno = wcscpy_s(szCurrentDirectory, data->runtimeDirectory); CHECK_RETURN_VALUE_FAIL_EXIT_VIA_FINISHED(errno); } else { GetModuleDirectory(NULL, szCurrentDirectory); } HMODULE hCoreCLRModule = LoadCoreClr(); if (!hCoreCLRModule) { printf_s("Failed to locate coreclr.dll.\n"); return E_FAIL; } // Get the path to the module DWORD dwCoreClrModulePathSize = GetModuleFileName(hCoreCLRModule, lpCoreClrModulePath, MAX_PATH); lpCoreClrModulePath[dwCoreClrModulePathSize] = '\0'; GetModuleDirectory(hCoreCLRModule, szCoreClrDirectory); HMODULE ignoreModule; // Pin the module - CoreCLR.dll does not support being unloaded. if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, lpCoreClrModulePath, &ignoreModule)) { printf_s("Failed to pin coreclr.dll.\n"); return E_FAIL; } pfnGetCLRRuntimeHost = (FnGetCLRRuntimeHost)::GetProcAddress(hCoreCLRModule, "GetCLRRuntimeHost"); if (!pfnGetCLRRuntimeHost) { printf_s("Failed to find export GetCLRRuntimeHost.\n"); return E_FAIL; } hr = pfnGetCLRRuntimeHost(IID_ICLRRuntimeHost2, (IUnknown**)&pCLRRuntimeHost); if (FAILED(hr)) { printf_s("Failed to get IID_ICLRRuntimeHost2.\n"); return hr; } STARTUP_FLAGS dwStartupFlags = (STARTUP_FLAGS)( STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN | STARTUP_FLAGS::STARTUP_SERVER_GC ); pCLRRuntimeHost->SetStartupFlags(dwStartupFlags); // Authenticate with either CORECLR_HOST_AUTHENTICATION_KEY or CORECLR_HOST_AUTHENTICATION_KEY_NONGEN hr = pCLRRuntimeHost->Authenticate(CORECLR_HOST_AUTHENTICATION_KEY); if (FAILED(hr)) { printf_s("Failed to Authenticate().\n"); return hr; } hr = pCLRRuntimeHost->Start(); if (FAILED(hr)) { printf_s("Failed to Start().\n"); return hr; } const wchar_t* property_keys[] = { // Allowed property names: // APPBASE // - The base path of the application from which the exe and other assemblies will be loaded L"APPBASE", // // TRUSTED_PLATFORM_ASSEMBLIES // - The list of complete paths to each of the fully trusted assemblies L"TRUSTED_PLATFORM_ASSEMBLIES", // // APP_PATHS // - The list of paths which will be probed by the assembly loader L"APP_PATHS", // // APP_NI_PATHS // - The list of additional paths that the assembly loader will probe for ngen images // // NATIVE_DLL_SEARCH_DIRECTORIES // - The list of paths that will be probed for native DLLs called by PInvoke // }; cchTrustedPlatformAssemblies = TRUSTED_PLATFORM_ASSEMBLIES_STRING_BUFFER_SIZE_CCH; pwszTrustedPlatformAssemblies = (LPWSTR)calloc(cchTrustedPlatformAssemblies+1, sizeof(WCHAR)); if (pwszTrustedPlatformAssemblies == NULL) { goto Finished; } pwszTrustedPlatformAssemblies[0] = L'\0'; // Try native images first if (!GetTrustedPlatformAssembliesList(szCoreClrDirectory, true, pwszTrustedPlatformAssemblies, cchTrustedPlatformAssemblies)) { if (!GetTrustedPlatformAssembliesList(szCoreClrDirectory, false, pwszTrustedPlatformAssemblies, cchTrustedPlatformAssemblies)) { printf_s("Failed to find files in the coreclr directory\n"); return E_FAIL; } } // Add the assembly containing the app domain manager to the trusted list errno = wcscat_s(pwszTrustedPlatformAssemblies, cchTrustedPlatformAssemblies, szCurrentDirectory); CHECK_RETURN_VALUE_FAIL_EXIT_VIA_FINISHED(errno); errno = wcscat_s(pwszTrustedPlatformAssemblies, cchTrustedPlatformAssemblies, L"kre.coreclr.managed.dll"); CHECK_RETURN_VALUE_FAIL_EXIT_VIA_FINISHED(errno); //wstring appPaths(szCurrentDirectory); WCHAR wszAppPaths[MAX_PATH]; wszAppPaths[0] = L'\0'; errno = wcscat_s(wszAppPaths, _countof(wszAppPaths), szCurrentDirectory); CHECK_RETURN_VALUE_FAIL_EXIT_VIA_FINISHED(errno); errno = wcscat_s(wszAppPaths, _countof(wszAppPaths), L";"); CHECK_RETURN_VALUE_FAIL_EXIT_VIA_FINISHED(errno); errno = wcscat_s(wszAppPaths, _countof(wszAppPaths), szCoreClrDirectory); CHECK_RETURN_VALUE_FAIL_EXIT_VIA_FINISHED(errno); errno = wcscat_s(wszAppPaths, _countof(wszAppPaths), L";"); CHECK_RETURN_VALUE_FAIL_EXIT_VIA_FINISHED(errno); const wchar_t* property_values[] = { // APPBASE data->applicationBase, // TRUSTED_PLATFORM_ASSEMBLIES pwszTrustedPlatformAssemblies, // APP_PATHS wszAppPaths, }; DWORD domainId; DWORD dwFlagsAppDomain = APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS | APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP; LPCWSTR szAssemblyName = L"kre.coreclr.managed, Version=0.1.0.0"; LPCWSTR szEntryPointTypeName = L"DomainManager"; LPCWSTR szMainMethodName = L"Execute"; int nprops = sizeof(property_keys) / sizeof(wchar_t*); hr = pCLRRuntimeHost->CreateAppDomainWithManager( L"kre.coreclr.managed", dwFlagsAppDomain, NULL, NULL, nprops, property_keys, property_values, &domainId); if (FAILED(hr)) { wprintf_s(L"TPA %d %S\n", wcslen(pwszTrustedPlatformAssemblies), pwszTrustedPlatformAssemblies); wprintf_s(L"AppPaths %S\n", wszAppPaths); printf_s("Failed to create app domain (%x).\n", hr); return hr; } HostMain pHostMain; hr = pCLRRuntimeHost->CreateDelegate( domainId, szAssemblyName, szEntryPointTypeName, szMainMethodName, (INT_PTR*)&pHostMain); if (FAILED(hr)) { printf_s("Failed to create main delegate (%x).\n", hr); return hr; } SetEnvironmentVariable(L"KRE_FRAMEWORK", L"aspnetcore50"); // Call main data->exitcode = pHostMain(data->argc, data->argv); pCLRRuntimeHost->UnloadAppDomain(domainId, true); pCLRRuntimeHost->Stop(); Finished: if (pwszTrustedPlatformAssemblies != NULL) { free(pwszTrustedPlatformAssemblies); pwszTrustedPlatformAssemblies = NULL; } if (FAILED(hr)) { return hr; } else { return S_OK; } }
HRESULT ExecuteMain(ICLRRuntimeHost2* pCLRRuntimeHost, PCALL_APPLICATION_MAIN_DATA data, const std::wstring& runtime_directory, const std::wstring& core_clr_directory, dnx::trace_writer& trace_writer) { const wchar_t* property_keys[] = { // Allowed property names: // APPBASE // - The base path of the application from which the exe and other assemblies will be loaded L"APPBASE", // // TRUSTED_PLATFORM_ASSEMBLIES // - The list of complete paths to each of the fully trusted assemblies L"TRUSTED_PLATFORM_ASSEMBLIES", // // APP_PATHS // - The list of paths which will be probed by the assembly loader L"APP_PATHS", // // APP_NI_PATHS // - The list of additional paths that the assembly loader will probe for ngen images // // NATIVE_DLL_SEARCH_DIRECTORIES // - The list of paths that will be probed for native DLLs called by PInvoke // L"AppDomainCompatSwitch", }; std::wstring trusted_platform_assemblies; // Came up with 8192 empirically - the string we build is about 4000 characters on my machine but it contains // paths to the user profile folder so it can be bigger. trusted_platform_assemblies.reserve(8192); // Try native images first if (!GetTrustedPlatformAssembliesList(core_clr_directory, true, trusted_platform_assemblies)) { if (!GetTrustedPlatformAssembliesList(core_clr_directory, false, trusted_platform_assemblies)) { trace_writer.write(L"Failed to find TPA files in the coreclr directory", false); return E_FAIL; } } // Add the assembly containing the app domain manager to the trusted list trusted_platform_assemblies.append(dnx::utils::path_combine(runtime_directory, L"Microsoft.Dnx.Host.CoreClr.dll")); std::wstring app_paths; app_paths.append(runtime_directory).append(L";"); app_paths.append(core_clr_directory).append(L";"); const wchar_t* property_values[] = { // APPBASE data->applicationBase, // TRUSTED_PLATFORM_ASSEMBLIES trusted_platform_assemblies.c_str(), // APP_PATHS app_paths.c_str(), // Use the latest behavior when TFM not specified L"UseLatestBehaviorWhenTFMNotSpecified", }; DWORD domainId; HRESULT hr = pCLRRuntimeHost->CreateAppDomainWithManager( L"Microsoft.Dnx.Host.CoreClr", APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS | APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP | APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT, NULL, NULL, sizeof(property_keys) / sizeof(wchar_t*), property_keys, property_values, &domainId); if (FAILED(hr)) { trace_writer.write(L"Failed to create app domain", false); trace_writer.write(std::wstring(L"TPA: ").append(trusted_platform_assemblies), false); trace_writer.write(std::wstring(L"AppPaths: ").append(app_paths), false); return hr; } HostMain main_function; // looks like the Version in the assembly is mandatory but the value does not matter hr = pCLRRuntimeHost->CreateDelegate(domainId, L"Microsoft.Dnx.Host.CoreClr, Version=0.0.0.0", L"DomainManager", L"Execute", (INT_PTR*)&main_function); if (FAILED(hr)) { trace_writer.write(L"Failed to create main delegate", false); return hr; } // Call main data->exitcode = main_function(data->argc, data->argv); pCLRRuntimeHost->UnloadAppDomain(domainId, true); return S_OK; }
extern "C" HRESULT CallApplicationMain(PCALL_APPLICATION_MAIN_DATA data) { HRESULT hr = S_OK; size_t cchTrustedPlatformAssemblies = 0; std::string runtimeDirectory; if (data->runtimeDirectory) { runtimeDirectory = data->runtimeDirectory; } else { // TODO: This should get the directory that this library is in, not the CWD. char szCurrentDirectory[PATH_MAX]; if (!getcwd(szCurrentDirectory, PATH_MAX)) { return E_FAIL; } runtimeDirectory = std::string(szCurrentDirectory); } std::string coreClrDirectory; void* coreClr = LoadCoreClr(coreClrDirectory); if (!coreClr) { char* error = dlerror(); fprintf(stderr, "failed to locate coreclr.dll with error %s\n", error); return E_FAIL; } const char* property_keys[] = { "APPBASE", "TRUSTED_PLATFORM_ASSEMBLIES", "APP_PATHS", }; std::string trustedPlatformAssemblies; // Try native images first if (!GetTrustedPlatformAssembliesList(coreClrDirectory.c_str(), true, trustedPlatformAssemblies)) { if (!GetTrustedPlatformAssembliesList(coreClrDirectory.c_str(), false, trustedPlatformAssemblies)) { fprintf(stderr, "Failed to find files in the coreclr directory\n"); hr = E_FAIL; return hr; } } // Add the assembly containing the app domain manager to the trusted list trustedPlatformAssemblies.append(runtimeDirectory); trustedPlatformAssemblies.append("dnx.coreclr.managed.dll"); std::string appPaths(runtimeDirectory); appPaths.append(":"); appPaths.append(coreClrDirectory); appPaths.append(":"); const char* property_values[] = { // APPBASE data->applicationBase, // TRUESTED_PLATFORM_ASSEMBLIES trustedPlatformAssemblies.c_str(), // APP_PATHS appPaths.c_str(), }; ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreClr, "ExecuteAssembly"); if (!executeAssembly) { fprintf(stderr, "Could not find ExecuteAssembly entrypoint in coreclr.\n"); return E_FAIL; } setenv("DNX_FRAMEWORK", "dnxcore50", 1); std::string coreClrDllPath(coreClrDirectory); coreClrDllPath.append("/"); coreClrDllPath.append("libcoreclr.so"); char pathToBootstrapper[PATH_MAX]; ssize_t pathLen = readlink("/proc/self/exe", pathToBootstrapper, PATH_MAX - 1); if (pathLen == -1) { fprintf(stderr, "Could not locate full bootstrapper path.\n"); return E_FAIL; } pathToBootstrapper[pathLen] = '\0'; hr = executeAssembly(pathToBootstrapper, coreClrDllPath.c_str(), "dnx.coreclr.managed", sizeof(property_keys) / sizeof(property_keys[0]), property_keys, property_values, data->argc, (const char**)data->argv, nullptr, "dnx.coreclr.managed, Version=0.1.0.0", "DomainManager", "Execute", (DWORD*)&(data->exitcode)); dlclose(coreClr); return hr; }