system-info-windows.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include "system-info.hpp"
  2. #include <dxgi.h>
  3. #include <cinttypes>
  4. #include <shlobj.h>
  5. #include <util/dstr.hpp>
  6. #include <util/platform.h>
  7. #include <util/windows/ComPtr.hpp>
  8. #include <util/windows/win-registry.h>
  9. #include <util/windows/win-version.h>
  10. static std::optional<std::vector<GoLiveApi::Gpu>> system_gpu_data()
  11. {
  12. ComPtr<IDXGIFactory1> factory;
  13. ComPtr<IDXGIAdapter1> adapter;
  14. HRESULT hr;
  15. UINT i;
  16. hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
  17. if (FAILED(hr))
  18. return std::nullopt;
  19. std::vector<GoLiveApi::Gpu> adapter_info;
  20. for (i = 0; factory->EnumAdapters1(i, adapter.Assign()) == S_OK; ++i) {
  21. DXGI_ADAPTER_DESC desc;
  22. char name[512] = "";
  23. char driver_version[512] = "";
  24. hr = adapter->GetDesc(&desc);
  25. if (FAILED(hr))
  26. continue;
  27. /* ignore Microsoft's 'basic' renderer' */
  28. if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c)
  29. continue;
  30. os_wcs_to_utf8(desc.Description, 0, name, sizeof(name));
  31. GoLiveApi::Gpu data;
  32. data.model = name;
  33. data.vendor_id = desc.VendorId;
  34. data.device_id = desc.DeviceId;
  35. data.dedicated_video_memory = desc.DedicatedVideoMemory;
  36. data.shared_system_memory = desc.SharedSystemMemory;
  37. /* driver version */
  38. LARGE_INTEGER umd;
  39. hr = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &umd);
  40. if (SUCCEEDED(hr)) {
  41. const uint64_t version = umd.QuadPart;
  42. const uint16_t aa = (version >> 48) & 0xffff;
  43. const uint16_t bb = (version >> 32) & 0xffff;
  44. const uint16_t ccccc = (version >> 16) & 0xffff;
  45. const uint16_t ddddd = version & 0xffff;
  46. snprintf(driver_version, sizeof(driver_version), "%" PRIu16 ".%" PRIu16 ".%" PRIu16 ".%" PRIu16,
  47. aa, bb, ccccc, ddddd);
  48. data.driver_version = driver_version;
  49. }
  50. adapter_info.push_back(data);
  51. }
  52. return adapter_info;
  53. }
  54. static void get_processor_info(char **name, DWORD *speed)
  55. {
  56. HKEY key;
  57. wchar_t data[1024];
  58. DWORD size;
  59. LSTATUS status;
  60. memset(data, 0, sizeof(data));
  61. status = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key);
  62. if (status != ERROR_SUCCESS)
  63. return;
  64. size = sizeof(data);
  65. status = RegQueryValueExW(key, L"ProcessorNameString", NULL, NULL, (LPBYTE)data, &size);
  66. if (status == ERROR_SUCCESS) {
  67. os_wcs_to_utf8_ptr(data, 0, name);
  68. } else {
  69. *name = 0;
  70. }
  71. size = sizeof(*speed);
  72. status = RegQueryValueExW(key, L"~MHz", NULL, NULL, (LPBYTE)speed, &size);
  73. if (status != ERROR_SUCCESS)
  74. *speed = 0;
  75. RegCloseKey(key);
  76. }
  77. #define WIN10_GAME_BAR_REG_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\GameDVR"
  78. #define WIN10_GAME_DVR_POLICY_REG_KEY L"SOFTWARE\\Policies\\Microsoft\\Windows\\GameDVR"
  79. #define WIN10_GAME_DVR_REG_KEY L"System\\GameConfigStore"
  80. #define WIN10_GAME_MODE_REG_KEY L"Software\\Microsoft\\GameBar"
  81. #define WIN10_HAGS_REG_KEY L"SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers"
  82. static std::optional<GoLiveApi::GamingFeatures> get_gaming_features_data(const win_version_info &ver)
  83. {
  84. uint32_t win_ver = (ver.major << 8) | ver.minor;
  85. if (win_ver < 0xA00)
  86. return std::nullopt;
  87. GoLiveApi::GamingFeatures gaming_features;
  88. struct feature_mapping_s {
  89. std::optional<bool> *field;
  90. HKEY hkey;
  91. LPCWSTR sub_key;
  92. LPCWSTR value_name;
  93. LPCWSTR backup_value_name;
  94. bool non_existence_is_false;
  95. DWORD disabled_value;
  96. };
  97. struct feature_mapping_s features[] = {
  98. {&gaming_features.game_bar_enabled, HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY, L"AppCaptureEnabled", 0,
  99. false, 0},
  100. {&gaming_features.game_dvr_allowed, HKEY_CURRENT_USER, WIN10_GAME_DVR_POLICY_REG_KEY, L"AllowGameDVR",
  101. 0, false, 0},
  102. {&gaming_features.game_dvr_enabled, HKEY_CURRENT_USER, WIN10_GAME_DVR_REG_KEY, L"GameDVR_Enabled", 0,
  103. false, 0},
  104. {&gaming_features.game_dvr_bg_recording, HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY,
  105. L"HistoricalCaptureEnabled", 0, false, 0},
  106. {&gaming_features.game_mode_enabled, HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY, L"AutoGameModeEnabled",
  107. L"AllowAutoGameMode", false, 0},
  108. {&gaming_features.hags_enabled, HKEY_LOCAL_MACHINE, WIN10_HAGS_REG_KEY, L"HwSchMode", 0, true, 1}};
  109. for (int i = 0; i < sizeof(features) / sizeof(*features); ++i) {
  110. struct reg_dword info;
  111. get_reg_dword(features[i].hkey, features[i].sub_key, features[i].value_name, &info);
  112. if (info.status != ERROR_SUCCESS && features[i].backup_value_name) {
  113. get_reg_dword(features[i].hkey, features[i].sub_key, features[i].backup_value_name, &info);
  114. }
  115. if (info.status == ERROR_SUCCESS) {
  116. *features[i].field = info.return_value != features[i].disabled_value;
  117. } else if (features[i].non_existence_is_false) {
  118. *features[i].field = false;
  119. }
  120. }
  121. return gaming_features;
  122. }
  123. static inline bool get_reg_sz(HKEY key, const wchar_t *val, wchar_t *buf, DWORD size)
  124. {
  125. const LSTATUS status = RegGetValueW(key, NULL, val, RRF_RT_REG_SZ, NULL, buf, &size);
  126. return status == ERROR_SUCCESS;
  127. }
  128. #define MAX_SZ_LEN 256
  129. #define WINVER_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
  130. static char win_release_id[MAX_SZ_LEN] = "unavailable";
  131. static inline void get_reg_ver(struct win_version_info *ver)
  132. {
  133. HKEY key;
  134. DWORD size, dw_val;
  135. LSTATUS status;
  136. wchar_t str[MAX_SZ_LEN];
  137. status = RegOpenKeyW(HKEY_LOCAL_MACHINE, WINVER_REG_KEY, &key);
  138. if (status != ERROR_SUCCESS)
  139. return;
  140. size = sizeof(dw_val);
  141. status = RegQueryValueExW(key, L"CurrentMajorVersionNumber", NULL, NULL, (LPBYTE)&dw_val, &size);
  142. if (status == ERROR_SUCCESS)
  143. ver->major = (int)dw_val;
  144. status = RegQueryValueExW(key, L"CurrentMinorVersionNumber", NULL, NULL, (LPBYTE)&dw_val, &size);
  145. if (status == ERROR_SUCCESS)
  146. ver->minor = (int)dw_val;
  147. status = RegQueryValueExW(key, L"UBR", NULL, NULL, (LPBYTE)&dw_val, &size);
  148. if (status == ERROR_SUCCESS)
  149. ver->revis = (int)dw_val;
  150. if (get_reg_sz(key, L"CurrentBuildNumber", str, sizeof(str))) {
  151. ver->build = wcstol(str, NULL, 10);
  152. }
  153. const wchar_t *release_key = ver->build > 19041 ? L"DisplayVersion" : L"ReleaseId";
  154. if (get_reg_sz(key, release_key, str, sizeof(str))) {
  155. os_wcs_to_utf8(str, 0, win_release_id, MAX_SZ_LEN);
  156. }
  157. RegCloseKey(key);
  158. }
  159. void system_info(GoLiveApi::Capabilities &capabilities)
  160. {
  161. char tmpstr[1024];
  162. capabilities.gpu = system_gpu_data();
  163. {
  164. auto &cpu_data = capabilities.cpu;
  165. cpu_data.physical_cores = os_get_physical_cores();
  166. cpu_data.logical_cores = os_get_logical_cores();
  167. DWORD processorSpeed;
  168. char *processorName;
  169. get_processor_info(&processorName, &processorSpeed);
  170. if (processorSpeed)
  171. cpu_data.speed = processorSpeed;
  172. if (processorName)
  173. cpu_data.name = processorName;
  174. bfree(processorName);
  175. }
  176. {
  177. auto &memory_data = capabilities.memory;
  178. memory_data.total = os_get_sys_total_size();
  179. memory_data.free = os_get_sys_free_size();
  180. }
  181. struct win_version_info ver;
  182. get_win_ver(&ver);
  183. get_reg_ver(&ver);
  184. // Gaming features
  185. capabilities.gaming_features = get_gaming_features_data(ver);
  186. {
  187. auto &system_data = capabilities.system;
  188. snprintf(tmpstr, sizeof(tmpstr), "%d.%d", ver.major, ver.minor);
  189. system_data.version = tmpstr;
  190. system_data.name = "Windows";
  191. system_data.build = ver.build;
  192. system_data.release = win_release_id;
  193. system_data.revision = ver.revis;
  194. system_data.bits = is_64_bit_windows() ? 64 : 32;
  195. system_data.arm = is_arm64_windows();
  196. system_data.armEmulation = os_get_emulation_status();
  197. }
  198. }