You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ DLL注入进程后Overlay绘制无显示问题排查与解决

三屏环境下DLL注入Overlay绘制不显示的解决方法

问题描述

将DLL注入目标进程后,在新线程创建Overlay窗口,主线程负责绘制内容。经检测绘制坐标值正确,但三屏显示环境下屏幕始终看不到绘制内容。

相关代码

maindll.cpp

uintptr_t mainModule = NULL;
bool visuals = false;
HWND hwndOverlay;

void DoMagic() {

    uintptr_t LocalPlayer = *(uintptr_t*)(mainModule + Offsets::dwLocalPlayerPawn);
    if (LocalPlayer == 0)
        return;

    if (GetAsyncKeyState(VK_F1) & 1)
    {
        visuals = !visuals;
    }

    if (hwndOverlay) {
        HDC hdcOverlay = GetDC(hwndOverlay);
        if (visuals) Visuals(mainModule, LocalPlayer, hdcOverlay);
    }

    Sleep(1);
}

DWORD WINAPI OverlayThread(LPVOID lpParam) {
    HMODULE hModule = (HMODULE)lpParam;
    hwndOverlay = CreateOverlayWindow(hModule);

    if (!hwndOverlay) {
        MessageBox(NULL, L"Error creating overlay window", L"Error", MB_ICONERROR);
        return 1;
    }

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

DWORD WINAPI MainFunc(HMODULE hModule) {
    AllocConsole();
    FILE* f;
    freopen_s(&f, "CONOUT$", "w", stdout);    

    CloseHandle(CreateThread(nullptr, 0, OverlayThread, hModule, 0, nullptr));

    mainModule = (uintptr_t)GetModuleHandle(L"client.dll");
    if (hModule)
    {
        while (!GetAsyncKeyState(VK_END) & 1) DoMagic();
    }
    else
    {
        std::cout << "Main module not found, press ENTER to exit..." << std::endl;
        getchar();
    }

    fclose(f);
    FreeConsole();
    FreeLibraryAndExitThread(hModule, 0);
    return 0;
}

CreateOverlayWindow()函数

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

HWND CreateOverlayWindow(HINSTANCE hInstance) {
    const wchar_t CLASS_NAME[] = L"OverlayClass";

    WNDCLASSEX wc = {};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
    wc.lpszClassName = CLASS_NAME;

    RegisterClassEx(&wc);

    HWND hwndOverlay = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED, CLASS_NAME, L"Overlay",
        WS_POPUP, 0, 0, 1920, 1080, nullptr, nullptr, hInstance, nullptr);

    SetLayeredWindowAttributes(hwndOverlay, RGB(0, 0, 0), 0, LWA_COLORKEY | LWA_ALPHA);

    ShowWindow(hwndOverlay, SW_SHOW);
    UpdateWindow(hwndOverlay);

    return hwndOverlay;
}

Visuals()核心代码

//Sets the Brush Color
HBRUSH Brush = (playerTeam == localPlayerTeam) ? hBrushGreen : hBrushRed;
COLORREF TextCOLOR = (playerTeam == localPlayerTeam) ? TextColorGreen : TextColorRed;

//Draws the box
DrawBorderBox(playerFeetInScreen.x + center, playerFeetInScreen.y, width, head - extra, 1, hdcOverlay, Brush);

//Draw our heath by converting a int to a char
char healthChar[255];
sprintf_s(healthChar, sizeof(healthChar), "%i", playerHealth);
DrawString(playerFeetInScreen.x, playerFeetInScreen.y, TextCOLOR, healthChar, Font, hdcOverlay);

解决步骤

1. 适配三屏环境的窗口位置与尺寸

当前Overlay固定创建在(0,0)位置且尺寸为1920x1080,三屏环境下大概率不在目标游戏所在屏幕,导致无法看到。需动态获取目标屏幕的区域:

