graphics-hook.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. #include <windows.h>
  2. #include <psapi.h>
  3. #include "graphics-hook.h"
  4. #include "../obfuscate.h"
  5. #include "../funchook.h"
  6. #define DEBUG_OUTPUT
  7. #ifdef DEBUG_OUTPUT
  8. #define DbgOut(x) OutputDebugStringA(x)
  9. #else
  10. #define DbgOut(x)
  11. #endif
  12. struct thread_data {
  13. CRITICAL_SECTION mutexes[NUM_BUFFERS];
  14. CRITICAL_SECTION data_mutex;
  15. void *volatile cur_data;
  16. uint8_t *shmem_textures[2];
  17. HANDLE copy_thread;
  18. HANDLE copy_event;
  19. HANDLE stop_event;
  20. volatile int cur_tex;
  21. unsigned int pitch;
  22. unsigned int cy;
  23. volatile bool locked_textures[NUM_BUFFERS];
  24. };
  25. ipc_pipe_client_t pipe = {0};
  26. HANDLE signal_restart = NULL;
  27. HANDLE signal_stop = NULL;
  28. HANDLE signal_ready = NULL;
  29. HANDLE signal_exit = NULL;
  30. HANDLE tex_mutexes[2] = {NULL, NULL};
  31. static HANDLE filemap_hook_info = NULL;
  32. static HINSTANCE dll_inst = NULL;
  33. static volatile bool stop_loop = false;
  34. static HANDLE capture_thread = NULL;
  35. char system_path[MAX_PATH] = {0};
  36. char process_name[MAX_PATH] = {0};
  37. char keepalive_name[64] = {0};
  38. HWND dummy_window = NULL;
  39. static unsigned int shmem_id_counter = 0;
  40. static void *shmem_info = NULL;
  41. static HANDLE shmem_file_handle = 0;
  42. static struct thread_data thread_data = {0};
  43. volatile bool active = false;
  44. struct hook_info *global_hook_info = NULL;
  45. static inline void wait_for_dll_main_finish(HANDLE thread_handle)
  46. {
  47. if (thread_handle) {
  48. WaitForSingleObject(thread_handle, 100);
  49. CloseHandle(thread_handle);
  50. }
  51. }
  52. bool init_pipe(void)
  53. {
  54. char new_name[64];
  55. sprintf(new_name, "%s%lu", PIPE_NAME, GetCurrentProcessId());
  56. if (!ipc_pipe_client_open(&pipe, new_name)) {
  57. DbgOut("Failed to open pipe\n");
  58. return false;
  59. }
  60. return true;
  61. }
  62. static HANDLE init_event(const char *name, DWORD pid)
  63. {
  64. HANDLE handle = get_event_plus_id(name, pid);
  65. if (!handle)
  66. hlog("Failed to get event '%s': %lu", name, GetLastError());
  67. return handle;
  68. }
  69. static HANDLE init_mutex(const char *name, DWORD pid)
  70. {
  71. char new_name[64];
  72. HANDLE handle;
  73. sprintf(new_name, "%s%lu", name, pid);
  74. handle = OpenMutexA(MUTEX_ALL_ACCESS, false, new_name);
  75. if (!handle)
  76. hlog("Failed to open mutex '%s': %lu", name, GetLastError());
  77. return handle;
  78. }
  79. static inline bool init_signals(void)
  80. {
  81. DWORD pid = GetCurrentProcessId();
  82. signal_restart = init_event(EVENT_CAPTURE_RESTART, pid);
  83. if (!signal_restart) {
  84. return false;
  85. }
  86. signal_stop = init_event(EVENT_CAPTURE_STOP, pid);
  87. if (!signal_stop) {
  88. return false;
  89. }
  90. signal_ready = init_event(EVENT_HOOK_READY, pid);
  91. if (!signal_ready) {
  92. return false;
  93. }
  94. signal_exit = init_event(EVENT_HOOK_EXIT, pid);
  95. if (!signal_exit) {
  96. return false;
  97. }
  98. return true;
  99. }
  100. static inline bool init_mutexes(void)
  101. {
  102. DWORD pid = GetCurrentProcessId();
  103. tex_mutexes[0] = init_mutex(MUTEX_TEXTURE1, pid);
  104. if (!tex_mutexes[0]) {
  105. return false;
  106. }
  107. tex_mutexes[1] = init_mutex(MUTEX_TEXTURE2, pid);
  108. if (!tex_mutexes[1]) {
  109. return false;
  110. }
  111. return true;
  112. }
  113. static inline bool init_system_path(void)
  114. {
  115. UINT ret = GetSystemDirectoryA(system_path, MAX_PATH);
  116. if (!ret) {
  117. hlog("Failed to get windows system path: %lu", GetLastError());
  118. return false;
  119. }
  120. return true;
  121. }
  122. static inline void log_current_process(void)
  123. {
  124. DWORD len = GetModuleBaseNameA(GetCurrentProcess(), NULL, process_name,
  125. MAX_PATH);
  126. if (len > 0) {
  127. process_name[len] = 0;
  128. hlog("Hooked to process: %s", process_name);
  129. }
  130. hlog("(half life scientist) everything.. seems to be in order");
  131. }
  132. static inline bool init_hook_info(void)
  133. {
  134. filemap_hook_info = get_hook_info(GetCurrentProcessId());
  135. if (!filemap_hook_info) {
  136. hlog("Failed to create hook info file mapping: %lu",
  137. GetLastError());
  138. return false;
  139. }
  140. global_hook_info = MapViewOfFile(filemap_hook_info, FILE_MAP_ALL_ACCESS,
  141. 0, 0, sizeof(struct hook_info));
  142. if (!global_hook_info) {
  143. hlog("Failed to map the hook info file mapping: %lu",
  144. GetLastError());
  145. return false;
  146. }
  147. return true;
  148. }
  149. #define DEF_FLAGS (WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
  150. static DWORD WINAPI dummy_window_thread(LPVOID *unused)
  151. {
  152. static const wchar_t dummy_window_class[] = L"temp_d3d_window_4039785";
  153. WNDCLASSW wc;
  154. MSG msg;
  155. memset(&wc, 0, sizeof(wc));
  156. wc.style = CS_OWNDC;
  157. wc.hInstance = dll_inst;
  158. wc.lpfnWndProc = (WNDPROC)DefWindowProc;
  159. wc.lpszClassName = dummy_window_class;
  160. if (!RegisterClass(&wc)) {
  161. hlog("Failed to create temp D3D window class: %lu",
  162. GetLastError());
  163. return 0;
  164. }
  165. dummy_window = CreateWindowExW(0, dummy_window_class, L"Temp Window",
  166. DEF_FLAGS, 0, 0, 1, 1, NULL, NULL, dll_inst, NULL);
  167. if (!dummy_window) {
  168. hlog("Failed to create temp D3D window: %lu", GetLastError());
  169. return 0;
  170. }
  171. while (GetMessage(&msg, NULL, 0, 0)) {
  172. TranslateMessage(&msg);
  173. DispatchMessage(&msg);
  174. }
  175. (void)unused;
  176. return 0;
  177. }
  178. static inline void init_dummy_window_thread(void)
  179. {
  180. HANDLE thread = CreateThread(NULL, 0, dummy_window_thread, NULL, 0,
  181. NULL);
  182. if (!thread) {
  183. hlog("Failed to create temp D3D window thread: %lu",
  184. GetLastError());
  185. return;
  186. }
  187. CloseHandle(thread);
  188. }
  189. static inline bool init_hook(HANDLE thread_handle)
  190. {
  191. wait_for_dll_main_finish(thread_handle);
  192. sprintf(keepalive_name, "%s%lu", EVENT_HOOK_KEEPALIVE,
  193. GetCurrentProcessId());
  194. if (!init_pipe()) {
  195. return false;
  196. }
  197. if (!init_signals()) {
  198. return false;
  199. }
  200. if (!init_mutexes()) {
  201. return false;
  202. }
  203. if (!init_system_path()) {
  204. return false;
  205. }
  206. if (!init_hook_info()) {
  207. return false;
  208. }
  209. init_dummy_window_thread();
  210. log_current_process();
  211. SetEvent(signal_restart);
  212. return true;
  213. }
  214. static inline void close_handle(HANDLE *handle)
  215. {
  216. if (*handle) {
  217. CloseHandle(*handle);
  218. *handle = NULL;
  219. }
  220. }
  221. static void free_hook(void)
  222. {
  223. if (filemap_hook_info) {
  224. CloseHandle(filemap_hook_info);
  225. filemap_hook_info = NULL;
  226. }
  227. if (global_hook_info) {
  228. UnmapViewOfFile(global_hook_info);
  229. global_hook_info = NULL;
  230. }
  231. close_handle(&tex_mutexes[1]);
  232. close_handle(&tex_mutexes[0]);
  233. close_handle(&signal_exit);
  234. close_handle(&signal_ready);
  235. close_handle(&signal_stop);
  236. close_handle(&signal_restart);
  237. ipc_pipe_client_free(&pipe);
  238. }
  239. static inline bool d3d8_hookable(void)
  240. {
  241. return !!global_hook_info->offsets.d3d8.present;
  242. }
  243. static inline bool ddraw_hookable(void)
  244. {
  245. return !!global_hook_info->offsets.ddraw.surface_create &&
  246. !!global_hook_info->offsets.ddraw.surface_restore &&
  247. !!global_hook_info->offsets.ddraw.surface_release &&
  248. !!global_hook_info->offsets.ddraw.surface_unlock &&
  249. !!global_hook_info->offsets.ddraw.surface_blt &&
  250. !!global_hook_info->offsets.ddraw.surface_flip &&
  251. !!global_hook_info->offsets.ddraw.surface_set_palette &&
  252. !!global_hook_info->offsets.ddraw.palette_set_entries;
  253. }
  254. static inline bool d3d9_hookable(void)
  255. {
  256. return !!global_hook_info->offsets.d3d9.present &&
  257. !!global_hook_info->offsets.d3d9.present_ex &&
  258. !!global_hook_info->offsets.d3d9.present_swap;
  259. }
  260. static inline bool dxgi_hookable(void)
  261. {
  262. return !!global_hook_info->offsets.dxgi.present &&
  263. !!global_hook_info->offsets.dxgi.resize;
  264. }
  265. static inline bool attempt_hook(void)
  266. {
  267. //static bool ddraw_hooked = false;
  268. static bool d3d8_hooked = false;
  269. static bool d3d9_hooked = false;
  270. static bool dxgi_hooked = false;
  271. static bool gl_hooked = false;
  272. if (!d3d9_hooked) {
  273. if (!d3d9_hookable()) {
  274. d3d9_hooked = true;
  275. } else {
  276. d3d9_hooked = hook_d3d9();
  277. if (d3d9_hooked) {
  278. return true;
  279. }
  280. }
  281. }
  282. if (!dxgi_hooked) {
  283. if (!dxgi_hookable()) {
  284. dxgi_hooked = true;
  285. } else {
  286. dxgi_hooked = hook_dxgi();
  287. if (dxgi_hooked) {
  288. return true;
  289. }
  290. }
  291. }
  292. if (!gl_hooked) {
  293. gl_hooked = hook_gl();
  294. if (gl_hooked) {
  295. return true;
  296. }
  297. /*} else {
  298. rehook_gl();*/
  299. }
  300. if (!d3d8_hooked) {
  301. if (!d3d8_hookable()) {
  302. d3d8_hooked = true;
  303. } else {
  304. d3d8_hooked = hook_d3d8();
  305. if (d3d8_hooked) {
  306. return true;
  307. }
  308. }
  309. }
  310. /*if (!ddraw_hooked) {
  311. if (!ddraw_hookable()) {
  312. ddraw_hooked = true;
  313. } else {
  314. ddraw_hooked = hook_ddraw();
  315. if (ddraw_hooked) {
  316. return true;
  317. }
  318. }
  319. }*/
  320. return false;
  321. }
  322. static inline void capture_loop(void)
  323. {
  324. while (!attempt_hook())
  325. Sleep(40);
  326. for (size_t n = 0; !stop_loop; n++) {
  327. /* this causes it to check every 4 seconds, but still with
  328. * a small sleep interval in case the thread needs to stop */
  329. if (n % 100 == 0) attempt_hook();
  330. Sleep(40);
  331. }
  332. }
  333. static DWORD WINAPI main_capture_thread(HANDLE thread_handle)
  334. {
  335. if (!init_hook(thread_handle)) {
  336. DbgOut("Failed to init hook\n");
  337. free_hook();
  338. return 0;
  339. }
  340. capture_loop();
  341. return 0;
  342. }
  343. static inline void hlogv(const char *format, va_list args)
  344. {
  345. char message[1024] = "";
  346. int num = _vsprintf_p(message, 1024, format, args);
  347. if (num) {
  348. if (!ipc_pipe_client_write(&pipe, message, num + 1)) {
  349. ipc_pipe_client_free(&pipe);
  350. }
  351. DbgOut(message);
  352. DbgOut("\n");
  353. }
  354. }
  355. void hlog(const char *format, ...)
  356. {
  357. va_list args;
  358. va_start(args, format);
  359. hlogv(format, args);
  360. va_end(args);
  361. }
  362. void hlog_hr(const char *text, HRESULT hr)
  363. {
  364. LPSTR buffer = NULL;
  365. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
  366. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  367. FORMAT_MESSAGE_IGNORE_INSERTS,
  368. NULL, hr, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  369. (LPSTR)&buffer, 0, NULL);
  370. if (buffer) {
  371. hlog("%s (0x%08lX): %s", text, hr, buffer);
  372. LocalFree(buffer);
  373. } else {
  374. hlog("%s (0x%08lX)", text, hr);
  375. }
  376. }
  377. static inline uint64_t get_clockfreq(void)
  378. {
  379. static bool have_clockfreq = false;
  380. static LARGE_INTEGER clock_freq;
  381. if (!have_clockfreq) {
  382. QueryPerformanceFrequency(&clock_freq);
  383. have_clockfreq = true;
  384. }
  385. return clock_freq.QuadPart;
  386. }
  387. uint64_t os_gettime_ns(void)
  388. {
  389. LARGE_INTEGER current_time;
  390. double time_val;
  391. QueryPerformanceCounter(&current_time);
  392. time_val = (double)current_time.QuadPart;
  393. time_val *= 1000000000.0;
  394. time_val /= (double)get_clockfreq();
  395. return (uint64_t)time_val;
  396. }
  397. static inline int try_lock_shmem_tex(int id)
  398. {
  399. int next = id == 0 ? 1 : 0;
  400. if (WaitForSingleObject(tex_mutexes[id], 0) == WAIT_OBJECT_0) {
  401. return id;
  402. } else if (WaitForSingleObject(tex_mutexes[next], 0) == WAIT_OBJECT_0) {
  403. return next;
  404. }
  405. return -1;
  406. }
  407. static inline void unlock_shmem_tex(int id)
  408. {
  409. if (id != -1) {
  410. ReleaseMutex(tex_mutexes[id]);
  411. }
  412. }
  413. static inline bool init_shared_info(size_t size)
  414. {
  415. char name[64];
  416. sprintf_s(name, 64, "%s%u", SHMEM_TEXTURE, ++shmem_id_counter);
  417. shmem_file_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL,
  418. PAGE_READWRITE, 0, (DWORD)size, name);
  419. if (!shmem_file_handle) {
  420. hlog("init_shared_info: Failed to create shared memory: %d",
  421. GetLastError());
  422. return false;
  423. }
  424. shmem_info = MapViewOfFile(shmem_file_handle, FILE_MAP_ALL_ACCESS,
  425. 0, 0, size);
  426. if (!shmem_info) {
  427. hlog("init_shared_info: Failed to map shared memory: %d",
  428. GetLastError());
  429. return false;
  430. }
  431. return true;
  432. }
  433. bool capture_init_shtex(struct shtex_data **data, HWND window,
  434. uint32_t base_cx, uint32_t base_cy, uint32_t cx, uint32_t cy,
  435. uint32_t format, bool flip, uintptr_t handle)
  436. {
  437. if (!init_shared_info(sizeof(struct shtex_data))) {
  438. hlog("capture_init_shtex: Failed to initialize memory");
  439. return false;
  440. }
  441. *data = shmem_info;
  442. (*data)->tex_handle = (uint32_t)handle;
  443. global_hook_info->window = (uint32_t)(uintptr_t)window;
  444. global_hook_info->type = CAPTURE_TYPE_TEXTURE;
  445. global_hook_info->format = format;
  446. global_hook_info->flip = flip;
  447. global_hook_info->map_id = shmem_id_counter;
  448. global_hook_info->map_size = sizeof(struct shtex_data);
  449. global_hook_info->cx = cx;
  450. global_hook_info->cy = cy;
  451. global_hook_info->base_cx = base_cx;
  452. global_hook_info->base_cy = base_cy;
  453. if (!SetEvent(signal_ready)) {
  454. hlog("capture_init_shtex: Failed to signal ready: %d",
  455. GetLastError());
  456. return false;
  457. }
  458. active = true;
  459. return true;
  460. }
  461. static DWORD CALLBACK copy_thread(LPVOID unused)
  462. {
  463. uint32_t pitch = thread_data.pitch;
  464. uint32_t cy = thread_data.cy;
  465. HANDLE events[2] = {NULL, NULL};
  466. int shmem_id = 0;
  467. if (!duplicate_handle(&events[0], thread_data.copy_event)) {
  468. hlog_hr("copy_thread: Failed to duplicate copy event: %d",
  469. GetLastError());
  470. return 0;
  471. }
  472. if (!duplicate_handle(&events[1], thread_data.stop_event)) {
  473. hlog_hr("copy_thread: Failed to duplicate stop event: %d",
  474. GetLastError());
  475. goto finish;
  476. }
  477. for (;;) {
  478. int copy_tex;
  479. void *cur_data;
  480. DWORD ret = WaitForMultipleObjects(2, events, false, INFINITE);
  481. if (ret != WAIT_OBJECT_0) {
  482. break;
  483. }
  484. EnterCriticalSection(&thread_data.data_mutex);
  485. copy_tex = thread_data.cur_tex;
  486. cur_data = thread_data.cur_data;
  487. LeaveCriticalSection(&thread_data.data_mutex);
  488. if (copy_tex < NUM_BUFFERS && !!cur_data) {
  489. EnterCriticalSection(&thread_data.mutexes[copy_tex]);
  490. int lock_id = try_lock_shmem_tex(shmem_id);
  491. if (lock_id != -1) {
  492. memcpy(thread_data.shmem_textures[lock_id],
  493. cur_data, pitch * cy);
  494. unlock_shmem_tex(lock_id);
  495. ((struct shmem_data*)shmem_info)->last_tex =
  496. lock_id;
  497. shmem_id = lock_id == 0 ? 1 : 0;
  498. }
  499. LeaveCriticalSection(&thread_data.mutexes[copy_tex]);
  500. }
  501. }
  502. finish:
  503. for (size_t i = 0; i < 2; i++) {
  504. if (events[i]) {
  505. CloseHandle(events[i]);
  506. }
  507. }
  508. (void)unused;
  509. return 0;
  510. }
  511. void shmem_copy_data(size_t idx, void *volatile data)
  512. {
  513. EnterCriticalSection(&thread_data.data_mutex);
  514. thread_data.cur_tex = (int)idx;
  515. thread_data.cur_data = data;
  516. thread_data.locked_textures[idx] = true;
  517. LeaveCriticalSection(&thread_data.data_mutex);
  518. SetEvent(thread_data.copy_event);
  519. }
  520. bool shmem_texture_data_lock(int idx)
  521. {
  522. bool locked;
  523. EnterCriticalSection(&thread_data.data_mutex);
  524. locked = thread_data.locked_textures[idx];
  525. LeaveCriticalSection(&thread_data.data_mutex);
  526. if (locked) {
  527. EnterCriticalSection(&thread_data.mutexes[idx]);
  528. return true;
  529. }
  530. return false;
  531. }
  532. void shmem_texture_data_unlock(int idx)
  533. {
  534. EnterCriticalSection(&thread_data.data_mutex);
  535. thread_data.locked_textures[idx] = false;
  536. LeaveCriticalSection(&thread_data.data_mutex);
  537. LeaveCriticalSection(&thread_data.mutexes[idx]);
  538. }
  539. static inline bool init_shmem_thread(uint32_t pitch, uint32_t cy)
  540. {
  541. struct shmem_data *data = shmem_info;
  542. thread_data.pitch = pitch;
  543. thread_data.cy = cy;
  544. thread_data.shmem_textures[0] = (uint8_t*)data + data->tex1_offset;
  545. thread_data.shmem_textures[1] = (uint8_t*)data + data->tex2_offset;
  546. thread_data.copy_event = CreateEvent(NULL, false, false, NULL);
  547. if (!thread_data.copy_event) {
  548. hlog("init_shmem_thread: Failed to create copy event: %d",
  549. GetLastError());
  550. return false;
  551. }
  552. thread_data.stop_event = CreateEvent(NULL, true, false, NULL);
  553. if (!thread_data.stop_event) {
  554. hlog("init_shmem_thread: Failed to create stop event: %d",
  555. GetLastError());
  556. return false;
  557. }
  558. for (size_t i = 0; i < NUM_BUFFERS; i++) {
  559. InitializeCriticalSection(&thread_data.mutexes[i]);
  560. }
  561. InitializeCriticalSection(&thread_data.data_mutex);
  562. thread_data.copy_thread = CreateThread(NULL, 0, copy_thread, NULL, 0,
  563. NULL);
  564. if (!thread_data.copy_thread) {
  565. hlog("init_shmem_thread: Failed to create thread: %d",
  566. GetLastError());
  567. return false;
  568. }
  569. return true;
  570. }
  571. #ifndef ALIGN
  572. #define ALIGN(bytes, align) (((bytes) + ((align) - 1)) & ~((align) - 1))
  573. #endif
  574. bool capture_init_shmem(struct shmem_data **data, HWND window,
  575. uint32_t base_cx, uint32_t base_cy, uint32_t cx, uint32_t cy,
  576. uint32_t pitch, uint32_t format, bool flip)
  577. {
  578. uint32_t tex_size = cy * pitch;
  579. uint32_t aligned_header = ALIGN(sizeof(struct shmem_data), 32);
  580. uint32_t aligned_tex = ALIGN(tex_size, 32);
  581. uint32_t total_size = aligned_header + aligned_tex * 2;
  582. uintptr_t align_pos;
  583. if (!init_shared_info(total_size)) {
  584. hlog("capture_init_shmem: Failed to initialize memory");
  585. return false;
  586. }
  587. *data = shmem_info;
  588. /* to ensure fast copy rate, align texture data to 256bit addresses */
  589. align_pos = (uintptr_t)shmem_info;
  590. align_pos += aligned_header;
  591. align_pos &= ~(32 - 1);
  592. align_pos -= (uintptr_t)shmem_info;
  593. (*data)->last_tex = -1;
  594. (*data)->tex1_offset = (uint32_t)align_pos;
  595. (*data)->tex2_offset = (*data)->tex1_offset + aligned_tex;
  596. global_hook_info->window = (uint32_t)(uintptr_t)window;
  597. global_hook_info->type = CAPTURE_TYPE_MEMORY;
  598. global_hook_info->format = format;
  599. global_hook_info->flip = flip;
  600. global_hook_info->map_id = shmem_id_counter;
  601. global_hook_info->map_size = total_size;
  602. global_hook_info->pitch = pitch;
  603. global_hook_info->cx = cx;
  604. global_hook_info->cy = cy;
  605. global_hook_info->base_cx = base_cx;
  606. global_hook_info->base_cy = base_cy;
  607. if (!init_shmem_thread(pitch, cy)) {
  608. return false;
  609. }
  610. if (!SetEvent(signal_ready)) {
  611. hlog("capture_init_shmem: Failed to signal ready: %d",
  612. GetLastError());
  613. return false;
  614. }
  615. active = true;
  616. return true;
  617. }
  618. static inline void thread_data_free(void)
  619. {
  620. if (thread_data.copy_thread) {
  621. DWORD ret;
  622. SetEvent(thread_data.stop_event);
  623. ret = WaitForSingleObject(thread_data.copy_thread, 500);
  624. if (ret != WAIT_OBJECT_0)
  625. TerminateThread(thread_data.copy_thread, (DWORD)-1);
  626. CloseHandle(thread_data.copy_thread);
  627. }
  628. if (thread_data.stop_event)
  629. CloseHandle(thread_data.stop_event);
  630. if (thread_data.copy_event)
  631. CloseHandle(thread_data.copy_event);
  632. for (size_t i = 0; i < NUM_BUFFERS; i++)
  633. DeleteCriticalSection(&thread_data.mutexes[i]);
  634. DeleteCriticalSection(&thread_data.data_mutex);
  635. memset(&thread_data, 0, sizeof(thread_data));
  636. }
  637. void capture_free(void)
  638. {
  639. thread_data_free();
  640. if (shmem_info) {
  641. UnmapViewOfFile(shmem_info);
  642. shmem_info = NULL;
  643. }
  644. close_handle(&shmem_file_handle);
  645. SetEvent(signal_restart);
  646. active = false;
  647. }
  648. BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID unused1)
  649. {
  650. if (reason == DLL_PROCESS_ATTACH) {
  651. wchar_t name[MAX_PATH];
  652. dll_inst = hinst;
  653. HANDLE cur_thread = OpenThread(THREAD_ALL_ACCESS, false,
  654. GetCurrentThreadId());
  655. /* this prevents the library from being automatically unloaded
  656. * by the next FreeLibrary call */
  657. GetModuleFileNameW(hinst, name, MAX_PATH);
  658. LoadLibraryW(name);
  659. capture_thread = CreateThread(NULL, 0,
  660. (LPTHREAD_START_ROUTINE)main_capture_thread,
  661. (LPVOID)cur_thread, 0, 0);
  662. if (!capture_thread) {
  663. CloseHandle(cur_thread);
  664. return false;
  665. }
  666. } else if (reason == DLL_PROCESS_DETACH) {
  667. if (capture_thread) {
  668. stop_loop = true;
  669. WaitForSingleObject(capture_thread, 300);
  670. CloseHandle(capture_thread);
  671. }
  672. free_hook();
  673. }
  674. (void)unused1;
  675. return true;
  676. }
  677. __declspec(dllexport) LRESULT CALLBACK dummy_debug_proc(int code,
  678. WPARAM wparam, LPARAM lparam)
  679. {
  680. static bool hooking = true;
  681. MSG *msg = (MSG*)lparam;
  682. if (hooking && msg->message == (WM_USER + 432)) {
  683. HMODULE user32 = GetModuleHandleW(L"USER32");
  684. BOOL (WINAPI *unhook_windows_hook_ex)(HHOOK) = NULL;
  685. unhook_windows_hook_ex = get_obfuscated_func(user32,
  686. "VojeleY`bdgxvM`hhDz",
  687. 0x7F55F80C9EE3A213ULL);
  688. if (unhook_windows_hook_ex)
  689. unhook_windows_hook_ex((HHOOK)msg->lParam);
  690. hooking = false;
  691. }
  692. return CallNextHookEx(0, code, wparam, lparam);
  693. }