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