static HRESULT __stdcall myResetEx(IDirect3DDevice9Ex *idd, D3DPRESENT_PARAMETERS *param, D3DDISPLAYMODEEX *param2) { ods("D3D9: Chaining ResetEx"); DevMapType::iterator it = devMap.find(idd); DevState *ds = it != devMap.end() ? it->second : NULL; if (ds) { if (ds->dwMyThread) { ods("D3D9: myResetEx from other thread"); } Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId()); ds->releaseAll(); } //TODO: Move logic to HardHook. // Call base without active hook in case of no trampoline. ResetExType oResetEx = (ResetExType) hhResetEx.call; hhResetEx.restore(); HRESULT hr = oResetEx(idd, param, param2); hhResetEx.inject(); if (ds) ds->createCleanState(); return hr; }
static ULONG __stdcall myRelease(IDirect3DDevice9 *idd) { Mutex m; DevMapType::iterator it = devMap.find(idd); DevState *ds = it != devMap.end() ? it->second : NULL; if (ds) { // Release is called very often. Thus, we do not want to always log here. #ifdef EXTENDED_OVERLAY_DEBUGOUTPUT ods("D3D9: Using own Refcount implementation for call to Release."); #endif if (ds->dwMyThread == GetCurrentThreadId()) { ds->myRefCount--; return ds->initRefCount + ds->refCount; } else { ds->refCount--; } if (ds->refCount <= 1) { ds->disconnect(); } if (ds->refCount >= 0) { return ds->initRefCount + ds->refCount; } ods("D3D9: Final release is following. MyRefs = %d, Tot = %d", ds->myRefCount, ds->refCount); if (ds->dwMyThread != 0) { ods("D3D9: finalRelease from other thread"); } // Codeblock for stashing threadid { Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId()); ds->releaseAll(); } ods("D3D9: Final release of %p. MyRefs = %d Tot = %d", idd, ds->myRefCount, ds->refCount); devMap.erase(it); delete ds; ds = NULL; } //TODO: Move logic to HardHook. // Call base without active hook in case of no trampoline. ReleaseType oRelease = (ReleaseType) hhRelease.call; hhRelease.restore(); ULONG res = oRelease(idd); hhRelease.inject(); // Release is called very often. Thus, we do not want to always log here. #ifdef EXTENDED_OVERLAY_DEBUGOUTPUT ods("D3D9: Chained Release with result %d", res); #endif return res; }
static HRESULT __stdcall myReset(IDirect3DDevice9 * idd, D3DPRESENT_PARAMETERS *param) { ods("D3D9: Chaining Reset"); DevState *ds = devMap[idd]; if (ds) { DWORD dwOldThread = ds->dwMyThread; if (dwOldThread) ods("myReset from other thread"); ds->dwMyThread = GetCurrentThreadId(); ds->releaseAll(); ds->dwMyThread = dwOldThread; resetAdditions(); } ResetType oReset = (ResetType) hhReset.call; hhReset.restore(); HRESULT hr=oReset(idd, param); hhReset.inject(); if (ds) ds->createCleanState(); return hr; }
static HRESULT __stdcall myReset(IDirect3DDevice9 * idd, D3DPRESENT_PARAMETERS *param) { ods("D3D9: Chaining Reset"); DevState *ds = devMap[idd]; if (ds) { DWORD dwOldThread = ds->dwMyThread; if (dwOldThread) ods("D3D9: myReset from other thread"); ds->dwMyThread = GetCurrentThreadId(); ds->releaseAll(); ds->dwMyThread = dwOldThread; } //TODO: Move logic to HardHook. // Call base without active hook in case of no trampoline. ResetType oReset = (ResetType) hhReset.call; hhReset.restore(); HRESULT hr = oReset(idd, param); hhReset.inject(); if (ds) ds->createCleanState(); return hr; }
static HRESULT __stdcall myCreateDeviceEx(IDirect3D9Ex * id3d, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode, IDirect3DDevice9Ex** ppReturnedDeviceInterface) { Mutex m; ods("D3D9: Chaining CreateDeviceEx"); // BehaviorFlags &= ~D3DCREATE_PUREDEVICE; //TODO: Move logic to HardHook. // Call base without active hook in case of no trampoline. CreateDeviceExType oCreateDeviceEx = (CreateDeviceExType) hhCreateDeviceEx.call; hhCreateDeviceEx.restore(); HRESULT hr = oCreateDeviceEx(id3d, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode, ppReturnedDeviceInterface); hhCreateDeviceEx.inject(); if (FAILED(hr)) return hr; IDirect3DDevice9Ex *idd = *ppReturnedDeviceInterface; DevState *ds = new DevState; ds->dev = idd; idd->AddRef(); ds->initRefCount = idd->Release(); devMap[idd] = ds; // The offsets are dependent on the declaration order of the struct. // See IDirect3DDevice9 (2nd, 3rd, 17th, 18th functions) const unsigned int offsetAddref = 1; const unsigned int offsetRelease = 2; const unsigned int offsetReset = 16; const unsigned int offsetPresent = 17; if (bIsWin8) { hhAddRef.setupInterface(idd, offsetAddref, reinterpret_cast<voidFunc>(myWin8AddRef)); hhRelease.setupInterface(idd, offsetRelease, reinterpret_cast<voidFunc>(myWin8Release)); } else { hhAddRef.setupInterface(idd, offsetAddref, reinterpret_cast<voidFunc>(myAddRef)); hhRelease.setupInterface(idd, offsetRelease, reinterpret_cast<voidFunc>(myRelease)); } hhReset.setupInterface(idd, offsetReset, reinterpret_cast<voidFunc>(myReset)); hhPresent.setupInterface(idd, offsetPresent, reinterpret_cast<voidFunc>(myPresent)); IDirect3DSwapChain9 *pSwap = NULL; idd->GetSwapChain(0, &pSwap); if (pSwap) { // The offset is dependent on the declaration order of the struct. // See IDirect3DSwapChain9 (Present is the fourth function) const unsigned int offsetPresent = 3; hhSwapPresent.setupInterface(pSwap, offsetPresent, reinterpret_cast<voidFunc>(mySwapPresent)); pSwap->Release(); } else { ods("D3D9: Failed to get swapchain for DevEx"); } ds->createCleanState(); return hr; }
static ULONG __stdcall myRelease(IDirect3DDevice9 *idd) { Mutex m; ods("D3D9: Chaining Release"); DevState *ds = devMap[idd]; if (ds) { if (ds->dwMyThread == GetCurrentThreadId()) { ds->myRefCount--; return ds->refCount + ds->initRefCount; } else { ds->refCount--; } if (ds->refCount <= 1) ds->disconnect(); if (ds->refCount >= 0) return ds->refCount + ds->initRefCount; ods("D3D9: Final release is following. MyRefs = %d, Tot = %d", ds->myRefCount, ds->refCount); DWORD dwOldThread = ds->dwMyThread; if (dwOldThread) ods("D3D9: finalRelease from other thread"); ds->dwMyThread = GetCurrentThreadId(); ds->releaseAll(); ds->dwMyThread = dwOldThread; ods("D3D9: Final release. MyRefs = %d Tot = %d", ds->myRefCount, ds->refCount); devMap.erase(idd); delete ds; } //TODO: Move logic to HardHook. // Call base without active hook in case of no trampoline. ReleaseType oRelease = (ReleaseType) hhRelease.call; hhRelease.restore(); ULONG res = oRelease(idd); hhRelease.inject(); ods("D3D9: Chained Release with result %d", res); return res; }
static HRESULT __stdcall myCreateDeviceEx(IDirect3D9Ex * id3d, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode, IDirect3DDevice9Ex** ppReturnedDeviceInterface) { Mutex m; ods("D3D9: Chaining CreateDeviceEx"); // BehaviorFlags &= ~D3DCREATE_PUREDEVICE; CreateDeviceExType oCreateDeviceEx = (CreateDeviceExType) hhCreateDeviceEx.call; hhCreateDeviceEx.restore(); HRESULT hr=oCreateDeviceEx(id3d, Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,pFullscreenDisplayMode,ppReturnedDeviceInterface); hhCreateDeviceEx.inject(); if (FAILED(hr)) return hr; IDirect3DDevice9Ex *idd = *ppReturnedDeviceInterface; DevState *ds = new DevState; ds->dev = idd; idd->AddRef(); ds->initRefCount = idd->Release(); devMap[idd] = ds; if (bIsWin8) { hhAddRef.setupInterface(idd, 1, reinterpret_cast<voidFunc>(myWin8AddRef)); hhRelease.setupInterface(idd, 2, reinterpret_cast<voidFunc>(myWin8Release)); } else { hhAddRef.setupInterface(idd, 1, reinterpret_cast<voidFunc>(myAddRef)); hhRelease.setupInterface(idd, 2, reinterpret_cast<voidFunc>(myRelease)); } hhReset.setupInterface(idd, 16, reinterpret_cast<voidFunc>(myReset)); hhPresent.setupInterface(idd, 17, reinterpret_cast<voidFunc>(myPresent)); IDirect3DSwapChain9 *pSwap = NULL; idd->GetSwapChain(0, &pSwap); if (pSwap) { hhSwapPresent.setupInterface(pSwap, 3, reinterpret_cast<voidFunc>(mySwapPresent)); pSwap->Release(); } else { ods("D3D9: Failed to get swapchain for DevEx"); } ds->createCleanState(); return hr; }
static void doPresent(IDirect3DDevice9 *idd) { DevMapType::iterator it = devMap.find(idd); DevState *ds = it != devMap.end() ? it->second : NULL; if (ds && ds->pSB) { if (ds->dwMyThread != 0) { ods("D3D9: doPresent from other thread"); } Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId()); IDirect3DSurface9 *pTarget = NULL; IDirect3DSurface9 *pRenderTarget = NULL; idd->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pTarget); idd->GetRenderTarget(0, &pRenderTarget); // Present is called for each frame. Thus, we do not want to always log here. #ifdef EXTENDED_OVERLAY_DEBUGOUTPUT ods("D3D9: doPresent BackB %p RenderT %p", pTarget, pRenderTarget); #endif IDirect3DStateBlock9* pStateBlock = NULL; idd->CreateStateBlock(D3DSBT_ALL, &pStateBlock); pStateBlock->Capture(); ds->pSB->Apply(); if (pTarget != pRenderTarget) idd->SetRenderTarget(0, pTarget); idd->BeginScene(); ds->draw(); idd->EndScene(); pStateBlock->Apply(); pStateBlock->Release(); pRenderTarget->Release(); pTarget->Release(); // ods("D3D9: Finished ref is %d %d", ds->myRefCount, ds->refCount); } }
static ULONG __stdcall myRelease(IDirect3DDevice9 *idd) { Mutex m; DevState *ds = devMap[idd]; if (ds) { if (ds->dwMyThread == GetCurrentThreadId()) { ds->myRefCount--; return ds->refCount + ds->initRefCount; } else { ds->refCount--; } if (ds->refCount <= 1) ds->disconnect(); if (ds->refCount >= 0) return ds->refCount + ds->initRefCount; ods("D3D9: Final release. MyRefs = %d, Tot = %d", ds->myRefCount, ds->refCount); DWORD dwOldThread = ds->dwMyThread; if (dwOldThread) ods("finalRelease from other thread"); ds->dwMyThread = GetCurrentThreadId(); ds->releaseAll(); ds->dwMyThread = dwOldThread; resetAdditions(); ods("D3D9: Final release, MyRefs = %d Tot = %d", ds->myRefCount, ds->refCount); devMap.erase(idd); delete ds; } ReleaseType oRelease = (ReleaseType) hhRelease.call; hhRelease.restore(); LONG res = oRelease(idd); hhRelease.inject(); ods("D3D9: Chaining Release: %d", res); return res; }
static ULONG __stdcall myWin8Release(IDirect3DDevice9 *idd) { Mutex m; DevState *ds = devMap[idd]; if (ds) { if (ds->dwMyThread == GetCurrentThreadId()) { ds->myRefCount--; return ds->refCount; } if (ds->refCount == 1) { ds->disconnect(); ods("D3D9: Final release. MyRefs = %d, Tot = %d", ds->myRefCount, ds->refCount); DWORD dwOldThread = ds->dwMyThread; if (dwOldThread) ods("finalRelease from other thread"); ds->dwMyThread = GetCurrentThreadId(); ds->releaseAll(); ds->dwMyThread = dwOldThread; CustomHUD::Reset(); ods("D3D9: Final release, MyRefs = %d Tot = %d", ds->myRefCount, ds->refCount); devMap.erase(idd); delete ds; ds = NULL; } } ReleaseType oRelease = (ReleaseType) hhRelease.call; hhRelease.restore(); LONG res = oRelease(idd); if (ds) ds->refCount = res; hhRelease.inject(); ods("D3D9: Chaining Release (Win8): %d", res); return res; }
static void doPresent(IDirect3DDevice9 *idd) { DevState *ds = devMap[idd]; if (ds && ds->pSB) { DWORD dwOldThread = ds->dwMyThread; if (dwOldThread) ods("doPresent from other thread"); ds->dwMyThread = GetCurrentThreadId(); IDirect3DSurface9 *pTarget = NULL; IDirect3DSurface9 *pRenderTarget = NULL; idd->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pTarget); idd->GetRenderTarget(0, &pRenderTarget); ods("D3D9: doPresent Back %p RenderT %p",pTarget,pRenderTarget); IDirect3DStateBlock9* pStateBlock = NULL; idd->CreateStateBlock(D3DSBT_ALL, &pStateBlock); pStateBlock->Capture(); ds->pSB->Apply(); if (pTarget != pRenderTarget) idd->SetRenderTarget(0, pTarget); idd->BeginScene(); ds->draw(); idd->EndScene(); pStateBlock->Apply(); pStateBlock->Release(); pRenderTarget->Release(); pTarget->Release(); // ods("Finished ref is %d %d", ds->myRefCount, ds->refCount); ds->dwMyThread = dwOldThread; } }
static HRESULT __stdcall myCreateDevice(IDirect3D9 *id3d, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface) { Mutex m; ods("D3D9: Chaining CreateDevice"); // BehaviorFlags &= ~D3DCREATE_PUREDEVICE; //TODO: Move logic to HardHook. // Call base without active hook in case of no trampoline. CreateDeviceType oCreateDevice = (CreateDeviceType) hhCreateDevice.call; hhCreateDevice.restore(); HRESULT hr = oCreateDevice(id3d, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface); hhCreateDevice.inject(); if (FAILED(hr)) return hr; IDirect3DDevice9 *idd = *ppReturnedDeviceInterface; // Get real interface, please. IDirect3DDevice9 *originalDevice = findOriginalDevice(idd); if (idd != originalDevice) { ods("D3D9: Prepatched device, using original. %p => %p", idd, originalDevice); idd = originalDevice; } DevState *ds = new DevState; ds->dev = idd; idd->AddRef(); ds->initRefCount = idd->Release(); DevMapType::iterator it = devMap.find(idd); if (it != devMap.end()) { ods("Device exists in devMap already - canceling injection into device. Thread prev: %d ; new: %d", it->second->dwMyThread, GetCurrentThreadId()); delete ds; return hr; } devMap[idd] = ds; // The offsets are dependent on the declaration order of the struct. // See IDirect3DDevice9 (2nd, 3rd, 17th, 18th functions) const unsigned int offsetAddref = 1; const unsigned int offsetRelease = 2; const unsigned int offsetReset = 16; const unsigned int offsetPresent = 17; if (bIsWin8) { hhAddRef.setupInterface(idd, offsetAddref, reinterpret_cast<voidFunc>(myWin8AddRef)); hhRelease.setupInterface(idd, offsetRelease, reinterpret_cast<voidFunc>(myWin8Release)); } else { hhAddRef.setupInterface(idd, offsetAddref, reinterpret_cast<voidFunc>(myAddRef)); hhRelease.setupInterface(idd, offsetRelease, reinterpret_cast<voidFunc>(myRelease)); } hhReset.setupInterface(idd, offsetReset, reinterpret_cast<voidFunc>(myReset)); hhPresent.setupInterface(idd, offsetPresent, reinterpret_cast<voidFunc>(myPresent)); IDirect3DSwapChain9 *pSwap = NULL; idd->GetSwapChain(0, &pSwap); if (pSwap) { // The offset is dependent on the declaration order of the struct. // See IDirect3DSwapChain9 (Present is the fourth function) const unsigned int offsetPresent = 3; hhSwapPresent.setupInterface(pSwap, offsetPresent, reinterpret_cast<voidFunc>(mySwapPresent)); pSwap->Release(); } else { ods("D3D9: Failed to get swapchain"); } ds->createCleanState(); return hr; }
/// Present the overlay. /// /// If called via IDirect3DDevice9::present() or IDirect3DDevice9Ex::present(), /// idd will be non-NULL and ids ill be NULL. /// /// If called via IDirect3DSwapChain9::present(), both idd and ids will be /// non-NULL. /// /// The doPresent function expects the following assumptions to be valid: /// /// - Only one swap chain used at the same time. /// - Windowed? IDirect3D9SwapChain::present() is used. ("Additional swap chain" is used) /// - Full screen? IDirect3D9Device::present() is used. (Implicit swap chain for IDirect3D9Device is used) /// /// It's either/or. /// /// If doPresent is called multiple times per frame (say, for different swap chains), /// the overlay will break badly when DevState::draw() is called. FPS counting will be off, /// different render targets with different sizes will cause a size-renegotiation with Mumble /// every frame, etc. static void doPresent(IDirect3DDevice9 *idd, IDirect3DSwapChain9 *ids) { DevMapType::iterator it = devMap.find(idd); DevState *ds = it != devMap.end() ? it->second : NULL; HRESULT hres; if (ds && ds->pSB) { if (ds->dwMyThread != 0) { ods("D3D9: doPresent from other thread"); } Stash<DWORD> stashThread(&(ds->dwMyThread), GetCurrentThreadId()); // Get the back buffer. // If we're called via IDirect3DSwapChain9, acquire it via the swap chain object. // Otherwise, acquire it via the device itself. IDirect3DSurface9 *pTarget = NULL; if (ids) { hres = ids->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pTarget); if (FAILED(hres)) { if (hres == D3DERR_INVALIDCALL) { ods("D3D9: IDirect3DSwapChain9::GetBackBuffer failed. BackBuffer index equals or exceeds the total number of back buffers"); } else { ods("D3D9: IDirect3DSwapChain9::GetBackBuffer failed"); } } } else { hres = idd->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pTarget); if (FAILED(hres)) { if (hres == D3DERR_INVALIDCALL) { ods("D3D9: IDirect3DDevice9::GetBackBuffer failed. BackBuffer index equals or exceeds the total number of back buffers"); } else { ods("D3D9: IDirect3DDevice9::GetBackBuffer failed"); } } } IDirect3DSurface9 *pRenderTarget = NULL; hres = idd->GetRenderTarget(0, &pRenderTarget); if (FAILED(hres)) { if (hres == D3DERR_NOTFOUND) { ods("D3D9: IDirect3DDevice9::GetRenderTarget failed. There is no render target with the specified index"); } else if (hres == D3DERR_INVALIDCALL) { ods("D3D9: IDirect3DDevice9::GetRenderTarget failed. One of the passed arguments was invalid"); } else { ods("D3D9: IDirect3DDevice9::GetRenderTarget failed"); } } // Present is called for each frame. Thus, we do not want to always log here. #ifdef EXTENDED_OVERLAY_DEBUGOUTPUT ods("D3D9: doPresent BackB %p RenderT %p", pTarget, pRenderTarget); #endif IDirect3DStateBlock9* pStateBlock = NULL; idd->CreateStateBlock(D3DSBT_ALL, &pStateBlock); pStateBlock->Capture(); ds->pSB->Apply(); if (pTarget != pRenderTarget) { hres = idd->SetRenderTarget(0, pTarget); if (FAILED(hres)) { ods("D3D9: IDirect3DDevice9::SetRenderTarget failed"); } } // If we're called via IDirect3DSwapChain9::present(), we have to // get the size of the back buffer and manually set the viewport size // to match it. // // Although the call to IDirect3DDevice9::SetRenderTarget() above is // documented as updating the device's viewport: // // "Setting a new render target will cause the viewport (see Viewports // and Clipping (Direct3D 9)) to be set to the full size of the new // render target." // // (via https://msdn.microsoft.com/en-us/library/windows/desktop/bb174455(v=vs.85).aspx) // // ...this doesn't happen. At least for some programs such as Final Fantasy XIV // and Battle.net Launcher. For these programs, we get a viewport of 1x1. // // The viewport we set here is used in the call below to DevState::draw() // as the full size of the screen/window. if (ids) { D3DPRESENT_PARAMETERS pp; hres = ids->GetPresentParameters(&pp); if (FAILED(hres)) { ods("D3D9: IDirect3DSwapChain9::GetPresentParameters failed"); } else { if (pp.BackBufferWidth != 0 && pp.BackBufferHeight != 0) { D3DVIEWPORT9 vp; vp.X = 0; vp.Y = 0; vp.Width = pp.BackBufferWidth; vp.Height = pp.BackBufferHeight; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; idd->SetViewport(&vp); } } } idd->BeginScene(); ds->draw(); idd->EndScene(); pStateBlock->Apply(); pStateBlock->Release(); pRenderTarget->Release(); pTarget->Release(); // ods("D3D9: Finished ref is %d %d", ds->myRefCount, ds->refCount); } }
static HRESULT __stdcall myCreateDevice(IDirect3D9 * id3d, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface) { ods("D3D9: Chaining CreateDevice"); Mutex m; // BehaviorFlags &= ~D3DCREATE_PUREDEVICE; CreateDeviceType oCreateDevice = (CreateDeviceType) hhCreateDevice.call; hhCreateDevice.restore(); HRESULT hr=oCreateDevice(id3d, Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,ppReturnedDeviceInterface); hhCreateDevice.inject(); if (FAILED(hr)) return hr; IDirect3DDevice9 *idd = *ppReturnedDeviceInterface; IDirect3DSwapChain9 *pSwap = NULL; // Get real interface, please. bool bfound; do { bfound = false; idd->GetSwapChain(0, &pSwap); if (pSwap) { IDirect3DDevice9 *idorig = NULL; if (SUCCEEDED(pSwap->GetDevice(&idorig))) { if (idorig != idd) { ods("Prepatched device, using original. %p => %p", idorig, idd); if (idd != *ppReturnedDeviceInterface) idd->Release(); idd = idorig; bfound = true; } else { idorig->Release(); } } pSwap->Release(); } } while (bfound); DevState *ds = new DevState; ds->dev = idd; idd->AddRef(); ds->initRefCount = idd->Release(); devMap[idd] = ds; if (bIsWin8) { hhAddRef.setupInterface(idd, 1, reinterpret_cast<voidFunc>(myWin8AddRef)); hhRelease.setupInterface(idd, 2, reinterpret_cast<voidFunc>(myWin8Release)); } else { hhAddRef.setupInterface(idd, 1, reinterpret_cast<voidFunc>(myAddRef)); hhRelease.setupInterface(idd, 2, reinterpret_cast<voidFunc>(myRelease)); } hhReset.setupInterface(idd, 16, reinterpret_cast<voidFunc>(myReset)); hhPresent.setupInterface(idd, 17, reinterpret_cast<voidFunc>(myPresent)); pSwap = NULL; idd->GetSwapChain(0, &pSwap); if (pSwap) { hhSwapPresent.setupInterface(pSwap, 3, reinterpret_cast<voidFunc>(mySwapPresent)); pSwap->Release(); } else { ods("D3D9: Failed to get swapchain"); } ds->createCleanState(); return hr; }