Search code examples
c++directxreverse-engineeringdirectx-9imgui

imgui is not rendering with a D3D9 Hook


ok so basically I am trying to inject a DLL into a game for an external menu for debugging and my hook works completely fine, i can render a normal square fine to the screen but when i try to render imgui, some games DirectX just dies and some others nothing renders at all. The issue makes no sense because I've tried everything, i've switched libraries, tried different compile settings and just started doing random shit but still to no avail, the library i am using for hooking is minhook (was using kiero but from trying to figure out the issue switched to manually getting the D3D Device).

My hooks work entirely fine as I said earlier, I can render a square to the screen without issues but I cant render imgui (and yes i checked it is the DX9 version of imgui), code:

long __stdcall EndSceneHook(IDirect3DDevice9* pDevice) // Our hooked endscene
{
    D3DRECT BarRect = { 100, 100, 200, 200 };
    pDevice->Clear(1, &BarRect, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 0, 255, 0), 0.0f, 0);

    if (!EndSceneInit) {
        ImGui::CreateContext();
        ImGuiIO& io = ImGui::GetIO();
        ImGui_ImplWin32_Init(TrackmaniaWindow);
        ImGui_ImplDX9_Init(pDevice);
        
        EndSceneInit = true;
        return OldEndScene(pDevice);
    }
    ImGui_ImplDX9_NewFrame();
    ImGui_ImplWin32_NewFrame();

    ImGui::NewFrame();

    ImGui::ShowDemoWindow();

    ImGui::EndFrame();
    ImGui::Render();

    ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());

    return OldEndScene(pDevice); // Call original ensdcene so the game can draw
}

And if you are considering saying i forgot to hook Reset I did but the game pretty much never calls it so I probably did it wrong, code for that:

long __stdcall ResetHook(IDirect3DDevice9* pDevice, D3DPRESENT_PARAMETERS Parameters) {

    /* Delete imgui to avoid errors */
    ImGui_ImplDX9_Shutdown();
    ImGui_ImplWin32_Shutdown();
    ImGui::DestroyContext();

    /* Check if its actually being called */
    if (!ResetInit) {
        std::cout << "Reset called correctly" << std::endl;
        ResetInit = true;
    }

    /* Return old function */
    return OldReset(pDevice, Parameters);
}

Just incase I did mess up the hooking process for 1 of the functions i will also include the code i used to actually hook them

if (MH_CreateHook(vTable[42], EndSceneHook, (void**)&OldEndScene) != MH_OK)
        ThrowError(MinHook_Hook_Creation_Failed);

if (MH_CreateHook(vTable[16],OldReset,(void**)&OldReset)!=MH_OK)
        ThrowError(MinHook_Hook_Creation_Failed);

MH_EnableHook(MH_ALL_HOOKS);

Solution

  • Ok so I solved the issue already, but just incase anyone else needs help I have found a few fixes as to why it would crash/not render.

    First one being EnumWindow(), if you are using EnumWindows() to get your target processes HWND then that is likely one or your entire issue, For internal cheats, Use GetForegroundWindow() when the game is loaded, or you can use FindWindow(0,"Window Name") (works for both external and internal [game needs to be loaded])

    void MainThread(){
        HWND ProcessWindow = 0;
        WaitForProcessToLoad(GameHandle); // This is just an example of waiting for the game to load
        ProcessWindow = GetForegroundWindow(); // We got the HWND
        
        // or
        ProcessWindow = FindWindow(0,"Thing.exe");
    }
    

    To start off with the 2nd possible issue, make sure your replacement functions for the functions your hooking are actually passing the right arguments (this is if your hook instantly crashes), and make sure you are returning the original function.

    Make sure your WndProc function is working correctly (if you dont know how then google DX9 Hooking Tutorials and copy + paste there code for that).

    Last fix is how you are rendering imgui to the screen, if imgui isnt rendering after the first fix then it is likely because you arent calling a function that is required, This is an example of correctly made imgui rendering

    long __stdcall EndSceneHook(IDirect3DDevice9* pDevice) // Our hooked endscene
    {
        if (!EndSceneInit) {
            ImGui::CreateContext();
            ImGuiIO& io = ImGui::GetIO();
    
            ImGui::StyleColorsDark();
            ImGui_ImplWin32_Init(Window);
            ImGui_ImplDX9_Init(pDevice);
            
            EndSceneInit = true;
            return OldEndScene(pDevice);
        }
    
        ImGui_ImplDX9_NewFrame();
        ImGui_ImplWin32_NewFrame();
    
        ImGui::NewFrame();
    
        ImGui::ShowDemoWindow();
    
        ImGui::EndFrame();
        ImGui::Render();
    
        ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
    
        return OldEndScene(pDevice); // Call original ensdcene so the game can draw
    }
    

    If none of these fixes worked then google the error or youtube DX9 hooking tutorials