You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hook D3D9时ImGui无法渲染的问题求助

排查DX9环境下ImGui无法渲染/游戏崩溃问题

核心问题总结

Hook EndScene 可正常绘制矩形,但ImGui要么无渲染输出,要么导致部分游戏DX9崩溃;已尝试Hook Reset 但未触发,当前使用MinHook手动获取D3D设备。

关键错误点与修复方案

1. Reset Hook创建代码错误

你的Hook创建代码中,Reset 的目标函数参数写错,导致Hook完全未生效:

// 错误代码:第二个参数应为自定义的ResetHook,而非OldReset
if (MH_CreateHook(vTable[16],OldReset,(void**)&OldReset)!=MH_OK)
        ThrowError(MinHook_Hook_Creation_Failed);

修复后:

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

2. ImGui渲染顺序错误

当前代码先渲染ImGui再调用原始EndScene,游戏画面会覆盖ImGui内容,导致无输出:

// 错误顺序:ImGui渲染被游戏画面覆盖
ImGui::Render();
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
return OldEndScene(pDevice);

修复后顺序:
先执行游戏原始EndScene完成画面渲染,再渲染ImGui(确保ImGui显示在最上层):

// 先调用原始EndScene让游戏完成渲染
long result = OldEndScene(pDevice);

// 再渲染ImGui
ImGui::Render();
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());

return result;

3. Reset Hook逻辑不完整

当前ResetHook仅销毁ImGui资源,但未在Reset成功后重新初始化,设备重置后ImGui资源失效会引发崩溃:
修复后的ResetHook:

long __stdcall ResetHook(IDirect3DDevice9* pDevice, D3DPRESENT_PARAMETERS* pParameters) {
    // 先让ImGui释放设备相关资源
    ImGui_ImplDX9_InvalidateDeviceObjects();
    
    // 调用原始Reset函数
    long result = OldReset(pDevice, pParameters);
    
    // Reset成功后重新初始化ImGui设备资源
    if (result == D3D_OK) {
        ImGui_ImplDX9_CreateDeviceObjects();
    }

    if (!ResetInit) {
        std::cout << "Reset called correctly" << std::endl;
        ResetInit = true;
    }

    return result;
}

注意:使用InvalidateDeviceObjects和CreateDeviceObjects替代直接销毁Context,更符合ImGui DX9后端的生命周期规范。

4. ImGui初始化时机的设备状态问题

当前初始化ImGui在Clear之后,设备可能处于非默认状态,易导致初始化失败:
调整初始化位置到Clear之前:

long __stdcall EndSceneHook(IDirect3DDevice9* pDevice) {
    if (!EndSceneInit) {
        ImGui::CreateContext();
        ImGuiIO& io = ImGui::GetIO();
        ImGui_ImplWin32_Init(TrackmaniaWindow);
        ImGui_ImplDX9_Init(pDevice);
        
        EndSceneInit = true;
    }

    // 先执行ImGui帧准备流程
    ImGui_ImplDX9_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();

    ImGui::ShowDemoWindow();

    ImGui::EndFrame();

    // 绘制测试矩形
    D3DRECT BarRect = { 100, 100, 200, 200 };
    pDevice->Clear(1, &BarRect, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 0, 255, 0), 0.0f, 0);

    // 调用游戏原始EndScene
    long result = OldEndScene(pDevice);

    // 渲染ImGui
    ImGui::Render();
    ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());

    return result;
}

5. 额外排查点

  • 线程安全:确保ImGui的初始化和渲染都在D3D设备所在线程执行,部分游戏会用多线程处理设备操作,可通过日志打印线程ID确认。
  • 编译设置:确保ImGui和你的DLL使用相同的CRT运行时库(比如均为Multi-threaded DLL (/MD)),避免内存管理冲突引发崩溃。
  • 设备状态保存:在渲染ImGui前后保存/恢复D3D设备状态,防止ImGui修改的状态影响游戏渲染:
    // 渲染前保存设备状态
    IDirect3DStateBlock9* stateBlock = nullptr;
    pDevice->CreateStateBlock(D3DSBT_ALL, &stateBlock);
    stateBlock->Capture();
    
    ImGui::Render();
    ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
    
    // 恢复设备状态
    stateBlock->Apply();
    stateBlock->Release();
    

内容的提问来源于stack exchange,提问作者bruh_wym

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:27:27