22#include " D3D9Hooks.h"
33#include " MinHook.h"
44
5+ #include < atomic>
56#include < mutex>
67#include < unordered_map>
78#include < vector>
@@ -72,6 +73,9 @@ namespace {
7273
7374 std::vector<void *> g_hooked_targets;
7475
76+ // Set when teardown begins; a detour still reached after this just calls the original.
77+ std::atomic<bool > g_unhooked{false };
78+
7579 // device -> owning TextureClient
7680 std::mutex g_devices_mutex;
7781 std::unordered_map<IDirect3DDevice9*, TextureClient*> g_devices;
@@ -174,6 +178,7 @@ namespace {
174178 D3DPRESENT_PARAMETERS * pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface)
175179 {
176180 const HRESULT hr = o_CreateDevice (self, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
181+ if (g_unhooked) return hr;
177182 if (SUCCEEDED (hr) && ppReturnedDeviceInterface && *ppReturnedDeviceInterface) {
178183 OnDeviceCreated (*ppReturnedDeviceInterface);
179184 }
@@ -184,6 +189,7 @@ namespace {
184189 D3DPRESENT_PARAMETERS * pPresentationParameters, D3DDISPLAYMODEEX * pFullscreenDisplayMode, IDirect3DDevice9Ex** ppReturnedDeviceInterface)
185190 {
186191 const HRESULT hr = o_CreateDeviceEx (self, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode, ppReturnedDeviceInterface);
192+ if (g_unhooked) return hr;
187193 if (SUCCEEDED (hr) && ppReturnedDeviceInterface && *ppReturnedDeviceInterface) {
188194 OnDeviceCreated (*ppReturnedDeviceInterface);
189195 }
@@ -193,6 +199,7 @@ namespace {
193199 ULONG STDMETHODCALLTYPE h_DeviceRelease (IDirect3DDevice9* self)
194200 {
195201 const ULONG count = o_DeviceRelease (self);
202+ if (g_unhooked) return count;
196203 if (count == 0 ) {
197204 TextureClient* client = nullptr ;
198205 {
@@ -212,6 +219,7 @@ namespace {
212219 IDirect3DTexture9** ppTexture, HANDLE * pSharedHandle)
213220 {
214221 const HRESULT hr = o_CreateTexture (self, Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
222+ if (g_unhooked) return hr;
215223 if (SUCCEEDED (hr) && ppTexture && *ppTexture) {
216224 InstallTextureReleaseHook (*ppTexture, TexType::Tex2D);
217225 if (auto * client = ClientFor (self))
@@ -224,6 +232,7 @@ namespace {
224232 IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE * pSharedHandle)
225233 {
226234 const HRESULT hr = o_CreateVolumeTexture (self, Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
235+ if (g_unhooked) return hr;
227236 if (SUCCEEDED (hr) && ppVolumeTexture && *ppVolumeTexture) {
228237 InstallTextureReleaseHook (*ppVolumeTexture, TexType::Volume);
229238 if (auto * client = ClientFor (self))
@@ -236,6 +245,7 @@ namespace {
236245 IDirect3DCubeTexture9** ppCubeTexture, HANDLE * pSharedHandle)
237246 {
238247 const HRESULT hr = o_CreateCubeTexture (self, EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
248+ if (g_unhooked) return hr;
239249 if (SUCCEEDED (hr) && ppCubeTexture && *ppCubeTexture) {
240250 InstallTextureReleaseHook (*ppCubeTexture, TexType::Cube);
241251 if (auto * client = ClientFor (self))
@@ -248,6 +258,7 @@ namespace {
248258 {
249259 // Pass the real textures through, then re-evaluate mods on the changed destination.
250260 const HRESULT hr = o_UpdateTexture (self, pSourceTexture, pDestinationTexture);
261+ if (g_unhooked) return hr;
251262 if (SUCCEEDED (hr)) {
252263 if (auto * client = ClientFor (self))
253264 client->OnUpdateTexture (pSourceTexture, pDestinationTexture);
@@ -257,13 +268,15 @@ namespace {
257268
258269 HRESULT STDMETHODCALLTYPE h_BeginScene (IDirect3DDevice9* self)
259270 {
271+ if (g_unhooked) return o_BeginScene (self);
260272 if (auto * client = ClientFor (self))
261273 client->OnBeginScene ();
262274 return o_BeginScene (self);
263275 }
264276
265277 HRESULT STDMETHODCALLTYPE h_SetTexture (IDirect3DDevice9* self, DWORD Stage, IDirect3DBaseTexture9* pTexture)
266278 {
279+ if (g_unhooked) return o_SetTexture (self, Stage, pTexture);
267280 IDirect3DBaseTexture9* bind = pTexture;
268281 if (auto * client = ClientFor (self))
269282 bind = client->ResolveBinding (pTexture); // substitute the fake when modded
@@ -273,6 +286,7 @@ namespace {
273286 HRESULT STDMETHODCALLTYPE h_GetTexture (IDirect3DDevice9* self, DWORD Stage, IDirect3DBaseTexture9** ppTexture)
274287 {
275288 const HRESULT hr = o_GetTexture (self, Stage, ppTexture);
289+ if (g_unhooked) return hr;
276290 if (SUCCEEDED (hr) && ppTexture && *ppTexture) {
277291 if (auto * client = ClientFor (self)) {
278292 if (auto * original = client->ResolveOriginalFromFake (*ppTexture)) {
@@ -295,20 +309,23 @@ namespace {
295309 ULONG STDMETHODCALLTYPE h_Tex2DRelease (IUnknown* self)
296310 {
297311 const ULONG count = o_Tex2DRelease (self);
312+ if (g_unhooked) return count;
298313 ReleaseTextureCleanup (self, count);
299314 return count;
300315 }
301316
302317 ULONG STDMETHODCALLTYPE h_VolumeRelease (IUnknown* self)
303318 {
304319 const ULONG count = o_VolumeRelease (self);
320+ if (g_unhooked) return count;
305321 ReleaseTextureCleanup (self, count);
306322 return count;
307323 }
308324
309325 ULONG STDMETHODCALLTYPE h_CubeRelease (IUnknown* self)
310326 {
311327 const ULONG count = o_CubeRelease (self);
328+ if (g_unhooked) return count;
312329 ReleaseTextureCleanup (self, count);
313330 return count;
314331 }
@@ -317,6 +334,7 @@ namespace {
317334void InstallD3D9Hooks (IDirect3D9* d3d9, const bool is_ex)
318335{
319336 if (d3d9 == nullptr || g_d3d9_hooks_installed) return ;
337+ g_unhooked = false ; // re-arm in case a prior teardown left the flag set
320338 void ** vt = GetVTable (d3d9);
321339 Hook (vt[kIDirect3D9_CreateDevice ], &h_CreateDevice, reinterpret_cast <void **>(&o_CreateDevice));
322340 if (is_ex) {
@@ -333,12 +351,16 @@ bool RegisterExistingDevice(IDirect3DDevice9* device)
333351 if (g_devices.contains (device)) return false ; // already known
334352 if (!g_devices.empty ()) return false ; // gMod supports a single device at a time
335353 }
354+ g_unhooked = false ; // re-arm in case a prior teardown left the flag set
336355 OnDeviceCreated (device); // installs device hooks + TextureClient (idempotent)
337356 return ClientFor (device) != nullptr ;
338357}
339358
340359void RemoveAllD3D9Hooks ()
341360{
361+ // Signal first: a detour reached after this (e.g. a surviving patch) falls through.
362+ g_unhooked = true ;
363+
342364 for (void * target : g_hooked_targets) {
343365 MH_DisableHook (target);
344366 MH_RemoveHook (target);
@@ -351,19 +373,7 @@ void RemoveAllD3D9Hooks()
351373 g_volume_release_installed = false ;
352374 g_cube_release_installed = false ;
353375
354- o_CreateDevice = nullptr ;
355- o_CreateDeviceEx = nullptr ;
356- o_DeviceRelease = nullptr ;
357- o_CreateTexture = nullptr ;
358- o_CreateVolumeTexture = nullptr ;
359- o_CreateCubeTexture = nullptr ;
360- o_UpdateTexture = nullptr ;
361- o_BeginScene = nullptr ;
362- o_SetTexture = nullptr ;
363- o_GetTexture = nullptr ;
364- o_Tex2DRelease = nullptr ;
365- o_VolumeRelease = nullptr ;
366- o_CubeRelease = nullptr ;
376+ // Leave the o_* trampoline pointers intact so a surviving detour can still call through.
367377}
368378
369379void DestroyAllTextureClients ()
0 commit comments