ImGui Window 未在 DLL 注入中显示

ImGui Window doesn't show on DLL Injection

我尝试过的事情: 制作自定义 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;
}