- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 505
- Реакции
- 12
Народ, кто плотно сидит на реверсе классики под DX9, подскажите по базе. Пытаюсь поднять ImGui в одном проекте через классический хук EndScene, но столкнулся с парой неприятных моментов, которые портят весь визуал.
Суть проблемы:
Техническая часть:
Для реализации использую Detours. Хукаю EndScene (индекс 42 в VTable) и Reset (индекс 16). Для инициализации девайса и получения HWND закинул хук на CreateWindowExA.
Грешу на то, что игра переопределяет стейты рендера прямо перед моим кодом или использует специфический Z-Buffer. Плюс по мышке — как лучше прокинуть инпут в ImGui, если игра клала на стандартные оконные сообщения и рисует свой курсор поверх всего?
Кто сталкивался с похожим поведением рендера в DX9?
Суть проблемы:
- Рендер ImGui окон ведет себя неадекватно — они отрисовываются как будто внутри игровых окон или под ними, ломая нормальный Z-order.
- В игре реализована кастомная система мыши. Она не использует стандартный Windows курсор, из-за чего ImGui перекрывает его или вообще неадекватно обрабатывает позицию.
Техническая часть:
Для реализации использую Detours. Хукаю EndScene (индекс 42 в VTable) и Reset (индекс 16). Для инициализации девайса и получения HWND закинул хук на CreateWindowExA.
Код:
#ifndef MDirectx9_H
#define MDirectx9_H
#include <d3d9.h>
#include <windows.h>
#include "imgui.h"
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM);
typedef HRESULT(_stdcall* EndScene)(IDirect3DDevice9Ex*);
typedef HRESULT(_stdcall* Reset)(IDirect3DDevice9Ex*, D3DPRESENT_PARAMETERS*);
typedef HWND(WINAPI* CreateWindowExA_t)(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID);
class MDirectx9 {
public:
static MDirectx9& gInst() {
static MDirectx9 instance;
return instance;
}
MDirectx9(MDirectx9 const&) = delete;
void operator=(MDirectx9 const&) = delete;
void MDirectx9DX();
void UnMDirectx9DX();
private:
MDirectx9();
~MDirectx9();
CreateWindowExA_t oCreateWindowExA;
WNDPROC OWndProc;
EndScene oEndScene;
Reset oReset;
void GetD3D9Device(HWND hWnd);
void UnMDirectx9Window();
static HWND WINAPI MDirectx9CreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
static LRESULT WINAPI MDirectx9WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static HRESULT APIENTRY MDirectx9EndScene(IDirect3DDevice9Ex* D3D9Device);
static HRESULT APIENTRY MDirectx9Reset(IDirect3DDevice9Ex* pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters);
void StartImGui(IDirect3DDevice9Ex* pDevice);
};
#endif
Код:
#include "MDirectx9.h"
#include <imgui_impl_dx9.h>
#include <imgui_impl_win32.h>
#include "detours.h"
void MDirectx9::GetD3D9Device(HWND hWnd) {
IDirect3D9Ex* pD3D9Ex = nullptr;
IDirect3DDevice9Ex* pDevice = nullptr;
D3DPRESENT_PARAMETERS d3dpp = {};
Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D9Ex);
// ... создание девайса и получение VTable
void** pVTable = *reinterpret_cast<void***>(pDevice);
oEndScene = (EndScene)pVTable[42];
oReset = (Reset)pVTable[16];
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)oEndScene, MDirectx9EndScene);
DetourAttach(&(PVOID&)oReset, MDirectx9Reset);
DetourTransactionCommit();
}
Грешу на то, что игра переопределяет стейты рендера прямо перед моим кодом или использует специфический Z-Buffer. Плюс по мышке — как лучше прокинуть инпут в ImGui, если игра клала на стандартные оконные сообщения и рисует свой курсор поверх всего?
Кто сталкивался с похожим поведением рендера в DX9?