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

为什么将Gdiplus初始化代码移至OnPaint函数会触发访问违例报错

问题原因

这个异常是Gdiplus对象析构时机和Gdiplus资源释放顺序错误导致的,核心逻辑如下:

  • Gdiplus所有的对象创建、成员方法调用、对象销毁操作,都必须发生在GdiplusStartup调用之后、GdiplusShutdown调用之前。
  • 你写的OnPaint代码中,Graphics和Image都是栈上分配的局部对象,这类对象的析构时机是函数执行结束、准备返回前,而你的GdiplusShutdown调用写在了函数结束前的最后一行,执行顺序就变成了:
    • 调用GdiplusStartup初始化Gdiplus
    • 创建Graphics、Image对象
    • 调用GdiplusShutdown释放所有Gdiplus全局资源
    • 函数退出前执行Image、Graphics的析构函数,此时Gdiplus资源已经被完全释放,析构函数访问已释放的内存空间,就触发了access violation异常。
额外说明

Gdiplus本身是进程级别的组件,全局只需要初始化、销毁各一次即可,不需要每次触发WM_PAINT消息都重复执行初始化销毁逻辑:WM_PAINT触发频率非常高(窗口移动、大小调整、被遮挡后重新显示都会触发),重复初始化不仅会严重降低绘制性能,还会增加资源冲突的概率。

修复方案

推荐方案

保持原有逻辑,将GdiplusStartup放在WinMain函数入口处执行,GdiplusShutdown放在WinMain函数退出前执行,全局仅执行一次初始化和销毁。

临时兼容方案(不推荐)

如果你确实需要在OnPaint内部完成初始化销毁,可以通过增加独立作用域的方式,让Gdiplus对象在GdiplusShutdown执行前完成析构:

void OnPaint(HDC hdc) {
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    // 独立作用域包裹Gdiplus对象
    {
        Graphics graphics(hdc);
        Image theImg(L"C:/....bmp");
        //graphics.DrawImage(&theImg, 0, 0);
    }
    // 执行到此处时,Graphics和Image对象已经析构完成
    GdiplusShutdown(gdiplusToken);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 16:57:02