diff --git a/Dalamud.Boot/dllmain.cpp b/Dalamud.Boot/dllmain.cpp index 9a741a47f..94f1c7d0f 100644 --- a/Dalamud.Boot/dllmain.cpp +++ b/Dalamud.Boot/dllmain.cpp @@ -133,8 +133,8 @@ DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) { // ============================== VEH ======================================== // logging::I("Initializing VEH..."); - if (utils::is_running_on_linux()) { - logging::I("=> VEH was disabled, running on linux"); + if (utils::is_running_on_wine()) { + logging::I("=> VEH was disabled, running on wine"); } else if (g_startInfo.BootVehEnabled) { if (veh::add_handler(g_startInfo.BootVehFull, g_startInfo.WorkingDirectory)) logging::I("=> Done!"); diff --git a/Dalamud.Boot/utils.cpp b/Dalamud.Boot/utils.cpp index 79205eb8d..b45795045 100644 --- a/Dalamud.Boot/utils.cpp +++ b/Dalamud.Boot/utils.cpp @@ -578,7 +578,7 @@ std::vector utils::get_env_list(const wchar_t* pcszName) { return res; } -bool utils::is_running_on_linux() { +bool utils::is_running_on_wine() { if (get_env(L"XL_WINEONLINUX")) return true; HMODULE hntdll = GetModuleHandleW(L"ntdll.dll"); @@ -588,6 +588,10 @@ bool utils::is_running_on_linux() { return true; if (GetProcAddress(hntdll, "wine_get_host_version")) return true; + if (GetProcAddress(hntdll, "wine_server_call")) + return true; + if (GetProcAddress(hntdll, "wine_unix_to_nt_file_name")) + return true; return false; } diff --git a/Dalamud.Boot/utils.h b/Dalamud.Boot/utils.h index 5d5c90dde..5e3caa4d6 100644 --- a/Dalamud.Boot/utils.h +++ b/Dalamud.Boot/utils.h @@ -264,7 +264,7 @@ namespace utils { return get_env_list(unicode::convert(pcszName).c_str()); } - bool is_running_on_linux(); + bool is_running_on_wine(); std::filesystem::path get_module_path(HMODULE hModule); diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs index 1975505a8..7ad794e42 100644 --- a/Dalamud/EntryPoint.cs +++ b/Dalamud/EntryPoint.cs @@ -166,7 +166,7 @@ public sealed class EntryPoint // This is due to GitHub not supporting TLS 1.0, so we enable all TLS versions globally ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls; - if (!Util.IsLinux()) + if (!Util.IsWine()) InitSymbolHandler(info); var dalamud = new Dalamud(info, configuration, mainThreadContinueEvent); diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs index 5f2e4d5bf..78edda3dd 100644 --- a/Dalamud/Utility/Util.cs +++ b/Dalamud/Utility/Util.cs @@ -1,13 +1,12 @@ -using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; -using System.Net.Http; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; using Dalamud.Configuration.Internal; @@ -15,14 +14,12 @@ using Dalamud.Data; using Dalamud.Game; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Utility; using Dalamud.Logging.Internal; -using Dalamud.Networking.Http; +using Dalamud.Memory; using ImGuiNET; using Lumina.Excel.GeneratedSheets; -using Microsoft.Win32; using Serilog; namespace Dalamud.Utility; @@ -38,7 +35,7 @@ public static class Util private static ulong moduleStartAddr; private static ulong moduleEndAddr; - + /// /// Gets the assembly version of Dalamud. /// @@ -491,32 +488,57 @@ public static class Util } /// - /// Heuristically determine if Dalamud is running on Linux/WINE. + /// Determine if Dalamud is currently running within a Wine context (e.g. either on macOS or Linux). This method + /// will not return information about the host operating system. /// - /// Whether or not Dalamud is running on Linux/WINE. - public static bool IsLinux() + /// Returns true if Wine is detected, false otherwise. + public static bool IsWine() { - bool Check1() + if (EnvironmentConfiguration.XlWineOnLinux) return true; + if (Environment.GetEnvironmentVariable("XL_PLATFORM") is not null and not "Windows") return true; + + var ntdll = NativeFunctions.GetModuleHandleW("ntdll.dll"); + + // Test to see if any Wine specific exports exist. If they do, then we are running on Wine. + // The exports "wine_get_version", "wine_get_build_id", and "wine_get_host_version" will tend to be hidden + // by most Linux users (else FFXIV will want a macOS license), so we will additionally check some lesser-known + // exports as well. + return AnyProcExists( + ntdll, + "wine_get_version", + "wine_get_build_id", + "wine_get_host_version", + "wine_server_call", + "wine_unix_to_nt_file_name"); + + bool AnyProcExists(nint handle, params string[] procs) => + procs.Any(p => NativeFunctions.GetProcAddress(handle, p) != nint.Zero); + } + + /// + /// Gets the best guess for the current host's platform based on the XL_PLATFORM environment variable or + /// heuristics. + /// + /// + /// macOS users running without XL_PLATFORM being set will be reported as Linux users. Due to the way our + /// Wines work, there isn't a great (consistent) way to split the two apart if we're not told. + /// + /// Returns the that Dalamud is currently running on. + public static OSPlatform GetHostPlatform() + { + switch (Environment.GetEnvironmentVariable("XL_PLATFORM")) { - return EnvironmentConfiguration.XlWineOnLinux; + case "Windows": return OSPlatform.Windows; + case "MacOS": return OSPlatform.OSX; + case "Linux": return OSPlatform.Linux; } - - bool Check2() - { - var hModule = NativeFunctions.GetModuleHandleW("ntdll.dll"); - var proc1 = NativeFunctions.GetProcAddress(hModule, "wine_get_version"); - var proc2 = NativeFunctions.GetProcAddress(hModule, "wine_get_build_id"); - - return proc1 != IntPtr.Zero || proc2 != IntPtr.Zero; - } - - bool Check3() - { - return Registry.CurrentUser.OpenSubKey(@"Software\Wine") != null || - Registry.LocalMachine.OpenSubKey(@"Software\Wine") != null; - } - - return Check1() || Check2() || Check3(); + + // n.b. we had some fancy code here to check if the Wine host version returned "Darwin" but apparently + // *all* our Wines report Darwin if exports aren't hidden. As such, it is effectively impossible (without some + // (very cursed and inaccurate heuristics) to determine if we're on macOS or Linux unless we're explicitly told + // by our launcher. See commit a7aacb15e4603a367e2f980578271a9a639d8852 for the old check. + + return IsWine() ? OSPlatform.Linux : OSPlatform.Windows; } /// @@ -685,7 +707,7 @@ public static class Util ImGui.SetClipboardText(actor.Address.ToInt64().ToString("X")); } } - + private static unsafe void ShowValue(ulong addr, IEnumerable path, Type type, object value) { if (type.IsPointer)