diff --git a/plugins/win-capture/game-capture.c b/plugins/win-capture/game-capture.c index 9c7663763..6954c5057 100644 --- a/plugins/win-capture/game-capture.c +++ b/plugins/win-capture/game-capture.c @@ -133,7 +133,8 @@ struct game_capture { ipc_pipe_server_t pipe; gs_texture_t *texture; struct hook_info *global_hook_info; - HANDLE keep_alive; + HANDLE keepalive_thread; + DWORD keepalive_thread_id; HANDLE hook_restart; HANDLE hook_stop; HANDLE hook_ready; @@ -219,7 +220,12 @@ static void stop_capture(struct game_capture *gc) gc->data = NULL; } - close_handle(&gc->keep_alive); + if (gc->keepalive_thread) { + PostThreadMessage(gc->keepalive_thread_id, WM_QUIT, 0, 0); + WaitForSingleObject(gc->keepalive_thread, 300); + close_handle(&gc->keepalive_thread); + } + close_handle(&gc->hook_restart); close_handle(&gc->hook_stop); close_handle(&gc->hook_ready); @@ -473,14 +479,6 @@ static void *game_capture_create(obs_data_t *settings, obs_source_t *source) return gc; } -static inline HANDLE create_event_id(bool manual_reset, bool initial_state, - const char *name, DWORD process_id) -{ - char new_name[128]; - sprintf(new_name, "%s%lu", name, process_id); - return CreateEventA(NULL, manual_reset, initial_state, new_name); -} - static inline HANDLE open_event_id(const char *name, DWORD process_id) { char new_name[128]; @@ -573,15 +571,78 @@ static inline bool open_target_process(struct game_capture *gc) return true; } +struct keepalive_data { + struct game_capture *gc; + HANDLE initialized; +}; + +#define DEF_FLAGS (WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS) + +static DWORD WINAPI keepalive_window_thread(struct keepalive_data *data) +{ + HANDLE initialized = data->initialized; + struct game_capture *gc = data->gc; + wchar_t new_name[64]; + WNDCLASSW wc; + HWND window; + MSG msg; + + _snwprintf(new_name, sizeof(new_name), L"%s%lu", + WINDOW_HOOK_KEEPALIVE, gc->process_id); + + memset(&wc, 0, sizeof(wc)); + wc.style = CS_OWNDC; + wc.hInstance = GetModuleHandleW(NULL); + wc.lpfnWndProc = (WNDPROC)DefWindowProc; + wc.lpszClassName = new_name; + + if (!RegisterClass(&wc)) { + warn("Failed to create keepalive window class: %lu", + GetLastError()); + return 0; + } + + window = CreateWindowExW(0, new_name, NULL, DEF_FLAGS, 0, 0, 1, 1, + NULL, NULL, wc.hInstance, NULL); + if (!window) { + warn("Failed to create keepalive window: %lu", + GetLastError()); + return 0; + } + + SetEvent(initialized); + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + DestroyWindow(window); + UnregisterClassW(new_name, wc.hInstance); + + return 0; +} + static inline bool init_keepalive(struct game_capture *gc) { - gc->keep_alive = create_event_id(false, false, EVENT_HOOK_KEEPALIVE, - gc->process_id); - if (!gc->keep_alive) { - warn("failed to create keepalive event"); + struct keepalive_data data; + HANDLE initialized = CreateEvent(NULL, false, false, NULL); + + data.gc = gc; + data.initialized = initialized; + + gc->keepalive_thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE)keepalive_window_thread, + &data, 0, &gc->keepalive_thread_id); + if (!gc->keepalive_thread) { + warn("Failed to create keepalive window thread: %lu", + GetLastError()); return false; } + WaitForSingleObject(initialized, INFINITE); + CloseHandle(initialized); + return true; } diff --git a/plugins/win-capture/graphics-hook-info.h b/plugins/win-capture/graphics-hook-info.h index bb61482f7..fca302c4a 100644 --- a/plugins/win-capture/graphics-hook-info.h +++ b/plugins/win-capture/graphics-hook-info.h @@ -13,7 +13,7 @@ #define EVENT_HOOK_READY "CaptureHook_HookReady" #define EVENT_HOOK_EXIT "CaptureHook_Exit" -#define EVENT_HOOK_KEEPALIVE "CaptureHook_KeepAlive" +#define WINDOW_HOOK_KEEPALIVE L"CaptureHook_KeepAlive" #define MUTEX_TEXTURE1 "CaptureHook_TextureMutex1" #define MUTEX_TEXTURE2 "CaptureHook_TextureMutex2" diff --git a/plugins/win-capture/graphics-hook/graphics-hook.c b/plugins/win-capture/graphics-hook/graphics-hook.c index 1a5c017f8..acd943eca 100644 --- a/plugins/win-capture/graphics-hook/graphics-hook.c +++ b/plugins/win-capture/graphics-hook/graphics-hook.c @@ -39,7 +39,7 @@ static volatile bool stop_loop = false; static HANDLE capture_thread = NULL; char system_path[MAX_PATH] = {0}; char process_name[MAX_PATH] = {0}; -char keepalive_name[64] = {0}; +wchar_t keepalive_name[64] = {0}; HWND dummy_window = NULL; static unsigned int shmem_id_counter = 0; @@ -234,8 +234,8 @@ static inline bool init_hook(HANDLE thread_handle) { wait_for_dll_main_finish(thread_handle); - sprintf(keepalive_name, "%s%lu", EVENT_HOOK_KEEPALIVE, - GetCurrentProcessId()); + _snwprintf(keepalive_name, sizeof(keepalive_name), L"%s%lu", + WINDOW_HOOK_KEEPALIVE, GetCurrentProcessId()); init_pipe(); if (!init_signals()) { diff --git a/plugins/win-capture/graphics-hook/graphics-hook.h b/plugins/win-capture/graphics-hook/graphics-hook.h index 3bf58b653..c9cd6c6d4 100644 --- a/plugins/win-capture/graphics-hook/graphics-hook.h +++ b/plugins/win-capture/graphics-hook/graphics-hook.h @@ -98,7 +98,7 @@ extern HANDLE signal_exit; extern HANDLE tex_mutexes[2]; extern char system_path[MAX_PATH]; extern char process_name[MAX_PATH]; -extern char keepalive_name[64]; +extern wchar_t keepalive_name[64]; extern HWND dummy_window; extern volatile bool active; @@ -143,13 +143,7 @@ static inline HMODULE load_system_library(const char *name) static inline bool capture_alive(void) { - HANDLE event = OpenEventA(GC_EVENT_FLAGS, false, keepalive_name); - if (event) { - CloseHandle(event); - return true; - } - - return false; + return !!FindWindowW(keepalive_name, NULL); } static inline bool capture_active(void) @@ -198,8 +192,18 @@ static inline bool capture_should_stop(void) { bool stop_requested = false; - if (capture_active()) - stop_requested = capture_stopped() || !capture_alive(); + if (capture_active()) { + static uint64_t last_keepalive_check = 0; + uint64_t cur_time = os_gettime_ns(); + bool alive = true; + + if (cur_time - last_keepalive_check > 5000000000) { + alive = capture_alive(); + last_keepalive_check = cur_time; + } + + stop_requested = capture_stopped() || !alive; + } return stop_requested; }