zoukankan      html  css  js  c++  java
  • C# .NET开发图形图像程序时提示"GDI+ 中发生一般性错误"

    今天突然收到一封信,说我那个极度复杂的Marshal的问题被解决了(http://www.cnblogs.com/hotcan/archive/2005/01/12/91007.html)。顿时感觉好久没有在这个blog上写东西了。想当年刚毕业没事情干的时候,还是写得很不亦乐乎的。所以决定炒炒冷饭,写一篇技术文章,以说明我还没有忘记这里。 

    1.GDI+的前世今生

    GDI+全称图形设备接口,Graphics Device Interface (GDI) ,他的爸爸叫做GDI, 用C写的。Windows XP出来以后用C++重新写了一下,变成了GDI+。从.NET Framework 1.0开始,GDI+就被正式封装在了.NET Framework里面,并被广泛地应用到了所有和图形图像相关的程序中。不幸的是,这个GDI+引入了微软有史以来最大的2个patch,造成了Microsoft IT, Support, Developer, Tester的无数麻烦。[1][2]

    GDI+没有用显卡加速,所以Windows Vista推荐用Windows Display Driver Model (WDDM)了,支持渲染,3D加速。不过普通的应用程序,用GDI/GDI+其实是完全足够了,所以GDI+是在微软平台上开发图形图像程序的最好选择了。至少现在没有听说微软准备重新写GDI

    GDI+ 可以用来做图形处理,也可以做图像处理。这里只分析几个使用.NET Framework容易出错的地方。 

    2. GDI+一般性错误(A generic error occurred in GDI+)

    这是使用GDI+的时候最滑稽的一个Exception,里面啥信息都没有。对于刚刚开始使用.NET Framework开发者来说,很难发现这个问题到底是为什么。

    我们先来看看下面一段代码 

    string fileName = "sample.jpg";
    Bitmap bmp = new Bitmap(fileName);
    bmp.Save(fileName, ImageFormat.Jpeg);

    这段代码的目的是要打开一个Bitmap,然后保存。可惜这段代码一定会给你一个GDI+一般性错误:

    System.Runtime.InteropServices.ExternalException

    其中的Error Code是0x80004005, innerException是空。如果你查Windows的Error Code表,会发现这个错误原因是“Unspecified Error”,还是什么都不知道。这其实是.NET Framework封装不好的问题,我们可以调用

    Marshal.GetLastWin32Error()

    拿到Win32的Error, 32。这个错误代码就有点信息量了,在winerror.h里面,我们可以找到下面的定义:

    //
    
    // MessageId: ERROR_SHARING_VIOLATION
    
    //
    
    // MessageText:
    
    //
    
    //  The process cannot access the file because it is being used by another process.
    
    //
    
    #define ERROR_SHARING_VIOLATION          32L

    原来是文件不能写。其实MSDN里面有一句话,The file remains locked until the Bitmap is disposed。所以文件读取以后是锁着的,没有办法写。那如果我想做点改动然后再保存原来的文件怎么办呢?

    这里有个土办法可以搞定这个问题 

    Bitmap bmpTemp = new Bitmap(image);
    Bitmap bmp = new Bitmap(bmpTemp);
    bmpTemp.Dispose();
    bmp.Save(image, ImageFormat.Jpeg);

    只要把当前的图像复制一份,然后把旧的Dispose掉,那个文件就不被锁住了,这样就可以放心覆盖原始文件了。

    想想如果你要用GDI+写一个Painter,很容易你就会遇到这个问题。 此种情况是因为图片被占用导致锁定,保存前使用 Graphics.DrawImage() 复制一份,然后dispose释放掉锁定就ok了~

    参考文献:

    [1]. Microsoft Security Bulletin MS04-028 Buffer Overrun in JPEG Processing (GDI+) Could Allow Code Execution (833987) http://www.microsoft.com/technet/security/bulletin/MS04-028.mspx

    [2].Microsoft Security Bulletin MS08-052 – Critical Vulnerabilities in GDI+ Could Allow Remote Code Execution (954593)http://www.microsoft.com/technet/security/bulletin/MS08-052.mspx

    原文链接:

    GDI+中常见的几个问题(1)

    GDI+ 中发生一般性错误

  • 相关阅读:
    共享纸巾更换主板代码分析 共享纸巾主板更换后的对接代码
    Python Django Ajax 传递列表数据
    Python Django migrate 报错解决办法
    Python 创建字典的多种方式
    Python 两个list合并成一个字典
    Python 正则 re.sub替换
    python Django Ajax基础
    Python Django 获取表单数据的三种方式
    python Django html 模板循环条件
    Python Django ORM 字段类型、参数、外键操作
  • 原文地址:https://www.cnblogs.com/rainbow70626/p/5149344.html
Copyright © 2011-2022 走看看