2010-06-16 73 views
5

Image.FromHbitmap()http://msdn.microsoft.com/en-us/library/k061we7x%28VS.80%29.aspx的文檔:使用Image.FromHbitmap()構造位圖時,原始位圖句柄多久可以刪除?

的FromHbitmap方法使GDI位圖的副本;因此您可以在創建新映像後立即使用GDIDeleteObject方法釋放傳入的GDI位圖。

這非常明確地規定,只要Bitmap實例被創建,位圖句柄就可以立即用DeleteObject刪除。

然而,使用Reflector查看Image.FromHbitmap()的實現,表明它是GDI +函​​數GdipCreateBitmapFromHBITMAP()的一個很薄的包裝。

上有GDI +平坦API函數相當稀少的文檔,但http://msdn.microsoft.com/en-us/library/ms533971%28VS.85%29.aspxGdipCreateBitmapFromHBITMAP()對應於Bitmap::Bitmap()構造函數的HBITMAPHPALETTE作爲參數。

http://msdn.microsoft.com/en-us/library/ms536314%28VS.85%29.aspx此版本的Bitmap::Bitmap()構造函數的文檔中有這樣一段話:

您有責任刪除GDI的位圖和GDI調色板。但是,直到GDI + Bitmap :: Bitmap對象被刪除或超出範圍之後,才能刪除GDI位圖或GDI調色板。

不要傳遞給GDI +位圖::位圖構造函數當前(或之前)已選擇到設備上下文中的GDI位圖或GDI調色板。

此外,可以在用於C源代碼看到++ GDI +在GdiPlusBitmap.h的一部分,該Bitmap::Bitmap()構造中的問題是本身爲從平坦API的GdipCreateBitmapFromHBITMAP()函數的包裝:

inline 
Bitmap::Bitmap(
    IN HBITMAP hbm, 
    IN HPALETTE hpal 
    ) 
{ 
    GpBitmap *bitmap = NULL; 

    lastResult = DllExports::GdipCreateBitmapFromHBITMAP(hbm, hpal, &bitmap); 

    SetNativeImage(bitmap); 
} 

我不能輕易看到的是GdipCreateBitmapFromHBITMAP()的實現,這是該功能的核心,但文檔中的兩個觀點似乎是相互矛盾的。 .Net文檔說我可以立即刪除位圖句柄,並且GDI +文檔說,位圖句柄必須保留直到包裝對象被刪除,但兩者都基於相同的GDI +函​​數。

此外,GDI +文檔警告不要使用當前或先前選擇到設備上下文中的源HBITMAP。雖然我可以理解爲什麼當前不應將位圖選擇到設備上下文中,但我不明白爲什麼會有使用先前選擇到設備上下文中的位圖的警告。這似乎阻止了使用標準GDI在內存中創建的GDI +位圖。

因此,簡言之:

  1. 是否原始位手柄需要被周圍,直到淨位圖對象設置保存?
  2. GDI +函​​數GdipCreateBitmapFromHBITMAP()是否創建源位圖的副本或僅保留原始句柄?
  3. 爲什麼我不應該使用先前選擇到設備上下文中的HBITMAP?
+0

同意衝突。本地位圖構造函數文檔必須是僞造的。 – 2010-06-17 05:15:46

回答

2

經驗上,似乎.Net文檔是正確的。確實可以立即在HBITMAP上呼叫DeleteObject()傳遞給Image.FromHbitmap(),並且看起來沒有不良影響。

基於我通過逆向工程學習到的代碼,這同樣適用於GDI + Bitmap::Bitmap()構造函數和GDI + GdipCreateBitmapFromHBITMAP()函數,儘管這與發佈的文檔相矛盾。

也許GDI +文檔過於保守 - 保留在未來版本中保留提供的HBITMAP句柄的權利。如果在GDI +中發生這種變化,那麼.Net框架將不得不改變,以便在將它傳遞給GDI +之前複製位圖來保留其已發佈的合同。