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
相关产品推荐
相关产品推荐

