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,很容易你就會遇到這個問題。
(To be continued)
[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