From 58723a95b3a8809bdd4621e5dea88632b0a4f5bf Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 20 Feb 2024 17:44:23 -0300 Subject: [PATCH] Fix platform version for Windows 10/11 using RtlGetVersion() We've added a new show_platform example to check the reported platform by the base::get_platform() function. --- base/platform.cpp | 27 +++++++++++++++++--- examples/CMakeLists.txt | 1 + examples/show_platform.cpp | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 examples/show_platform.cpp diff --git a/base/platform.cpp b/base/platform.cpp index 4b037901d..76334ae48 100644 --- a/base/platform.cpp +++ b/base/platform.cpp @@ -1,5 +1,5 @@ // LAF Base Library -// Copyright (c) 2021 Igara Studio S.A. +// Copyright (c) 2021-2024 Igara Studio S.A. // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -12,6 +12,8 @@ #if LAF_WINDOWS #include + + typedef LONG (WINAPI* RtlGetVersion_Func)(OSVERSIONINFOEX*); #elif LAF_LINUX // Unix-like system #include #endif @@ -29,9 +31,28 @@ Platform get_platform() OSVERSIONINFOEX osv; osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - ::GetVersionEx((OSVERSIONINFO*)&osv); - p.osVer = Version(osv.dwMajorVersion, osv.dwMinorVersion, 0, 0); + // It looks like GetVersionEx() returns 6.2 for all Windows versions + // after Windows 8 and RtlGetVersion() returns the correct version + // and build number for Windows 10 and 11. + static const auto fnRtlGetVersion = reinterpret_cast( + GetProcAddress(GetModuleHandle(L"ntdll.dll"), + "RtlGetVersion")); + if (!fnRtlGetVersion || + !fnRtlGetVersion(&osv) || + !osv.dwMajorVersion) { + OSVERSIONINFOEX osv; + osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + // Ignore deprecated function warning +#pragma warning(push) +#pragma warning(disable : 4996) + GetVersionEx((OSVERSIONINFO*)&osv); +#pragma warning(pop) + } + + p.osVer = Version(osv.dwMajorVersion, + osv.dwMinorVersion, + osv.dwBuildNumber, 0); switch (osv.wProductType) { case VER_NT_DOMAIN_CONTROLLER: case VER_NT_SERVER: diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9dab91b1c..126e90652 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -23,4 +23,5 @@ if(LAF_BACKEND STREQUAL "skia") laf_add_example(multiple_windows GUI) laf_add_example(panviewport GUI) laf_add_example(shader GUI) + laf_add_example(show_platform CONSOLE) endif() diff --git a/examples/show_platform.cpp b/examples/show_platform.cpp new file mode 100644 index 000000000..3c17f2512 --- /dev/null +++ b/examples/show_platform.cpp @@ -0,0 +1,50 @@ +// LAF Library +// Copyright (c) 2024 Igara Studio S.A. +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#include "base/platform.h" + +#include + +int app_main(int argc, char* argv[]) +{ + base::Platform p = base::get_platform(); + switch (p.os) { +#if LAF_WINDOWS + case base::Platform::OS::Windows: + std::printf( + "Windows v%s%s%s", + p.osVer.str().c_str(), + p.isWow64 ? " WoW64": "", + (p.wineVer ? (std::string(" WINE v") + p.wineVer).c_str(): "")); + break; +#endif + case base::Platform::OS::macOS: + std::printf( + "macOS v%s", + p.osVer.str().c_str()); + break; +#if LAF_LINUX + case base::Platform::OS::Linux: + std::printf("Linux %s", p.distroName.c_str()); + if (!p.distroVer.empty()) + std::printf(" %s", p.distroVer.c_str()); + break; +#endif + } + switch (p.arch) { + case base::Platform::Arch::x86: + std::printf(" (x86)"); + break; + case base::Platform::Arch::x64: + std::printf(" (x64)"); + break; + case base::Platform::Arch::arm64: + std::printf(" (arm64)"); + break; + } + std::printf("\n"); + return 0; +}