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

C#触发含GDI+错误的System.Reflection.TargetInvocationException异常排查

问题解决:C# GDI+ 通用错误(ExternalException)

该异常和集合长度为23完全无关,A generic error occurred in GDI+ 90%以上的触发原因是资源未释放、文件被占用、路径权限不足三类,结合你提供的代码,具体问题和修复方案如下:

核心问题点

  • 重复执行逻辑导致文件占用:你同时为WebClient注册了DownloadFileCompleted和DownloadDataCompleted两个回调,两个回调中写了完全一致的遍历图片调用DrawText的逻辑,两类下载任务都完成时,两个回调会先后/同时执行,同一个图片文件被两个线程同时打开写入,直接触发GDI+报错
  • GDI资源未显式释放:不管是DrawText方法内加载的图片,还是下载卫星图时创建的Image对象,都没有主动释放非托管资源,GDI+资源不会被GC自动及时回收,操作到最后一个文件时资源耗尽、文件句柄未释放就会触发异常
  • 回调逻辑冗余:你已经使用了await异步任务写法,完全不需要依赖Completed事件处理后续逻辑,下载循环走完后直接执行后续绘制逻辑即可,从根源避免多回调冲突

修复步骤

  1. 删掉所有DownloadFileCompleted、DownloadDataCompleted的回调注册代码,将回调内的后续逻辑直接搬到for循环下载全部完成之后,避免重复执行
  2. 所有Image对象都用using包裹,确保用完立即释放资源,下载卫星图的代码修改为:
using (MemoryStream ms = new MemoryStream(await client.DownloadDataTaskAsync(new Uri(urls[i]))))
using (Image img = Image.FromStream(ms, true))
{
    img.Save(satelliteFolderImagesDownload + "\\image" + satCounter + ".gif", System.Drawing.Imaging.ImageFormat.Gif);
}
  1. 改造DrawText方法,确保内部加载的图片、画布、画笔等所有GDI对象都用using包裹,同时避免保存时原文件被占用,示例如下:
public void DrawText(string text, string imagePath)
{
    using (Image img = Image.FromFile(imagePath))
    using (Graphics g = Graphics.FromImage(img))
    using (Font font = new Font("Arial", 12))
    using (Brush brush = Brushes.Black)
    {
        g.DrawString(text, font, brush, new PointF(10, 10));
        // 先写到内存流,释放原图片对象后再覆盖文件,避免占用报错
        using (MemoryStream ms = new MemoryStream())
        {
            img.Save(ms, img.RawFormat);
            ms.Position = 0;
            using (FileStream fs = new FileStream(imagePath, FileMode.Create, FileAccess.Write))
            {
                ms.CopyTo(fs);
            }
        }
    }
}
  1. 若你需要保留Completed事件逻辑,必须加锁避免两个回调同时执行文件操作,或者只保留一个回调的处理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:15:05