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

时间:2010-06-16 20:40:18

标签: .net gdi+ system.drawing

来自http://msdn.microsoft.com/en-us/library/k061we7x%28VS.80%29.aspxImage.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.aspx表示GdipCreateBitmapFromHBITMAP()对应Bitmap::Bitmap()构造函数,它带有HBITMAP和{{1}作为参数。

http://msdn.microsoft.com/en-us/library/ms536314%28VS.85%29.aspx HPALETTE构造函数的此版本的文档可以这样说:

  

您负责删除GDI位图和GDI调色板。但是,在删除GDI + Bitmap :: Bitmap对象或超出范围之前,不应删除GDI位图或GDI调色板。

     

不要将当前(或以前)选择的GDI位图或GDI调色板传递给GDI + Bitmap :: Bitmap构造函数。

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

GdipCreateBitmapFromHBITMAP()

我不能轻易看到的是inline Bitmap::Bitmap( IN HBITMAP hbm, IN HPALETTE hpal ) { GpBitmap *bitmap = NULL; lastResult = DllExports::GdipCreateBitmapFromHBITMAP(hbm, hpal, &bitmap); SetNativeImage(bitmap); } 的实现,这是此功能的核心,但文档中的两个评论似乎是矛盾的。 .Net文档说我可以立即删除位图句柄,并且GDI +文档说必须保留位图句柄,直到删除包装对象,但两者都基于相同的GDI +函​​数。

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

所以,总结一下:

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

1 个答案:

答案 0 :(得分:2)

根据经验,.Net文档似乎是正确的。确实可以立即在传递给DeleteObject()的HBITMAP上调用Image.FromHbitmap(),这样做似乎没有任何不良影响。

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

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