Переглянути джерело

graphics-hook: Use Detours for function hooking

Helped D3D12 path recover from window mode changes, so we assume it
should be more stable across the board for all API hooks.
jpark37 4 роки тому
батько
коміт
452ee646e1

+ 33 - 27
plugins/win-capture/graphics-hook/d3d8-capture.cpp

@@ -2,7 +2,8 @@
 
 #include "../d3d8-api/d3d8.h"
 #include "graphics-hook.h"
-#include "../funchook.h"
+
+#include <detours.h>
 
 typedef HRESULT(STDMETHODCALLTYPE *reset_t)(IDirect3DDevice8 *,
 					    D3DPRESENT_PARAMETERS *);
@@ -10,8 +11,8 @@ typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDirect3DDevice8 *, CONST RECT *,
 					      CONST RECT *, HWND,
 					      CONST RGNDATA *);
 
-static struct func_hook present;
-static struct func_hook reset;
+reset_t RealReset = NULL;
+present_t RealPresent = NULL;
 
 struct d3d8_data {
 	HMODULE d3d8;
@@ -250,17 +251,10 @@ static void d3d8_capture(IDirect3DDevice8 *device,
 static HRESULT STDMETHODCALLTYPE hook_reset(IDirect3DDevice8 *device,
 					    D3DPRESENT_PARAMETERS *parameters)
 {
-	HRESULT hr;
-
 	if (capture_active())
 		d3d8_free();
 
-	unhook(&reset);
-	reset_t call = (reset_t)reset.call_addr;
-	hr = call(device, parameters);
-	rehook(&reset);
-
-	return hr;
+	return RealReset(device, parameters);
 }
 
 static bool hooked_reset = false;
@@ -269,11 +263,19 @@ static void setup_reset_hooks(IDirect3DDevice8 *device)
 {
 	uintptr_t *vtable = *(uintptr_t **)device;
 
-	hook_init(&reset, (void *)vtable[14], (void *)hook_reset,
-		  "IDirect3DDevice8::Reset");
-	rehook(&reset);
+	DetourTransactionBegin();
 
-	hooked_reset = true;
+	RealReset = (reset_t)vtable[14];
+	DetourAttach((PVOID *)&RealReset, hook_reset);
+
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDirect3DDevice8::Reset");
+		hooked_reset = true;
+	} else {
+		RealReset = nullptr;
+	}
 }
 
 static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device,
@@ -283,7 +285,6 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device,
 					      CONST RGNDATA *dirty_region)
 {
 	IDirect3DSurface8 *backbuffer;
-	HRESULT hr;
 
 	if (!hooked_reset)
 		setup_reset_hooks(device);
@@ -294,12 +295,8 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device,
 		backbuffer->Release();
 	}
 
-	unhook(&present);
-	present_t call = (present_t)present.call_addr;
-	hr = call(device, src_rect, dst_rect, override_window, dirty_region);
-	rehook(&present);
-
-	return hr;
+	return RealPresent(device, src_rect, dst_rect, override_window,
+			   dirty_region);
 }
 
 typedef IDirect3D8 *(WINAPI *d3d8create_t)(UINT);
@@ -388,11 +385,20 @@ bool hook_d3d8(void)
 		return true;
 	}
 
-	hook_init(&present, present_addr, (void *)hook_present,
-		  "IDirect3DDevice8::Present");
+	DetourTransactionBegin();
 
-	rehook(&present);
+	RealPresent = (present_t)present_addr;
+	DetourAttach((PVOID *)&RealPresent, hook_present);
 
-	hlog("Hooked D3D8");
-	return true;
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDirect3DDevice8::Present");
+		hlog("Hooked D3D8");
+	} else {
+		RealPresent = nullptr;
+		hlog("Failed to attach Detours hook: %ld", error);
+	}
+
+	return success;
 }

+ 67 - 66
plugins/win-capture/graphics-hook/d3d9-capture.cpp

@@ -3,13 +3,14 @@
 #include <dxgi.h>
 
 #include "graphics-hook.h"
-#include "../funchook.h"
 #include "d3d9-patches.hpp"
 
+#include <detours.h>
+
 typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDirect3DDevice9 *, CONST RECT *,
 					      CONST RECT *, HWND,
 					      CONST RGNDATA *);
