Things I have tried: Making a custom Imgui window and reinjecting, debugging the code to make sure it's being run and is called every frame, making sure nothing is NULL, searching up my problem on google, ImGui GitHub, stack overflow.
D3D11 Init (Called First thing after injection)
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 (Called everytime the game calls 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);
}
The problem was getting the current D3D11RenderTargetView or creating my own D3D11RenderTargetView. Adding parts of the function below or creating a whole new function and adding it to Present Init should fix the problem of ImGui not displaying.
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;
}