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

C++中Overlay类addLabel方法仅在main函数生效问题排查

桌面文字覆盖层闪烁问题修复

问题场景

实现桌面上层绘制文字功能时出现异常:

  • 在main函数直接调用ol.addLabel(),标签能正常持续显示
  • 在其他函数(如notWorking)或类内部调用addLabel(),标签仅闪烁一下就消失

相关代码如下:

main.cpp

#include "OVERLAY.h"
void notWorking(Overlay &ol)
{
    ol.addLabel(100, 100, L"ASDASDASD", RGB(255, 0, 0));
}
int main()
{
    Overlay ol;

    ol.addLabel(100, 100, L"ASDASDASD", RGB(255, 0, 0));
    //notWorking(ol);
    
    for (;;)
    {
        ol.drawAll();
    }
}

Overlay类

class Overlay
{
private:
    std::vector<Label> labels;
    HDC hdc;
    
public:
    void addLabel(int x, int y, std::wstring title, COLORREF clr)
    {
        Label label;
        label.create(x, y, title, hdc, clr);
        label.draw(2); 
        labels.push_back(label);
    }
    
    void drawAll()
    {   
        for (int i =0; i < labels.size(); i++)
            labels[i].draw();   
    }

    Overlay()
    {   
        hdc = GetDC(GetDesktopWindow());    
    }
};

Label类

class Label
{
    int x, y;
    std::wstring txt;
    HDC* wdc;
    COLORREF color;
public:
    Label()
    {
    }
    void create(int x, int y, std::wstring text, HDC wdc, COLORREF color)
    {
        this->x = x;
        this->y = y;
        this->txt = text;
        this->wdc = &wdc;
        this->color = color;
    }
    void draw(int state = 1)
    {
        RECT rect;

        SetTextColor(*wdc, color);
        
        SetBkMode(*wdc, state); 
        rect.left = x;
        rect.top = y;

        DrawText(*wdc, txt.c_str(), -1, &rect, DT_NOCLIP);
    }
};

问题根源

  1. Label类的HDC指针失效:
    在Label::create()中,this->wdc = &wdc保存的是函数参数wdc的地址,该参数是Overlay::addLabel()传入的局部拷贝。当addLabel()执行完毕,局部参数被销毁,Label对象中的wdc指针变为野指针。

    • main中直接调用时,addLabel()执行后立刻进入循环调用drawAll(),此时局部参数内存暂未被覆盖,能短暂正常工作;
    • 其他函数调用时,函数返回后局部参数内存被释放/覆盖,后续drawAll()访问野指针导致绘制失效,标签闪烁后消失。
  2. Overlay::addLabel()执行顺序问题:
    先调用label.draw(2)再labels.push_back(label),此时绘制用的是局部label对象的有效指针,但拷贝到vector中的Label对象已携带失效指针,后续循环绘制必然出错。

修复方案

1. 修改Label类,使用HDC句柄而非指针

HDC是系统句柄,属于值类型,可直接拷贝存储:

class Label
{
    int x, y;
    std::wstring txt;
    HDC wdc;  // 改为直接存储HDC,而非指针
    COLORREF color;
public:
    Label() {}

    void create(int x, int y, std::wstring text, HDC wdc, COLORREF color)
    {
        this->x = x;
        this->y = y;
        this->txt = text;
        this->wdc = wdc;  // 直接赋值句柄
        this->color = color;
    }

    void draw(int state = 1)
    {
        RECT rect;

        SetTextColor(wdc, color);  // 直接使用wdc,无需解引用
        
        SetBkMode(wdc, state); 
        rect.left = x;
        rect.top = y;

        DrawText(wdc, txt.c_str(), -1, &rect, DT_NOCLIP);
    }
};

2. 调整Overlay::addLabel()执行顺序

先将Label对象存入vector,再进行绘制,确保使用vector中有效对象的句柄:

void addLabel(int x, int y, std::wstring title, COLORREF clr)
{
    Label label;
    label.create(x, y, title, hdc, clr);
    labels.push_back(label);
    labels.back().draw(2);  // 使用vector中刚存入的对象绘制
}

3. 补充:释放DC句柄(可选但推荐)

在Overlay类析构函数中释放桌面DC,避免资源泄漏:

~Overlay()
{
    ReleaseDC(GetDesktopWindow(), hdc);
}

修复后效果

修改后,无论在main函数还是其他函数中调用addLabel(),标签都能正常持续显示,不会出现闪烁消失的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:57:45