ImGui Window 未在 DLL 注入中显示
ImGui Window doesn't show on DLL Injection
- 当前目标: 尝试将自定义代码注入 DirectX11 游戏以显示 windows。
- 预期结果: ImGui 演示 Window 应该在注入后显示,但不应交互
- 得到的结果: ImGui 演示 Window 在注入时没有显示或显示任何内容。
我尝试过的事情: 制作自定义 Imgui window 并重新注入,调试代码以确保它被 运行 并被调用每一帧,确保没有任何内容为 NULL,在 google、ImGui GitHub、stack overflow.
上搜索我的问题
D3D11 Init(注入后调用的第一件事)
LRESULT CALLBACK DXGIMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hwnd, uMsg, wParam, lParam); }
DWORD __stdcall D3D11Init() {
// Create Dummy Window
WNDCLASSEXA wc = { sizeof(WNDCLASSEX), CS_CLASSDC, DXGIMsgProc, 0L, 0L, GetModuleHandleA(NULL), NULL, NULL, NULL, NULL, "DX", NULL };
RegisterClassExA(&wc);
HWND hWnd = CreateWindowA("DX", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, NULL, NULL, wc.hInstance, NULL);
D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1 };
D3D_FEATURE_LEVEL obtainedLevel;
DXGI_SWAP_CHAIN_DESC sd;
{
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.OutputWindow = hWnd;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.SampleDesc.Count = 1;
}
HRESULT hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, levels, sizeof(levels) / sizeof(D3D_FEATURE_LEVEL), D3D11_SDK_VERSION, &sd, &d3dSwapChain, &d3dDevice, &obtainedLevel, &d3dContext);
if (FAILED(hr))
{
return E_FAIL;
}
pSwapChainVTable = (DWORD_PTR*)(d3dSwapChain);
pSwapChainVTable = (DWORD_PTR*)(pSwapChainVTable[0]);
pDeviceVTable = (DWORD_PTR*)(d3dDevice);
pDeviceVTable = (DWORD_PTR*)pDeviceVTable[0];
pDeviceContextVTable = (DWORD_PTR*)(d3dContext);
pDeviceContextVTable = (DWORD_PTR*)(pDeviceContextVTable[0]);
SAFE_RELEASE(d3dSwapChain);
SAFE_RELEASE(d3dDevice);
SAFE_RELEASE(d3dContext);
UnregisterClassA(wc.lpszClassName, wc.hInstance);
if (MH_Initialize() != MH_OK) { return 1; }
if (MH_CreateHook((DWORD_PTR*)pSwapChainVTable[8], PresentHook, reinterpret_cast<void**>(&pHookD3D11Present)) != MH_OK) { return 1; }
if (MH_EnableHook((DWORD_PTR*)pSwapChainVTable[8]) != MH_OK) { return 1; }
DWORD old_protect;
VirtualProtect(pHookD3D11Present, 2, PAGE_EXECUTE_READWRITE, &old_protect);
}
PresentHook(每次游戏调用Present Function时调用)
HRESULT __stdcall PresentHook(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) {
if(!init) {
std::cout << "\t[+] Present Hook called First Time!" << std::endl;
if (FAILED(GetDeviceAndCtxFromSwapChain(pSwapChain, &d3dDevice, &d3dContext)))
return pHookD3D11Present(pSwapChain, SyncInterval, Flags);
// Get Game Window Handle
DXGI_SWAP_CHAIN_DESC sd;
pSwapChain->GetDesc(&sd);
window = sd.OutputWindow;
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void) io;
io.IniFilename = NULL;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.DisplaySize = ImVec2(1280, 720);
ImGui_ImplWin32_Init(window);
ImGui_ImplDX11_Init(d3dDevice, d3dContext);
init = true;
};
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
ImGui::ShowDemoWindow();
ImGui::EndFrame();
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
return pHookD3D11Present(pSwapChain, SyncInterval, Flags);
}
问题是获取当前的 D3D11RenderTargetView 或创建我自己的 D3D11RenderTargetView。添加下面的部分功能或创建一个全新的功能并将其添加到 Present Init 应该可以解决 ImGui 不显示的问题。
bool GetDeivceContextRenderTarget(IDXGISwapChain* pSwapChain)
{
HRESULT hr = pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&pDevice);
if (FAILED(hr))
return false;
pDevice->GetImmediateContext(&pContext);
pContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);
// If for some reason we fail to get a render target, create one
if (!pRenderTargetView) {
ID3D11Texture2D* pBackBuffer = nullptr;
hr = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer));
if (FAILED(hr))
return false;
hr = pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &pRenderTargetView);
pBackBuffer->Release();
if (FAILED(hr))
return false;
// Make sure our render target is set, only needed if creating our own, if already exist use original
pContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);
}
return true;
}
- 当前目标: 尝试将自定义代码注入 DirectX11 游戏以显示 windows。
- 预期结果: ImGui 演示 Window 应该在注入后显示,但不应交互
- 得到的结果: ImGui 演示 Window 在注入时没有显示或显示任何内容。
我尝试过的事情: 制作自定义 Imgui window 并重新注入,调试代码以确保它被 运行 并被调用每一帧,确保没有任何内容为 NULL,在 google、ImGui GitHub、stack overflow.
上搜索我的问题D3D11 Init(注入后调用的第一件事)
LRESULT CALLBACK DXGIMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hwnd, uMsg, wParam, lParam); }
DWORD __stdcall D3D11Init() {
// Create Dummy Window
WNDCLASSEXA wc = { sizeof(WNDCLASSEX), CS_CLASSDC, DXGIMsgProc, 0L, 0L, GetModuleHandleA(NULL), NULL, NULL, NULL, NULL, "DX", NULL };
RegisterClassExA(&wc);
HWND hWnd = CreateWindowA("DX", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, NULL, NULL, wc.hInstance, NULL);
D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1 };
D3D_FEATURE_LEVEL obtainedLevel;
DXGI_SWAP_CHAIN_DESC sd;
{
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.OutputWindow = hWnd;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.SampleDesc.Count = 1;
}
HRESULT hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, levels, sizeof(levels) / sizeof(D3D_FEATURE_LEVEL), D3D11_SDK_VERSION, &sd, &d3dSwapChain, &d3dDevice, &obtainedLevel, &d3dContext);
if (FAILED(hr))
{
return E_FAIL;
}
pSwapChainVTable = (DWORD_PTR*)(d3dSwapChain);
pSwapChainVTable = (DWORD_PTR*)(pSwapChainVTable[0]);
pDeviceVTable = (DWORD_PTR*)(d3dDevice);
pDeviceVTable = (DWORD_PTR*)pDeviceVTable[0];
pDeviceContextVTable = (DWORD_PTR*)(d3dContext);
pDeviceContextVTable = (DWORD_PTR*)(pDeviceContextVTable[0]);
SAFE_RELEASE(d3dSwapChain);
SAFE_RELEASE(d3dDevice);
SAFE_RELEASE(d3dContext);
UnregisterClassA(wc.lpszClassName, wc.hInstance);
if (MH_Initialize() != MH_OK) { return 1; }
if (MH_CreateHook((DWORD_PTR*)pSwapChainVTable[8], PresentHook, reinterpret_cast<void**>(&pHookD3D11Present)) != MH_OK) { return 1; }
if (MH_EnableHook((DWORD_PTR*)pSwapChainVTable[8]) != MH_OK) { return 1; }
DWORD old_protect;
VirtualProtect(pHookD3D11Present, 2, PAGE_EXECUTE_READWRITE, &old_protect);
}
PresentHook(每次游戏调用Present Function时调用)
HRESULT __stdcall PresentHook(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) {
if(!init) {
std::cout << "\t[+] Present Hook called First Time!" << std::endl;
if (FAILED(GetDeviceAndCtxFromSwapChain(pSwapChain, &d3dDevice, &d3dContext)))
return pHookD3D11Present(pSwapChain, SyncInterval, Flags);
// Get Game Window Handle
DXGI_SWAP_CHAIN_DESC sd;
pSwapChain->GetDesc(&sd);
window = sd.OutputWindow;
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void) io;
io.IniFilename = NULL;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.DisplaySize = ImVec2(1280, 720);
ImGui_ImplWin32_Init(window);
ImGui_ImplDX11_Init(d3dDevice, d3dContext);
init = true;
};
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
ImGui::ShowDemoWindow();
ImGui::EndFrame();
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
return pHookD3D11Present(pSwapChain, SyncInterval, Flags);
}
问题是获取当前的 D3D11RenderTargetView 或创建我自己的 D3D11RenderTargetView。添加下面的部分功能或创建一个全新的功能并将其添加到 Present Init 应该可以解决 ImGui 不显示的问题。
bool GetDeivceContextRenderTarget(IDXGISwapChain* pSwapChain)
{
HRESULT hr = pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&pDevice);
if (FAILED(hr))
return false;
pDevice->GetImmediateContext(&pContext);
pContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);
// If for some reason we fail to get a render target, create one
if (!pRenderTargetView) {
ID3D11Texture2D* pBackBuffer = nullptr;
hr = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer));
if (FAILED(hr))
return false;
hr = pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &pRenderTargetView);
pBackBuffer->Release();
if (FAILED(hr))
return false;
// Make sure our render target is set, only needed if creating our own, if already exist use original
pContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);
}
return true;
}