load-graphics-offsets.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include <obs-module.h>
  2. #include <util/windows/win-version.h>
  3. #include <util/platform.h>
  4. #include <util/dstr.h>
  5. #include <util/config-file.h>
  6. #include <util/pipe.h>
  7. #include <windows.h>
  8. #include "graphics-hook-info.h"
  9. extern struct graphics_offsets offsets32;
  10. extern struct graphics_offsets offsets64;
  11. static inline bool load_offsets_from_string(struct graphics_offsets *offsets, const char *str)
  12. {
  13. config_t *config;
  14. if (config_open_string(&config, str) != CONFIG_SUCCESS) {
  15. return false;
  16. }
  17. offsets->d3d8.present = (uint32_t)config_get_uint(config, "d3d8", "present");
  18. offsets->d3d9.present = (uint32_t)config_get_uint(config, "d3d9", "present");
  19. offsets->d3d9.present_ex = (uint32_t)config_get_uint(config, "d3d9", "present_ex");
  20. offsets->d3d9.present_swap = (uint32_t)config_get_uint(config, "d3d9", "present_swap");
  21. offsets->d3d9.d3d9_clsoff = (uint32_t)config_get_uint(config, "d3d9", "d3d9_clsoff");
  22. offsets->d3d9.is_d3d9ex_clsoff = (uint32_t)config_get_uint(config, "d3d9", "is_d3d9ex_clsoff");
  23. offsets->dxgi.present = (uint32_t)config_get_uint(config, "dxgi", "present");
  24. offsets->dxgi.present1 = (uint32_t)config_get_uint(config, "dxgi", "present1");
  25. offsets->dxgi.resize = (uint32_t)config_get_uint(config, "dxgi", "resize");
  26. offsets->dxgi2.release = (uint32_t)config_get_uint(config, "dxgi", "release");
  27. config_close(config);
  28. return true;
  29. }
  30. static inline bool load_offsets_from_file(struct graphics_offsets *offsets, const char *file)
  31. {
  32. char *str = os_quick_read_utf8_file(file);
  33. bool success = false;
  34. if (str && *str)
  35. success = load_offsets_from_string(offsets, str);
  36. bfree(str);
  37. return success;
  38. }
  39. static inline bool config_ver_mismatch(config_t *ver_config, const char *section, struct win_version_info *ver)
  40. {
  41. struct win_version_info config_ver;
  42. bool mismatch = false;
  43. #define get_sub_ver(subver) \
  44. config_ver.subver = (int)config_get_int(ver_config, section, #subver); \
  45. mismatch |= config_ver.subver != ver->subver;
  46. get_sub_ver(major);
  47. get_sub_ver(minor);
  48. get_sub_ver(build);
  49. get_sub_ver(revis);
  50. #undef get_sub_ver
  51. return mismatch;
  52. }
  53. static inline void write_config_ver(config_t *ver_config, const char *section, struct win_version_info *ver)
  54. {
  55. #define set_sub_ver(subver) config_set_int(ver_config, section, #subver, ver->subver);
  56. set_sub_ver(major);
  57. set_sub_ver(minor);
  58. set_sub_ver(build);
  59. set_sub_ver(revis);
  60. #undef set_sub_ver
  61. }
  62. static bool get_32bit_system_dll_ver(const wchar_t *system_lib, struct win_version_info *ver)
  63. {
  64. wchar_t path[MAX_PATH];
  65. UINT ret;
  66. #ifdef _WIN64
  67. ret = GetSystemWow64DirectoryW(path, MAX_PATH);
  68. #else
  69. ret = GetSystemDirectoryW(path, MAX_PATH);
  70. #endif
  71. if (!ret) {
  72. blog(LOG_ERROR,
  73. "Failed to get windows 32bit system path: "
  74. "%lu",
  75. GetLastError());
  76. return false;
  77. }
  78. wcscat(path, L"\\");
  79. wcscat(path, system_lib);
  80. return get_dll_ver(path, ver);
  81. }
  82. bool cached_versions_match(void)
  83. {
  84. struct win_version_info d3d8_ver = {0};
  85. struct win_version_info d3d9_ver = {0};
  86. struct win_version_info dxgi_ver = {0};
  87. bool ver_mismatch = false;
  88. config_t *config;
  89. char *ver_file;
  90. int ret;
  91. ver_mismatch |= !get_32bit_system_dll_ver(L"d3d8.dll", &d3d8_ver);
  92. ver_mismatch |= !get_32bit_system_dll_ver(L"d3d9.dll", &d3d9_ver);
  93. ver_mismatch |= !get_32bit_system_dll_ver(L"dxgi.dll", &dxgi_ver);
  94. ver_file = obs_module_config_path("version.ini");
  95. if (!ver_file)
  96. return false;
  97. ret = config_open(&config, ver_file, CONFIG_OPEN_ALWAYS);
  98. if (ret != CONFIG_SUCCESS)
  99. goto failed;
  100. ver_mismatch |= config_ver_mismatch(config, "d3d8", &d3d8_ver);
  101. ver_mismatch |= config_ver_mismatch(config, "d3d9", &d3d9_ver);
  102. ver_mismatch |= config_ver_mismatch(config, "dxgi", &dxgi_ver);
  103. if (ver_mismatch) {
  104. write_config_ver(config, "d3d8", &d3d8_ver);
  105. write_config_ver(config, "d3d9", &d3d9_ver);
  106. write_config_ver(config, "dxgi", &dxgi_ver);
  107. config_save_safe(config, "tmp", NULL);
  108. }
  109. failed:
  110. bfree(ver_file);
  111. config_close(config);
  112. return !ver_mismatch;
  113. }
  114. bool load_graphics_offsets(bool is32bit, bool use_hook_address_cache, const char *config_path)
  115. {
  116. char *offset_exe_path = NULL;
  117. struct dstr config_ini = {0};
  118. struct dstr offset_exe = {0};
  119. struct dstr str = {0};
  120. struct dstr cmd = {0};
  121. os_process_pipe_t *pp;
  122. bool success = false;
  123. char data[2048];
  124. #ifndef _WIN64
  125. if (!is32bit && !is_64_bit_windows()) {
  126. return true;
  127. }
  128. #endif
  129. dstr_copy(&offset_exe, "get-graphics-offsets");
  130. dstr_cat(&offset_exe, is32bit ? "32.exe" : "64.exe");
  131. offset_exe_path = obs_module_file(offset_exe.array);
  132. dstr_init_move_array(&cmd, offset_exe_path);
  133. dstr_insert_ch(&cmd, 0, '\"');
  134. dstr_cat(&cmd, "\"");
  135. pp = os_process_pipe_create(cmd.array, "r");
  136. if (!pp) {
  137. blog(LOG_INFO, "load_graphics_offsets: Failed to start '%s'", offset_exe.array);
  138. goto error;
  139. }
  140. for (;;) {
  141. size_t len = os_process_pipe_read(pp, (uint8_t *)data, sizeof(data));
  142. if (!len)
  143. break;
  144. dstr_ncat(&str, data, len);
  145. }
  146. if (dstr_is_empty(&str)) {
  147. blog(LOG_INFO,
  148. "load_graphics_offsets: Failed to read "
  149. "from '%s'",
  150. offset_exe.array);
  151. goto error;
  152. }
  153. if (use_hook_address_cache) {
  154. dstr_copy(&config_ini, config_path);
  155. dstr_cat(&config_ini, is32bit ? "32.ini" : "64.ini");
  156. os_quick_write_utf8_file_safe(config_ini.array, str.array, str.len, false, "tmp", NULL);
  157. dstr_free(&config_ini);
  158. }
  159. success = load_offsets_from_string(is32bit ? &offsets32 : &offsets64, str.array);
  160. if (!success) {
  161. blog(LOG_INFO, "load_graphics_offsets: Failed to load string");
  162. }
  163. os_process_pipe_destroy(pp);
  164. error:
  165. dstr_free(&offset_exe);
  166. dstr_free(&str);
  167. dstr_free(&cmd);
  168. return success;
  169. }
  170. bool load_cached_graphics_offsets(bool is32bit, const char *config_path)
  171. {
  172. struct dstr config_ini = {0};
  173. bool success;
  174. dstr_copy(&config_ini, config_path);
  175. dstr_cat(&config_ini, is32bit ? "32.ini" : "64.ini");
  176. success = load_offsets_from_file(is32bit ? &offsets32 : &offsets64, config_ini.array);
  177. if (!success)
  178. success = load_graphics_offsets(is32bit, true, config_path);
  179. dstr_free(&config_ini);
  180. return success;
  181. }