WindowsRegistry.cpp 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #include "Common/WindowsRegistry.h"
  2. #include <Windows.h>
  3. #include <string>
  4. #include <type_traits>
  5. #include "Common/StringUtil.h"
  6. namespace WindowsRegistry
  7. {
  8. template <typename T>
  9. bool ReadValue(T* value, const std::string& subkey, const std::string& name)
  10. {
  11. DWORD flags = 0;
  12. static_assert(std::is_integral_v<T> && (sizeof(T) == sizeof(u32) || sizeof(T) == sizeof(u64)),
  13. "Unsupported type");
  14. if constexpr (sizeof(T) == sizeof(u32))
  15. flags = RRF_RT_REG_DWORD;
  16. else if constexpr (sizeof(T) == sizeof(u64))
  17. flags = RRF_RT_REG_QWORD;
  18. DWORD value_len = sizeof(*value);
  19. return RegGetValueA(HKEY_LOCAL_MACHINE, subkey.c_str(), name.c_str(), flags, nullptr, value,
  20. &value_len) == ERROR_SUCCESS;
  21. }
  22. template <>
  23. bool ReadValue(std::string* value, const std::string& subkey, const std::string& name)
  24. {
  25. const DWORD flags = RRF_RT_REG_SZ | RRF_NOEXPAND;
  26. DWORD value_len = 0;
  27. auto status = RegGetValueA(HKEY_LOCAL_MACHINE, subkey.c_str(), name.c_str(), flags, nullptr,
  28. nullptr, &value_len);
  29. if (status != ERROR_SUCCESS && status != ERROR_MORE_DATA)
  30. return false;
  31. value->resize(value_len);
  32. status = RegGetValueA(HKEY_LOCAL_MACHINE, subkey.c_str(), name.c_str(), flags, nullptr,
  33. value->data(), &value_len);
  34. if (status != ERROR_SUCCESS)
  35. {
  36. value->clear();
  37. return false;
  38. }
  39. TruncateToCString(value);
  40. return true;
  41. }
  42. OSVERSIONINFOW GetOSVersion()
  43. {
  44. // PEB may have faked data if the binary is launched with "compatibility mode" enabled.
  45. // Try to read real OS version from registry.
  46. const char* subkey = R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)";
  47. OSVERSIONINFOW info{.dwOSVersionInfoSize = sizeof(info)};
  48. std::string build_str;
  49. if (!ReadValue(&info.dwMajorVersion, subkey, "CurrentMajorVersionNumber") ||
  50. !ReadValue(&info.dwMinorVersion, subkey, "CurrentMinorVersionNumber") ||
  51. !ReadValue(&build_str, subkey, "CurrentBuildNumber") ||
  52. !TryParse(build_str, &info.dwBuildNumber))
  53. {
  54. // Fallback to version from PEB
  55. typedef DWORD(WINAPI * RtlGetVersion_t)(PRTL_OSVERSIONINFOW);
  56. auto RtlGetVersion =
  57. (RtlGetVersion_t)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlGetVersion");
  58. RtlGetVersion(&info);
  59. // Clear fields which would not be filled in by registry query
  60. info.dwPlatformId = 0;
  61. info.szCSDVersion[0] = L'\0';
  62. }
  63. return info;
  64. }
  65. } // namespace WindowsRegistry