使用Image.FromHbitmap()构造Bitmap时,原始位图句柄多久可以被删除?

GBe*_*gen 5 .net system.drawing gdi+

从文档Image.FromHbitmap()http://msdn.microsoft.com/en-us/library/k061we7x%28VS.80%29.aspx:

FromHbitmap方法制作GDI位图的副本; 因此,您可以在创建新图像后立即使用GDIDeleteObject方法释放传入的GDI位图.

这非常明确地说明,一旦创建了Bitmap实例,就可以使用DeleteObject立即删除位图句柄.

Image.FromHbitmap()然而,看看使用Reflector 的实现,它表明它是围绕GDI +函​​数的一个非常薄的包装器GdipCreateBitmapFromHBITMAP().

有对GDI +平板API函数相当稀少的文档,但http://msdn.microsoft.com/en-us/library/ms533971%28VS.85%29.aspx表示,GdipCreateBitmapFromHBITMAP()对应于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调色板.

此外,可以在源代码中看到GdiPlusBitmap.h中GDI +的C++部分,所讨论的Bitmap::Bitmap()构造函数本身就是GdipCreateBitmapFromHBITMAP()来自平面API 的函数的包装器:

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

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

    SetNativeImage(bitmap);
}
Run Code Online (Sandbox Code Playgroud)

我不能轻易看到的是GdipCreateBitmapFromHBITMAP()这个功能的核心实现,但文档中的两个评论似乎是矛盾的..Net文档说我可以立即删除位图句柄,并且GDI +文档说必须保留位图句柄,直到删除包装对象,但两者都基于相同的GDI +函​​数.

此外,GDI +文档警告不要使用当前或之前选择到设备上下文中的源HBITMAP.虽然我可以理解为什么当前不应该将位图选择到设备上下文中,但我不明白为什么会出现使用先前选择到设备上下文中的位图的警告.这似乎会阻止使用标准GDI在内存中创建的GDI +位图.

所以,总结一下:

  1. 在处理.Net Bitmap对象之前,是否需要保留原始位图句柄?
  2. GDI +函​​数GdipCreateBitmapFromHBITMAP()是复制源位图还是只保留原始句柄?
  3. 为什么我不应该使用先前在设备上下文中选择的HBITMAP?

GBe*_*gen 2

根据经验,.Net 文档似乎是正确的。人们确实可以立即调用DeleteObject()传递到的 HBITMAP Image.FromHbitmap(),而且这样做似乎不会产生任何不良影响。

根据我通过对代码进行逆向工程所学到的知识,同样的情况也适用于 GDI+Bitmap::Bitmap()构造函数和 GDI+GdipCreateBitmapFromHBITMAP()函数,尽管这与已发布的文档相矛盾。

也许 GDI+ 文档过于保守 - 保留在未来版本中保留所提供的 HBITMAP 句柄的权利。如果 GDI+ 中发生这种变化,.Net 框架必须进行更改,以在将位图传递给 GDI+ 之前制作位图的副本,以保留其已发布的约定。