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

使用GDI+ API绘制图像时调用GdiplusShutdown触发访问违例如何解决

GDI+ 调用GdiplusShutdown触发访问违例问题原因及解决方案

异常触发原因

  • 核心原因是Graphics对象的生命周期和GDI+的初始化周期不匹配:你代码中的Graphics是栈上声明的局部变量,它的析构时机是整个函数执行完毕、退出大括号的时候,而你提前在函数末尾调用了GdiplusShutdown释放了所有GDI+核心资源,后续析构Graphics对象时需要访问已经被释放的GDI+资源,就触发了访问写违规异常。
  • 这个原因完全匹配你观察到的现象:
    • 注释掉Graphics相关代码后,没有需要析构的GDI+对象,所以调用GdiplusShutdown不会报错
    • 注释掉GdiplusShutdown后,GDI+资源不会被提前释放,Graphics析构时资源有效,所以也不会报错
  • 额外的不合理设计:GdiplusStartup和GdiplusShutdown是GDI+的全局初始化/销毁接口,不应该每次绘图都重复调用,频繁启停GDI+不仅会大幅降低绘制性能,还容易引发额外的资源冲突问题。

解决方案

临时修复(不改动全局初始化逻辑)

通过额外的大括号限制Graphics对象的作用域,确保它在GdiplusShutdown执行前就完成析构,修改后的代码如下:

void drawImg_ArmorInfo_PupupWnd(HDC hdc) {
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    Image* image = new Image(L"C:/Users/Darek/F2 stuff/art/intrface/armor_info_1.bmp");
    // 新增图片加载成功判断,避免空指针访问风险
    if (image->GetLastStatus() != Ok) {
        delete image;
        GdiplusShutdown(gdiplusToken);
        return;
    }
    int a1 = image->GetWidth();
    int a2 = image->GetHeight();
    // 额外大括号限定Graphics生命周期,确保销毁在GdiplusShutdown之前
    {
        Graphics graphics(hdc);
        graphics.DrawImage(image, 0, 0);
    }
    delete image;
    GdiplusShutdown(gdiplusToken);
}

最优修复

把GDI+的初始化和销毁逻辑移到程序全局的启停节点,避免重复初始化:

  1. 在程序入口(如WinMain函数开头、MFC框架的InitInstance方法中)仅执行一次GdiplusStartup,保存返回的token
  2. 在程序退出前(如WinMain返回前、MFC框架的ExitInstance方法中)调用一次GdiplusShutdown传入保存的token
  3. 绘图函数中删除GdiplusStartup和GdiplusShutdown的调用,直接使用GDI+接口绘制即可,也不需要额外限制Graphics的作用域

内容的提问来源于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 09:27:02