HWND CreateOverlayWindow(HINSTANCE hInstance) {
    // ... 窗口类注册代码不变 ...

    // 获取目标游戏窗口(替换为实际游戏窗口标题或通过进程获取主窗口)
    HWND gameHwnd = FindWindow(nullptr, L"目标游戏窗口标题");
    RECT gameRect;
    GetWindowRect(gameHwnd, &gameRect);

    // 创建覆盖游戏窗口的Overlay
    HWND hwndOverlay = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED, CLASS_NAME, L"Overlay",
        WS_POPUP, gameRect.left, gameRect.top, gameRect.right - gameRect.left, gameRect.bottom - gameRect.top, 
        nullptr, nullptr, hInstance, nullptr);

    // ... 后续属性设置代码不变 ...
}

如果游戏是全屏模式,也可以直接获取当前显示器的分辨率:

int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);

2. 修复GDI资源泄漏问题

DoMagic中调用GetDC后未释放,会导致GDI资源耗尽,最终无法绘制。必须添加ReleaseDC:

void DoMagic() {
    // ... 其他代码不变 ...

    if (hwndOverlay) {
        HDC hdcOverlay = GetDC(hwndOverlay);
        if (visuals) Visuals(mainModule, LocalPlayer, hdcOverlay);
        ReleaseDC(hwndOverlay, hdcOverlay); // 释放设备上下文
    }

    // ... 其他代码不变 ...
}

3. 调整Overlay窗口透明度设置

当前SetLayeredWindowAttributes中LWA_ALPHA设为0会让整个窗口完全透明,导致绘制内容无法显示。仅保留颜色键透明即可:

SetLayeredWindowAttributes(hwndOverlay, RGB(0, 0, 0), 255, LWA_COLORKEY);

4. 确保窗口就绪后再绘制

添加窗口就绪标志,避免主线程在Overlay窗口未完全创建时就尝试绘制:

// 全局变量
bool overlayReady = false;

DWORD WINAPI OverlayThread(LPVOID lpParam) {
    HMODULE hModule = (HMODULE)lpParam;
    hwndOverlay = CreateOverlayWindow(hModule);

    if (!hwndOverlay) {
        MessageBox(NULL, L"Error creating overlay window", L"Error", MB_ICONERROR);
        return 1;
    }
    overlayReady = true; // 标记窗口就绪

    // ... 消息循环代码不变 ...

    overlayReady = false;
    return 0;
}

// DoMagic中修改判断逻辑
if (hwndOverlay && overlayReady) {
    HDC hdcOverlay = GetDC(hwndOverlay);
    if (visuals) Visuals(mainModule, LocalPlayer, hdcOverlay);
    ReleaseDC(hwndOverlay, hdcOverlay);
}

5. 校验绘制函数实现

确保DrawBorderBox和DrawString的实现正确,比如DrawBorderBox需正确使用传入的画刷:

void DrawBorderBox(int x, int y, int w, int h, int thickness, HDC hdc, HBRUSH brush) {
    RECT rect = {x, y, x + thickness, y + h};
    FillRect(hdc, &rect, brush);
    
    rect = {x + w - thickness, y, x + w, y + h};
    FillRect(hdc, &rect, brush);
    
    rect = {x, y, x + w, y + thickness};
    FillRect(hdc, &rect, brush);
    
    rect = {x, y + h - thickness, x + w, y + h};
    FillRect(hdc, &rect, brush);
}

DrawString需确保字体句柄有效,并正确设置文本颜色:

void DrawString(int x, int y, COLORREF color, const char* text, HFONT font, HDC hdc) {
    SetTextColor(hdc, color);
    SetBkMode(hdc, TRANSPARENT); // 背景透明
    HFONT oldFont = (HFONT)SelectObject(hdc, font);
    TextOutA(hdc, x, y, text, strlen(text));
    SelectObject(hdc, oldFont);
}

内容的提问来源于stack exchange,提问作者kuhi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 11:32:04