#define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include "CoreCLR.h" #include "..\..\Dalamud.Boot\logging.h" FILE* g_CmdStream; void ConsoleSetup(const std::wstring console_name) { if (!AllocConsole()) return; SetConsoleTitleW(console_name.c_str()); freopen_s(&g_CmdStream, "CONOUT$", "w", stdout); freopen_s(&g_CmdStream, "CONOUT$", "w", stderr); freopen_s(&g_CmdStream, "CONIN$", "r", stdin); SetConsoleOutputCP(CP_UTF8); } void ConsoleTeardown() { FreeConsole(); } std::optional g_clr; static wchar_t* GetRuntimePath() { int result; std::wstring buffer; wchar_t* runtime_path; wchar_t* _appdata; DWORD username_len = UNLEN + 1; wchar_t username[UNLEN + 1]; buffer.resize(0); result = GetEnvironmentVariableW(L"DALAMUD_RUNTIME", &buffer[0], 0); if (result) { buffer.resize(result); // The first pass returns the required length result = GetEnvironmentVariableW(L"DALAMUD_RUNTIME", &buffer[0], result); return _wcsdup(buffer.c_str()); } // Detect Windows first result = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, nullptr, &_appdata); if (result != 0) { logging::E("Unable to get RoamingAppData path (err={})", result); return NULL; } std::filesystem::path fs_app_data(_appdata); runtime_path = _wcsdup(fs_app_data.append("XIVLauncher").append("runtime").c_str()); if (std::filesystem::exists(runtime_path)) return runtime_path; free(runtime_path); // Next XLCore on Linux result = GetUserNameW(username, &username_len); if (result != 0) { logging::E("Unable to get user name (err={})", result); return NULL; } std::filesystem::path homeDir = L"Z:\\home\\" + std::wstring(username); runtime_path = _wcsdup(homeDir.append(".xlcore").append("runtime").c_str()); if (std::filesystem::exists(runtime_path)) return runtime_path; free(runtime_path); // Finally XOM homeDir = L"Z:\\Users\\" + std::wstring(username); runtime_path = _wcsdup(homeDir.append("Library").append("Application Suppor").append("XIV on Mac").append("runtime").c_str()); if (std::filesystem::exists(runtime_path)) return runtime_path; free(runtime_path); return NULL; } HRESULT InitializeClrAndGetEntryPoint( void* calling_module, bool enable_etw, std::wstring runtimeconfig_path, std::wstring module_path, std::wstring entrypoint_assembly_name, std::wstring entrypoint_method_name, std::wstring entrypoint_delegate_type_name, void** entrypoint_fn) { g_clr.emplace(calling_module); int result; SetEnvironmentVariable(L"DOTNET_MULTILEVEL_LOOKUP", L"0"); SetEnvironmentVariable(L"COMPLUS_ForceENC", L"1"); SetEnvironmentVariable(L"DOTNET_ForceENC", L"1"); // Enable Dynamic PGO SetEnvironmentVariable(L"DOTNET_TieredPGO", L"1"); SetEnvironmentVariable(L"DOTNET_TC_QuickJitForLoops", L"1"); SetEnvironmentVariable(L"DOTNET_ReadyToRun", L"1"); // WINE does not support QUIC and we don't need it SetEnvironmentVariable(L"DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP3SUPPORT", L"0"); SetEnvironmentVariable(L"COMPlus_ETWEnabled", enable_etw ? L"1" : L"0"); wchar_t* dotnet_path = GetRuntimePath(); if (!dotnet_path || !std::filesystem::exists(dotnet_path)) { logging::E("Error: Unable to find .NET runtime path"); return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); } // =========================================================================== // logging::I("with dotnet_path: {}", dotnet_path); logging::I("with config_path: {}", runtimeconfig_path); logging::I("with module_path: {}", module_path); get_hostfxr_parameters init_parameters { sizeof(get_hostfxr_parameters), nullptr, dotnet_path, }; logging::I("Loading hostfxr..."); if ((result = g_clr->load_hostfxr(&init_parameters)) != 0) { logging::E("Failed to load the `hostfxr` library (err=0x{:08x})", result); return result; } logging::I("Done!"); // =========================================================================== // hostfxr_initialize_parameters runtime_parameters { sizeof(hostfxr_initialize_parameters), module_path.c_str(), dotnet_path, }; logging::I("Loading coreclr... "); if ((result = g_clr->load_runtime(runtimeconfig_path, &runtime_parameters)) != 0) { logging::E("Failed to load coreclr (err=0x{:08X})", static_cast(result)); return result; } logging::I("Done!"); // =========================================================================== // logging::I("Loading module from {}...", module_path.c_str()); if ((result = g_clr->load_assembly_and_get_function_pointer( module_path.c_str(), entrypoint_assembly_name.c_str(), entrypoint_method_name.c_str(), entrypoint_delegate_type_name.c_str(), nullptr, entrypoint_fn)) != 0) { logging::E("Failed to load module (err=0x{:X})", static_cast(result)); return result; } logging::I("Done!"); // =========================================================================== // return S_OK; }