Search code examples
c++windowsx86directx-9detours

Why does the DirectX Device Present hook not work in detours?


I am creating a hook which will allow to hook the Present method from the Direct X 9 device,

I do this as follow:

#include <windows.h>
#include <detours.h>
#include <iostream>
#include <d3d9.h>

#pragma comment( lib, "d3d9.lib"   )


typedef HRESULT(PresentDef)(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion);
PresentDef* Real_Present;
PresentDef Mine_Present;

HRESULT Mine_Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
{
    return Real_Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}

BOOL WINAPI DetoursInit(HINSTANCE, DWORD dwReason, LPVOID) {
    switch (dwReason) {
    case DLL_PROCESS_ATTACH:

        LoadLibrary("d3d9.dll");

        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());

        Real_Present = (PresentDef*)DetourFindFunction("d3d9.dll", "IDirect3DDevice9::Present");
        DetourAttach(&(PVOID &)Real_Present, Mine_Present);

        if (ERROR_SUCCESS != DetourTransactionCommit())
        {
            MessageBoxA(NULL, "Failed to Detour", "ERROR", 0);
            break;
        }
        break;

    case DLL_PROCESS_DETACH:
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach(&(PVOID &)Real_Present, Mine_Present);
        DetourTransactionCommit();
        break;
    }

    return TRUE;
}

But every time I do this, I get the Failed to detour message.

Is there any way to detour pure virtual members with microsoft detours?


Solution

  • I'm not going to give any code examples. This is an advanced topic, and you should do the research yourself. You can download the source code of DSFix for Dark Souls and look through it. This will give you a good starting point. link: http://blog.metaclassofnil.com/?tag=dsfix

    The basic idea is that you are detouring a "COM-object" not a "pure function". Consider 'd3d9::IDirect3DDevice9::Present' vs 'd3d9::Present'.

    In the latter case, you would have no problem detouring, using your method. Detours knows the entry-point/address of the d3d9.dll, which is 'd3d9' and the entry-point/address and the function Present() which is 'd3d9::Present'.

    However, since Direct3D uses the 'COM model' it will need some way of referring to the 'COM object', in this case 'IDirect3DDevice9' (the interface for the Direct3D device). You do this by creating your own detoured Direct3DDevice9 object through the function Direct3DCreate9 which is not a 'COM object' but creates the 'COM object' you need to reference the Present() function. Therefore you should make a 'd3d9::Direct3DCreate9' detour which will create a device object (lets call it device9), which you can store in your code. You can then detour the device9->Present function.

    Hope this makes sense. Detours 3 also have some samples of other ways to detouring COM. They are located in the 'Samples' folder after installing detours. There are also tutorials like: http://forum.cheatengine.org/viewtopic.php?t=161045 this uses the older version of detours 1.5. However the overall methodology is the same.