diff --git a/engine/system/sys_main.h b/engine/system/sys_main.h index 5d83fc78..e2ffb447 100644 --- a/engine/system/sys_main.h +++ b/engine/system/sys_main.h @@ -50,7 +50,7 @@ class find_c { std::filesystem::directory_iterator iter; }; -std::string GetWineHostVersion(); +std::tuple GetWineHostVersion(); // ========== // Interfaces diff --git a/engine/system/win/sys_main.cpp b/engine/system/win/sys_main.cpp index 3078e0d8..67600e1d 100644 --- a/engine/system/win/sys_main.cpp +++ b/engine/system/win/sys_main.cpp @@ -434,23 +434,39 @@ void sys_main_c::SpawnProcess(std::filesystem::path cmdName, const char* argList #endif } -std::string GetWineHostVersion() +// get wine host OS type and x.y.z format version of wine +std::tuple GetWineHostVersion() { #ifdef _WIN32 using WineHostVersionFun = void(const char** /*sysname*/, const char** /*release*/); + using WineVersionFun = char *(); HMODULE mod = GetModuleHandleA("ntdll.dll"); if (!mod) - return ""; + return {"", ""}; auto ptr = GetProcAddress(mod, "wine_get_host_version"); if (!ptr) - return ""; + return {"", ""}; + auto verPtr = GetProcAddress(mod, "wine_get_version"); + if (!verPtr) + return {"", ""}; auto fun = (WineHostVersionFun*)ptr; const char* sysname{}; const char* release{}; fun(&sysname, &release); - return sysname ? sysname : ""; + + auto verFun = (WineVersionFun *)verPtr; + // version in x.y.z format + const char *version = verFun(); + if (sysname && version) + { + return {sysname, version}; + } + else + { + return {"", ""}; + } #else - return ""; + return {"", ""}; #endif } @@ -458,14 +474,22 @@ std::string GetWineHostVersion() const char* PlatformOpenURL(const char* url) { #ifdef _WIN32 - const std::string wineHost = GetWineHostVersion(); - /* - Wine has some loosely determined maximum length on how long of an URL - can be, so we pick a "safe" maximum and refuse to open anything longer. - */ - if ((wineHost == "Linux" || wineHost == "Darwin") && strlen(url) > 1500) - return AllocString("Did not open URL, length likely too long for the OS."); - ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWDEFAULT); + auto [wineHost, wineVersion] = GetWineHostVersion(); + int major = INT_MAX; + int minor = INT_MAX; + auto match = RE2::PartialMatch(wineVersion, "^(\\d+)\\.(\\d+)", &major, &minor); + // work around a pre-8.17 wine bug where long urls may cause a stack corruption and overflow + bool invalidVersion = (major < 8) || (major == 8 && minor < 17); + if ((wineHost == "Linux" || wineHost == "Darwin") && strlen(url) > 1500 && invalidVersion) + { + return AllocString("Did not open URL, length likely too long for pre-8.17 Wine versions."); + } + auto retVal = (INT_PTR)ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWDEFAULT); + // "If the function succeeds, it returns a value greater than 32" + if (retVal <= 32) + { + return AllocString("Opening URL failed."); + } return nullptr; #else #warning LV: URL opening not implemented on this OS. diff --git a/engine/system/win/sys_video.cpp b/engine/system/win/sys_video.cpp index 6f61bffb..f8963d11 100644 --- a/engine/system/win/sys_video.cpp +++ b/engine/system/win/sys_video.cpp @@ -108,7 +108,7 @@ sys_video_c::sys_video_c(sys_IMain* sysHnd) int platformType = GLFW_ANGLE_PLATFORM_TYPE_NONE; #ifdef _WIN32 - const std::string wineHost = GetWineHostVersion(); + auto [wineHost, _] = GetWineHostVersion(); if (wineHost == "Linux") platformType = GLFW_ANGLE_PLATFORM_TYPE_OPENGL; else if (wineHost == "Darwin")