使用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+的初始化和销毁逻辑移到程序全局的启停节点,避免重复初始化:
- 在程序入口(如
WinMain函数开头、MFC框架的InitInstance方法中)仅执行一次GdiplusStartup,保存返回的token - 在程序退出前(如
WinMain返回前、MFC框架的ExitInstance方法中)调用一次GdiplusShutdown传入保存的token - 绘图函数中删除
GdiplusStartup和GdiplusShutdown的调用,直接使用GDI+接口绘制即可,也不需要额外限制Graphics的作用域
内容的提问来源于stack exchange,提问作者darek_911
相关产品推荐
相关产品推荐

