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); } };
问题根源
Label类的HDC指针失效:
在Label::create()中,this->wdc = &wdc保存的是函数参数wdc的地址,该参数是Overlay::addLabel()传入的局部拷贝。当addLabel()执行完毕,局部参数被销毁,Label对象中的wdc指针变为野指针。main中直接调用时,addLabel()执行后立刻进入循环调用drawAll(),此时局部参数内存暂未被覆盖,能短暂正常工作;- 其他函数调用时,函数返回后局部参数内存被释放/覆盖,后续
drawAll()访问野指针导致绘制失效,标签闪烁后消失。
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
相关产品推荐
相关产品推荐

