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

WM_CTLCOLORSTATIC中创建的自定义画笔如何正确释放以避免资源泄漏?

WM_CTLCOLORSTATIC中创建的自定义画笔如何正确释放以避免资源泄漏?

这个问题我做Win32原生界面时也踩过一模一样的坑!你现在的代码逻辑最大的问题是:每次WM_CTLCOLORSTATIC消息触发时,你都调用CreateSolidBrush生成新的画笔,然后直接返回它——Windows会用这个画笔完成绘制,但不会帮你自动销毁它。而WM_CTLCOLORSTATIC会被频繁触发(控件重绘、窗口刷新、甚至鼠标移过时都可能发这个消息),日积月累就会造成GDI资源泄漏,严重的话还会导致界面绘制异常。

正确的解决思路:把画笔的创建和释放从消息处理中抽离

要解决这个问题,核心是提前创建好自定义画笔,重复使用同一个画笔句柄,最后在窗口销毁时统一释放,而不是每次消息都新建。具体步骤如下:

1. 先声明变量保存画笔句柄

你需要在窗口的上下文里保存自定义画笔的句柄,比如用全局变量(单窗口场景下)或者把它存在窗口的附加数据结构中:

// 可以放在窗口回调函数外作为全局变量,或者封装到窗口的自定义数据里
HBRUSH hTextBoxBrush = NULL;
HBRUSH hInfoBoxBrush = NULL;

2. 在窗口初始化时创建画笔

在窗口创建的WM_CREATE消息中,一次性创建好需要的自定义画笔(注意要确保colorbkgnd01此时已经有正确的初始值):

case WM_CREATE:
    // 创建文本框的自定义背景画笔
    hTextBoxBrush = CreateSolidBrush(0xBEBEBE);
    // 创建infoBox01的自定义背景画笔
    hInfoBoxBrush = CreateSolidBrush(colorbkgnd01);
    break;

3. 修改WM_CTLCOLORSTATIC的处理逻辑,返回预先创建的画笔

现在不需要每次消息触发都新建画笔,直接返回之前创建好的句柄即可:

case WM_CTLCOLORSTATIC:
{
    HDC hdc = (HDC)wParam;
    HWND hwndStatic = (HWND)lParam;

    if (hwndStatic == *phwndTextBox)
    {
        SetTextColor(hdc, 0x000000);
        SetBkColor(hdc, 0xBEBEBE);
        // 返回预先创建的画笔,而非每次新建
        return (LRESULT)hTextBoxBrush;
    }
    if (hwndStatic == *phwndinfoBox01)
    {
        SetTextColor(hdc, 0x000000);
        SetBkColor(hdc, colorbkgnd01);
        // 同样返回预先创建的画笔
        return (LRESULT)hInfoBoxBrush;
    }
}
break;

4. 在窗口销毁时释放画笔资源

最后,在窗口收到WM_DESTROY消息时,一定要用DeleteObject释放这些自定义画笔,彻底避免泄漏:

case WM_DESTROY:
    // 释放文本框的画笔
    if (hTextBoxBrush != NULL)
    {
        DeleteObject(hTextBoxBrush);
        hTextBoxBrush = NULL;
    }
    // 释放infoBox01的画笔
    if (hInfoBoxBrush != NULL)
    {
        DeleteObject(hInfoBoxBrush);
        hInfoBoxBrush = NULL;
    }
    PostQuitMessage(0);
    break;

额外补充:动态修改画笔颜色的情况

如果你的colorbkgnd01是动态变化的(比如用户可以在运行时修改背景色),那需要在颜色变更时,先销毁旧的画笔,再创建新的,同时触发控件重绘让新颜色生效:

// 当colorbkgnd01需要更新时的代码示例
if (hInfoBoxBrush != NULL)
{
    // 先销毁旧画笔,避免泄漏
    DeleteObject(hInfoBoxBrush);
}
// 创建新颜色的画笔
hInfoBoxBrush = CreateSolidBrush(newColorValue);
// 触发infoBox01控件重绘,让新颜色立即生效
InvalidateRect(*phwndinfoBox01, NULL, TRUE);

为什么GetStockObject不会泄漏?

你提到用GetStockObject(比如LTGRAY_BRUSH)不会泄漏,这是因为库存画笔是系统全局管理的资源,不用我们手动调用DeleteObject释放,Windows会负责它们的生命周期。但库存对象的颜色是固定的,没法满足自定义颜色的需求,所以需要自定义颜色时,还是得用上面的方法。

验证泄漏是否解决

你可以用Windows自带的任务管理器验证:打开任务管理器→找到你的进程→右键→「转到详细信息」→右键列→「选择列」→勾选「GDI对象」。如果修改后的代码运行时,GDI对象数量不再持续增长,就说明泄漏问题解决了。

备注:内容来源于stack exchange,提问作者PeterS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:08:10