-typedef HRESULT(STDMETHODCALLTYPE *present_ex_t)(IDirect3DDevice9 *,
+typedef HRESULT(STDMETHODCALLTYPE *present_ex_t)(IDirect3DDevice9Ex *,
 						 CONST RECT *, CONST RECT *,
 						 HWND, CONST RGNDATA *, DWORD);
 typedef HRESULT(STDMETHODCALLTYPE *present_swap_t)(IDirect3DSwapChain9 *,
@@ -24,11 +25,11 @@ typedef HRESULT(STDMETHODCALLTYPE *reset_ex_t)(IDirect3DDevice9 *,
 
 typedef HRESULT(WINAPI *createfactory1_t)(REFIID, void **);
 
-static struct func_hook present;
-static struct func_hook present_ex;
-static struct func_hook present_swap;
-static struct func_hook reset;
-static struct func_hook reset_ex;
+present_t RealPresent = NULL;
+present_ex_t RealPresentEx = NULL;
+present_swap_t RealPresentSwap = NULL;
+reset_t RealReset = NULL;
+reset_ex_t RealResetEx = NULL;
 
 struct d3d9_data {
 	HMODULE d3d9;
@@ -641,17 +642,14 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice9 *device,
 					      CONST RGNDATA *dirty_region)
 {
 	IDirect3DSurface9 *backbuffer = nullptr;
-	HRESULT hr;
 
 	if (!hooked_reset)
 		setup_reset_hooks(device);
 
 	present_begin(device, backbuffer);
 
-	unhook(&present);
-	present_t call = (present_t)present.call_addr;
-	hr = call(device, src_rect, dst_rect, override_window, dirty_region);
-	rehook(&present);
+	const HRESULT hr = RealPresent(device, src_rect, dst_rect,
+				       override_window, dirty_region);
 
 	present_end(device, backbuffer);
 
@@ -659,22 +657,18 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice9 *device,
 }
 
 static HRESULT STDMETHODCALLTYPE hook_present_ex(
-	IDirect3DDevice9 *device, CONST RECT *src_rect, CONST RECT *dst_rect,
+	IDirect3DDevice9Ex *device, CONST RECT *src_rect, CONST RECT *dst_rect,
 	HWND override_window, CONST RGNDATA *dirty_region, DWORD flags)
 {
 	IDirect3DSurface9 *backbuffer = nullptr;
-	HRESULT hr;
 
 	if (!hooked_reset)
 		setup_reset_hooks(device);
 
 	present_begin(device, backbuffer);
 
-	unhook(&present_ex);
-	present_ex_t call = (present_ex_t)present_ex.call_addr;
-	hr = call(device, src_rect, dst_rect, override_window, dirty_region,
-		  flags);
-	rehook(&present_ex);
+	const HRESULT hr = RealPresentEx(device, src_rect, dst_rect,
+					 override_window, dirty_region, flags);
 
 	present_end(device, backbuffer);
 
@@ -687,12 +681,11 @@ static HRESULT STDMETHODCALLTYPE hook_present_swap(
 {
 	IDirect3DSurface9 *backbuffer = nullptr;
 	IDirect3DDevice9 *device = nullptr;
-	HRESULT hr;
 
 	if (!present_recurse) {
-		hr = swap->GetDevice(&device);
-		if (SUCCEEDED(hr)) {
-			device->Release();
+		IDirect3DDevice9 *temp;
+		if (SUCCEEDED(swap->GetDevice(&temp))) {
+			device = temp;
 		}
 	}
 
@@ -703,14 +696,13 @@ static HRESULT STDMETHODCALLTYPE hook_present_swap(
 		present_begin(device, backbuffer);
 	}
 
-	unhook(&present_swap);
-	present_swap_t call = (present_swap_t)present_swap.call_addr;
-	hr = call(swap, src_rect, dst_rect, override_window, dirty_region,
-		  flags);
-	rehook(&present_swap);
+	const HRESULT hr = RealPresentSwap(
+		swap, src_rect, dst_rect, override_window, dirty_region, flags);
 
-	if (device)
+	if (device) {
 		present_end(device, backbuffer);
+		device->Release();
+	}
 
 	return hr;
 }
@@ -718,34 +710,20 @@ static HRESULT STDMETHODCALLTYPE hook_present_swap(
 static HRESULT STDMETHODCALLTYPE hook_reset(IDirect3DDevice9 *device,
 					    D3DPRESENT_PARAMETERS *params)
 {
-	HRESULT hr;
-
 	if (capture_active())
 		d3d9_free();
 
-	unhook(&reset);
-	reset_t call = (reset_t)reset.call_addr;
-	hr = call(device, params);
-	rehook(&reset);
-
-	return hr;
+	return RealReset(device, params);
 }
 
 static HRESULT STDMETHODCALLTYPE hook_reset_ex(IDirect3DDevice9 *device,
 					       D3DPRESENT_PARAMETERS *params,
 					       D3DDISPLAYMODEEX *dmex)
 {
-	HRESULT hr;
-
 	if (capture_active())
 		d3d9_free();
 
-	unhook(&reset_ex);
-	reset_ex_t call = (reset_ex_t)reset_ex.call_addr;
-	hr = call(device, params, dmex);
-	rehook(&reset_ex);
-
-	return hr;
+	return RealResetEx(device, params, dmex);
 }
 
 static void setup_reset_hooks(IDirect3DDevice9 *device)
@@ -754,21 +732,30 @@ static void setup_reset_hooks(IDirect3DDevice9 *device)
 	uintptr_t *vtable = *(uintptr_t **)device;
 	HRESULT hr;
 
-	hook_init(&reset, (void *)vtable[16], (void *)hook_reset,
-		  "IDirect3DDevice9::Reset");
-	rehook(&reset);
+	DetourTransactionBegin();
 
-	hr = device->QueryInterface(__uuidof(IDirect3DDevice9Ex),
-				    (void **)&d3d9ex);
+	RealReset = (reset_t)vtable[16];
+	DetourAttach((PVOID *)&RealReset, hook_reset);
+
+	hr = device->QueryInterface(IID_PPV_ARGS(&d3d9ex));
 	if (SUCCEEDED(hr)) {
-		hook_init(&reset_ex, (void *)vtable[132], (void *)hook_reset_ex,
-			  "IDirect3DDevice9Ex::ResetEx");
-		rehook(&reset_ex);
+		RealResetEx = (reset_ex_t)vtable[132];
+		DetourAttach((PVOID *)&RealResetEx, hook_reset_ex);
 
 		d3d9ex->Release();
 	}
 
-	hooked_reset = true;
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDirect3DDevice9::Reset");
+		if (RealResetEx)
+			hlog("Hooked IDirect3DDevice9Ex::ResetEx");
+		hooked_reset = true;
+	} else {
+		RealReset = nullptr;
+		RealResetEx = nullptr;
+	}
 }
 
 typedef HRESULT(WINAPI *d3d9create_ex_t)(UINT, IDirect3D9Ex **);
@@ -878,23 +865,37 @@ bool hook_d3d9(void)
 		return true;
 	}
 
+	DetourTransactionBegin();
+
 	if (present_swap_addr) {
-		hook_init(&present_swap, present_swap_addr,
-			  (void *)hook_present_swap,
-			  "IDirect3DSwapChain9::Present");
-		rehook(&present_swap);
+		RealPresentSwap = (present_swap_t)present_swap_addr;
+		DetourAttach((PVOID *)&RealPresentSwap, hook_present_swap);
 	}
 	if (present_ex_addr) {
-		hook_init(&present_ex, present_ex_addr, (void *)hook_present_ex,
-			  "IDirect3DDevice9Ex::PresentEx");
-		rehook(&present_ex);
+		RealPresentEx = (present_ex_t)present_ex_addr;
+		DetourAttach((PVOID *)&RealPresentEx, hook_present_ex);
 	}
 	if (present_addr) {
-		hook_init(&present, present_addr, (void *)hook_present,
-			  "IDirect3DDevice9::Present");
-		rehook(&present);
+		RealPresent = (present_t)present_addr;
+		DetourAttach((PVOID *)&RealPresent, hook_present);
+	}
+
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		if (RealPresentSwap)
+			hlog("Hooked IDirect3DSwapChain9::Present");
+		if (RealPresentEx)
+			hlog("Hooked IDirect3DDevice9Ex::PresentEx");
+		if (RealPresent)
+			hlog("Hooked IDirect3DDevice9::Present");
+		hlog("Hooked D3D9");
+	} else {
+		RealPresentSwap = nullptr;
+		RealPresentEx = nullptr;
+		RealPresent = nullptr;
+		hlog("Failed to attach Detours hook: %ld", error);
 	}
 
-	hlog("Hooked D3D9");
-	return true;
+	return success;
 }

+ 42 - 42
plugins/win-capture/graphics-hook/dxgi-capture.cpp

@@ -5,7 +5,8 @@
 #include <inttypes.h>
 
 #include "graphics-hook.h"
-#include "../funchook.h"
+
+#include <detours.h>
 
 #if COMPILE_D3D12_HOOK
 #include <d3d12.h>
@@ -19,10 +20,10 @@ typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDXGISwapChain *, UINT, UINT);
 typedef HRESULT(STDMETHODCALLTYPE *present1_t)(IDXGISwapChain1 *, UINT, UINT,
 					       const DXGI_PRESENT_PARAMETERS *);
 
-static struct func_hook release;
-static struct func_hook resize_buffers;
-static struct func_hook present;
-static struct func_hook present1;
+release_t RealRelease = nullptr;
+resize_buffers_t RealResizeBuffers = nullptr;
+present_t RealPresent = nullptr;
+present1_t RealPresent1 = nullptr;
 
 thread_local bool dxgi_presenting = false;
 struct ID3D12CommandQueue *dxgi_possible_swap_queues[8]{};
@@ -112,10 +113,7 @@ static bool setup_dxgi(IDXGISwapChain *swap)
 
 static ULONG STDMETHODCALLTYPE hook_release(IUnknown *unknown)
 {
-	unhook(&release);
-	release_t call = (release_t)release.call_addr;
-	ULONG refs = call(unknown);
-	rehook(&release);
+	const ULONG refs = RealRelease(unknown);
 
 	hlog_verbose("Release callback: Refs=%lu", refs);
 	if (unknown == data.swap && refs == 0) {
@@ -155,11 +153,8 @@ static HRESULT STDMETHODCALLTYPE hook_resize_buffers(IDXGISwapChain *swap,
 		data.free();
 	data.free = nullptr;
 
-	unhook(&resize_buffers);
-	resize_buffers_t call = (resize_buffers_t)resize_buffers.call_addr;
-	const HRESULT hr =
-		call(swap, buffer_count, width, height, format, flags);
-	rehook(&resize_buffers);
+	const HRESULT hr = RealResizeBuffers(swap, buffer_count, width, height,
+					     format, flags);
 
 	resize_buffers_called = true;
 
@@ -229,10 +224,7 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap,
 	}
 
 	dxgi_presenting = true;
-	unhook(&present);
-	present_t call = (present_t)present.call_addr;
-	const HRESULT hr = call(swap, sync_interval, flags);
-	rehook(&present);
+	const HRESULT hr = RealPresent(swap, sync_interval, flags);
 	dxgi_presenting = false;
 	dxgi_present_attempted = true;
 
@@ -291,10 +283,7 @@ hook_present1(IDXGISwapChain1 *swap, UINT sync_interval, UINT flags,
 	}
 
 	dxgi_presenting = true;
-	unhook(&present1);
-	present1_t call = (present1_t)present1.call_addr;
-	const HRESULT hr = call(swap, sync_interval, flags, params);
-	rehook(&present1);
+	const HRESULT hr = RealPresent1(swap, sync_interval, flags, params);
 	dxgi_presenting = false;
 	dxgi_present_attempted = true;
 
@@ -337,30 +326,41 @@ bool hook_dxgi(void)
 		release_addr = get_offset_addr(
 			dxgi_module, global_hook_info->offsets.dxgi2.release);
 
-	hook_init(&present, present_addr, (void *)hook_present,
-		  "IDXGISwapChain::Present");
-	hlog("Hooked IDXGISwapChain::Present");
-	hook_init(&resize_buffers, resize_addr, (void *)hook_resize_buffers,
-		  "IDXGISwapChain::ResizeBuffers");
-	hlog("Hooked IDXGISwapChain::ResizeBuffers");
+	DetourTransactionBegin();
+
+	RealPresent = (present_t)present_addr;
+	DetourAttach(&(PVOID &)RealPresent, hook_present);
+
+	RealResizeBuffers = (resize_buffers_t)resize_addr;
+	DetourAttach(&(PVOID &)RealResizeBuffers, hook_resize_buffers);
+
 	if (present1_addr) {
-		hook_init(&present1, present1_addr, (void *)hook_present1,
-			  "IDXGISwapChain1::Present1");
-		hlog("Hooked IDXGISwapChain::Present1");
+		RealPresent1 = (present1_t)present1_addr;
+		DetourAttach(&(PVOID &)RealPresent1, hook_present1);
 	}
+
 	if (release_addr) {
-		hook_init(&release, release_addr, (void *)hook_release,
-			  "IDXGISwapChain::Release");
-		hlog("Hooked IDXGISwapChain::Release");
+		RealRelease = (release_t)release_addr;
+		DetourAttach(&(PVOID &)RealRelease, hook_release);
 	}
 
-	rehook(&resize_buffers);
-	rehook(&present);
-	if (present1_addr)
-		rehook(&present1);
-	if (release_addr)
-		rehook(&release);
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDXGISwapChain::Present");
+		hlog("Hooked IDXGISwapChain::ResizeBuffers");
+		if (RealPresent1)
+			hlog("Hooked IDXGISwapChain1::Present1");
+		if (RealRelease)
+			hlog("Hooked IDXGISwapChain::Release");
+		hlog("Hooked DXGI");
+	} else {
+		RealPresent = nullptr;
+		RealResizeBuffers = nullptr;
+		RealPresent1 = nullptr;
+		RealRelease = nullptr;
+		hlog("Failed to attach Detours hook: %ld", error);
+	}
 
-	hlog("Hooked DXGI");
-	return true;
+	return success;
 }

+ 48 - 44
plugins/win-capture/graphics-hook/gl-capture.c

@@ -11,7 +11,8 @@
 
 #include "gl-decs.h"
 #include "graphics-hook.h"
-#include "../funchook.h"
+
+#include <detours.h>
 
 #define DUMMY_WINDOW_CLASS_NAME L"graphics_hook_gl_dummy_window"
 
@@ -24,10 +25,15 @@ static const GUID GUID_IDXGIResource =
 
 /* clang-format on */
 
-static struct func_hook swap_buffers;
-static struct func_hook wgl_swap_layer_buffers;
-static struct func_hook wgl_swap_buffers;
-static struct func_hook wgl_delete_context;
+typedef BOOL(WINAPI *PFN_SwapBuffers)(HDC);
+typedef BOOL(WINAPI *PFN_WglSwapLayerBuffers)(HDC, UINT);
+typedef BOOL(WINAPI *PFN_WglSwapBuffers)(HDC);
+typedef BOOL(WINAPI *PFN_WglDeleteContext)(HGLRC);
+
+PFN_SwapBuffers RealSwapBuffers = NULL;
+PFN_WglSwapLayerBuffers RealWglSwapLayerBuffers = NULL;
+PFN_WglSwapBuffers RealWglSwapBuffers = NULL;
+PFN_WglDeleteContext RealWglDeleteContext = NULL;
 
 static bool darkest_dungeon_fix = false;
 static bool functions_initialized = false;
@@ -780,14 +786,9 @@ static inline void gl_swap_end(HDC hdc)
 
 static BOOL WINAPI hook_swap_buffers(HDC hdc)
 {
-	BOOL ret;
-
 	gl_swap_begin(hdc);
 
-	unhook(&swap_buffers);
-	BOOL(WINAPI * call)(HDC) = swap_buffers.call_addr;
-	ret = call(hdc);
-	rehook(&swap_buffers);
+	const BOOL ret = RealSwapBuffers(hdc);
 
 	gl_swap_end(hdc);
 
@@ -796,14 +797,9 @@ static BOOL WINAPI hook_swap_buffers(HDC hdc)
 
 static BOOL WINAPI hook_wgl_swap_buffers(HDC hdc)
 {
-	BOOL ret;
-
 	gl_swap_begin(hdc);
 
-	unhook(&wgl_swap_buffers);
-	BOOL(WINAPI * call)(HDC) = wgl_swap_buffers.call_addr;
-	ret = call(hdc);
-	rehook(&wgl_swap_buffers);
+	const BOOL ret = RealWglSwapBuffers(hdc);
 
 	gl_swap_end(hdc);
 
@@ -812,14 +808,9 @@ static BOOL WINAPI hook_wgl_swap_buffers(HDC hdc)
 
 static BOOL WINAPI hook_wgl_swap_layer_buffers(HDC hdc, UINT planes)
 {
-	BOOL ret;
-
 	gl_swap_begin(hdc);
 
-	unhook(&wgl_swap_layer_buffers);
-	BOOL(WINAPI * call)(HDC, UINT) = wgl_swap_layer_buffers.call_addr;
-	ret = call(hdc, planes);
-	rehook(&wgl_swap_layer_buffers);
+	const BOOL ret = RealWglSwapLayerBuffers(hdc, planes);
 
 	gl_swap_end(hdc);
 
@@ -828,8 +819,6 @@ static BOOL WINAPI hook_wgl_swap_layer_buffers(HDC hdc, UINT planes)
 
 static BOOL WINAPI hook_wgl_delete_context(HGLRC hrc)
 {
-	BOOL ret;
-
 	if (capture_active() && functions_initialized) {
 		HDC last_hdc = jimglGetCurrentDC();
 		HGLRC last_hrc = jimglGetCurrentContext();
@@ -839,12 +828,7 @@ static BOOL WINAPI hook_wgl_delete_context(HGLRC hrc)
 		jimglMakeCurrent(last_hdc, last_hrc);
 	}
 
-	unhook(&wgl_delete_context);
-	BOOL(WINAPI * call)(HGLRC) = wgl_delete_context.call_addr;
-	ret = call(hrc);
-	rehook(&wgl_delete_context);
-
-	return ret;
+	return RealWglDeleteContext(hrc);
 }
 
 static bool gl_register_window(void)
@@ -892,24 +876,44 @@ bool hook_gl(void)
 	wgl_slb_proc = base_get_proc("wglSwapLayerBuffers");
 	wgl_sb_proc = base_get_proc("wglSwapBuffers");
 
-	hook_init(&swap_buffers, SwapBuffers, hook_swap_buffers, "SwapBuffers");
+	DetourTransactionBegin();
+
+	RealSwapBuffers = SwapBuffers;
+	DetourAttach((PVOID *)&RealSwapBuffers, hook_swap_buffers);
 	if (wgl_dc_proc) {
-		hook_init(&wgl_delete_context, wgl_dc_proc,
-			  hook_wgl_delete_context, "wglDeleteContext");
-		rehook(&wgl_delete_context);
+		RealWglDeleteContext = (PFN_WglDeleteContext)wgl_dc_proc;
+		DetourAttach((PVOID *)&RealWglDeleteContext,
+			     hook_wgl_delete_context);
 	}
 	if (wgl_slb_proc) {
-		hook_init(&wgl_swap_layer_buffers, wgl_slb_proc,
-			  hook_wgl_swap_layer_buffers, "wglSwapLayerBuffers");
-		rehook(&wgl_swap_layer_buffers);
+		RealWglSwapLayerBuffers = (PFN_WglSwapLayerBuffers)wgl_slb_proc;
+		DetourAttach((PVOID *)&RealWglSwapLayerBuffers,
+			     hook_wgl_swap_layer_buffers);
 	}
 	if (wgl_sb_proc) {
-		hook_init(&wgl_swap_buffers, wgl_sb_proc, hook_wgl_swap_buffers,
-			  "wglSwapBuffers");
-		rehook(&wgl_swap_buffers);
+		RealWglSwapBuffers = (PFN_WglSwapBuffers)wgl_sb_proc;
+		DetourAttach((PVOID *)&RealWglSwapBuffers,
+			     hook_wgl_swap_buffers);
+	}
+
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked SwapBuffers");
+		if (RealWglDeleteContext)
+			hlog("Hooked wglDeleteContext");
+		if (RealWglSwapLayerBuffers)
+			hlog("Hooked wglSwapLayerBuffers");
+		if (RealWglSwapBuffers)
+			hlog("Hooked wglSwapBuffers");
+		hlog("Hooked GL");
+	} else {
+		RealSwapBuffers = NULL;
+		RealWglDeleteContext = NULL;
+		RealWglSwapLayerBuffers = NULL;
+		RealWglSwapBuffers = NULL;
+		hlog("Failed to attach Detours hook: %ld", error);
 	}
 
-	rehook(&swap_buffers);
-
-	return true;
+	return success;
 }