Browse Source

win-capture: Use window for keepalive check

To check to make sure game capture is still active in the capture
program, it currently uses a named event, and then it checks to see if
that named event exists.  However with UWP programs, you can't open a
named event outside of the UWP process.  FindWindow on the other hand
does work, so instead of checking to see if a named kernel object
exists, create a window and check to see if that window exists.
jp9000 9 years ago
parent
commit
d19342442f

+ 75 - 14
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;
 }
 

+ 1 - 1
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"

+ 3 - 3
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()) {

+ 14 - 10
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;
 }