diff --git a/Source/Core/Common/ArmCPUDetect.cpp b/Source/Core/Common/ArmCPUDetect.cpp index 7fe2d14220..43c0063f78 100644 --- a/Source/Core/Common/ArmCPUDetect.cpp +++ b/Source/Core/Common/ArmCPUDetect.cpp @@ -14,6 +14,7 @@ #elif defined(_WIN32) #include #include +#include "Common/WindowsRegistry.h" #else #ifndef __FreeBSD__ #include @@ -55,33 +56,14 @@ static constexpr char SUBKEY_CORE0[] = R"(HARDWARE\DESCRIPTION\System\CentralPro // There are some other maybe-interesting values nearby, BIOS info etc. static bool ReadProcessorString(std::string* value, const std::string& name) { - const DWORD flags = RRF_RT_REG_SZ | RRF_NOEXPAND; - DWORD value_len = 0; - auto status = RegGetValueA(HKEY_LOCAL_MACHINE, SUBKEY_CORE0, name.c_str(), flags, nullptr, - nullptr, &value_len); - if (status != ERROR_SUCCESS && status != ERROR_MORE_DATA) - return false; - - value->resize(value_len); - status = RegGetValueA(HKEY_LOCAL_MACHINE, SUBKEY_CORE0, name.c_str(), flags, nullptr, - value->data(), &value_len); - if (status != ERROR_SUCCESS) - { - value->clear(); - return false; - } - - TruncateToCString(value); - return true; + return WindowsRegistry::ReadValue(value, SUBKEY_CORE0, name); } // Read cached register values from the registry static bool ReadPrivilegedCPReg(u64* value, u32 reg) { - DWORD value_len = sizeof(*value); // Not sure if the value name is padded or not - return RegGetValueA(HKEY_LOCAL_MACHINE, SUBKEY_CORE0, fmt::format("CP {:x}", reg).c_str(), - RRF_RT_REG_QWORD, nullptr, value, &value_len) == ERROR_SUCCESS; + return WindowsRegistry::ReadValue(value, SUBKEY_CORE0, fmt::format("CP {:x}", reg).c_str()); } static bool Read_MIDR_EL1(u64* value) diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 2ae474ab64..5d9290549c 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -270,6 +270,7 @@ if(WIN32) CompatPatches.cpp GL/GLInterface/WGL.cpp GL/GLInterface/WGL.h + WindowsRegistry.cpp ) elseif(APPLE) target_sources(common PRIVATE diff --git a/Source/Core/Common/WindowsRegistry.cpp b/Source/Core/Common/WindowsRegistry.cpp new file mode 100644 index 0000000000..4b6f1f2c24 --- /dev/null +++ b/Source/Core/Common/WindowsRegistry.cpp @@ -0,0 +1,72 @@ +#include "Common/WindowsRegistry.h" + +#include +#include +#include +#include "Common/StringUtil.h" + +namespace WindowsRegistry +{ +template +bool ReadValue(T* value, const std::string& subkey, const std::string& name) +{ + DWORD flags = 0; + static_assert(std::is_integral_v && (sizeof(T) == sizeof(u32) || sizeof(T) == sizeof(u64)), + "Unsupported type"); + if constexpr (sizeof(T) == sizeof(u32)) + flags = RRF_RT_REG_DWORD; + else if constexpr (sizeof(T) == sizeof(u64)) + flags = RRF_RT_REG_QWORD; + + DWORD value_len = sizeof(*value); + return RegGetValueA(HKEY_LOCAL_MACHINE, subkey.c_str(), name.c_str(), flags, nullptr, value, + &value_len) == ERROR_SUCCESS; +} + +template <> +bool ReadValue(std::string* value, const std::string& subkey, const std::string& name) +{ + const DWORD flags = RRF_RT_REG_SZ | RRF_NOEXPAND; + DWORD value_len = 0; + auto status = RegGetValueA(HKEY_LOCAL_MACHINE, subkey.c_str(), name.c_str(), flags, nullptr, + nullptr, &value_len); + if (status != ERROR_SUCCESS && status != ERROR_MORE_DATA) + return false; + + value->resize(value_len); + status = RegGetValueA(HKEY_LOCAL_MACHINE, subkey.c_str(), name.c_str(), flags, nullptr, + value->data(), &value_len); + if (status != ERROR_SUCCESS) + { + value->clear(); + return false; + } + + TruncateToCString(value); + return true; +} + +OSVERSIONINFOW GetOSVersion() +{ + // PEB may have faked data if the binary is launched with "compatibility mode" enabled. + // Try to read real OS version from registry. + const char* subkey = R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)"; + OSVERSIONINFOW info{.dwOSVersionInfoSize = sizeof(info)}; + std::string build_str; + if (!ReadValue(&info.dwMajorVersion, subkey, "CurrentMajorVersionNumber") || + !ReadValue(&info.dwMinorVersion, subkey, "CurrentMinorVersionNumber") || + !ReadValue(&build_str, subkey, "CurrentBuildNumber") || + !TryParse(build_str, &info.dwBuildNumber)) + { + // Fallback to version from PEB + typedef DWORD(WINAPI * RtlGetVersion_t)(PRTL_OSVERSIONINFOW); + auto RtlGetVersion = + (RtlGetVersion_t)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlGetVersion"); + RtlGetVersion(&info); + // Clear fields which would not be filled in by registry query + info.dwPlatformId = 0; + info.szCSDVersion[0] = L'\0'; + } + return info; +} +}; // namespace WindowsRegistry diff --git a/Source/Core/Common/WindowsRegistry.h b/Source/Core/Common/WindowsRegistry.h new file mode 100644 index 0000000000..4472a37e0e --- /dev/null +++ b/Source/Core/Common/WindowsRegistry.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace WindowsRegistry +{ +template +bool ReadValue(T* value, const std::string& subkey, const std::string& name); +template bool ReadValue(u32* value, const std::string& subkey, const std::string& name); +template bool ReadValue(u64* value, const std::string& subkey, const std::string& name); +template <> +bool ReadValue(std::string* value, const std::string& subkey, const std::string& name); + +OSVERSIONINFOW GetOSVersion(); +}; // namespace WindowsRegistry diff --git a/Source/Core/Core/DolphinAnalytics.cpp b/Source/Core/Core/DolphinAnalytics.cpp index ea551143ec..b999b55e2a 100644 --- a/Source/Core/Core/DolphinAnalytics.cpp +++ b/Source/Core/Core/DolphinAnalytics.cpp @@ -12,7 +12,8 @@ #include #if defined(_WIN32) -#include +#include +#include "Common/WindowsRegistry.h" #elif defined(__APPLE__) #include #elif defined(ANDROID) @@ -265,21 +266,10 @@ void DolphinAnalytics::MakeBaseBuilder() #if defined(_WIN32) builder.AddData("os-type", "windows"); - // Windows 8 removes support for GetVersionEx and such. Stupid. - DWORD(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW); - *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlGetVersion"); - - OSVERSIONINFOEXW winver; - winver.dwOSVersionInfoSize = sizeof(winver); - if (RtlGetVersion != nullptr) - { - RtlGetVersion(&winver); - builder.AddData("win-ver-major", static_cast(winver.dwMajorVersion)); - builder.AddData("win-ver-minor", static_cast(winver.dwMinorVersion)); - builder.AddData("win-ver-build", static_cast(winver.dwBuildNumber)); - builder.AddData("win-ver-spmajor", static_cast(winver.wServicePackMajor)); - builder.AddData("win-ver-spminor", static_cast(winver.wServicePackMinor)); - } + const auto winver = WindowsRegistry::GetOSVersion(); + builder.AddData("win-ver-major", static_cast(winver.dwMajorVersion)); + builder.AddData("win-ver-minor", static_cast(winver.dwMinorVersion)); + builder.AddData("win-ver-build", static_cast(winver.dwBuildNumber)); #elif defined(ANDROID) builder.AddData("os-type", "android"); builder.AddData("android-manufacturer", s_get_val_func("DEVICE_MANUFACTURER")); diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 1ae8d7212a..ebe61a1560 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -157,6 +157,7 @@ + @@ -778,6 +779,7 @@ + diff --git a/Source/Core/WinUpdater/Platform.cpp b/Source/Core/WinUpdater/Platform.cpp index 565d53c413..f60a6621c0 100644 --- a/Source/Core/WinUpdater/Platform.cpp +++ b/Source/Core/WinUpdater/Platform.cpp @@ -10,6 +10,7 @@ #include "Common/IOFile.h" #include "Common/ScopeGuard.h" #include "Common/StringUtil.h" +#include "Common/WindowsRegistry.h" #include "UpdaterCommon/Platform.h" #include "UpdaterCommon/UI.h" @@ -133,9 +134,7 @@ static const char* VCRuntimeRegistrySubkey() static bool ReadVCRuntimeVersionField(u32* value, const char* name) { - DWORD value_len = sizeof(*value); - return RegGetValueA(HKEY_LOCAL_MACHINE, VCRuntimeRegistrySubkey(), name, RRF_RT_REG_DWORD, - nullptr, value, &value_len) == ERROR_SUCCESS; + return WindowsRegistry::ReadValue(value, VCRuntimeRegistrySubkey(), name); } static std::optional GetInstalledVCRuntimeVersion() @@ -219,11 +218,7 @@ static bool VCRuntimeUpdate(const BuildInfo& build_info) static BuildVersion CurrentOSVersion() { - typedef DWORD(WINAPI * RtlGetVersion_t)(PRTL_OSVERSIONINFOW); - auto RtlGetVersion = - (RtlGetVersion_t)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlGetVersion"); - RTL_OSVERSIONINFOW info{.dwOSVersionInfoSize = sizeof(info)}; - RtlGetVersion(&info); + OSVERSIONINFOW info = WindowsRegistry::GetOSVersion(); return {.major = info.dwMajorVersion, .minor = info.dwMinorVersion, .build = info.dwBuildNumber}; }