在类库之间传递System.Drawing.Bitmap是否不可靠?

5
我有一个第三方dll,它生成一个位图并返回其引用。如果我立即将其生成为System.Windows.Media.Imaging.BitmapSource,则一切都正常。但是,如果我保存引用,稍后(几秒钟和许多函数调用之后)尝试生成Bitmapsource,则会出现以下错误: System.AccessViolationException was unhandled by user code
Message=尝试读取或写入受保护的内存。这通常表明其他内存已损坏。 Source="System.Drawing"
在执行以下操作时:
System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
    bmp.GetHbitmap(),
    IntPtr.Zero,
    Int32Rect.Empty,
    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

有没有任何线索表明出了什么问题?有任何指点将非常有用。谢谢。
2个回答

4
我认为这表明由 bmp.GetHBitmap 返回的句柄(对操作系统管理的资源的引用,而不是 .Net)不再有效 - 可能已经调用了 Dispose 或类似的方法(但不一定是由您的代码调用的)。
我建议使用另一种不依赖于句柄的持久化位图数据的方法 - 可能是立即将位图本身的二进制数据流输出,然后传递该引用。

3

我曾经遇到过位图和访问冲突的大问题。我认为发生的情况是某些位图构造函数在不应该的情况下保留了文件句柄。因此,你运行的程序会检测到文件正在使用中,但实际上不应该这样。

最终我找到了一个解决方案,即复制原始位图,然后处理原始位图。以下是我的代码,它可以保留原始位图的分辨率:

Bitmap Temp = new Bitmap(inFullPathName);
Bitmap Copy = new Bitmap(Temp.Width, Temp.Height);
Copy.SetResolution(Temp.HorizontalResolution, Temp.VerticalResolution);
using (Graphics g = Graphics.FromImage(Copy))
{
     g.DrawImageUnscaled(Temp, 0, 0);
}
Temp.Dispose();
return Copy;

显然,对于第一行,您的代码将是Bitmap Temp = MyThirdPartyDLL.GetBitmap();或类似的内容。如果您不关心分辨率,可以简化为:
Bitmap Temp = MyThirdPartyDLL.GetBitmap();
Bitmap Copy = new Bitmap(Temp, Temp.Width, Temp.Height);
Temp.Dispose();
return Copy;

在进行了这个更改之后,我能够完美地进行各种文件I/O等操作,希望您也能做到同样的效果。


抱歉,它与文件处理无关。请参见Andras的答案以获取正确的解释。但是,我喜欢你为解决缺陷而复制位图的解决方案(+1)。如果mishal153的内部数据结构需要位图而不是BitmapSource,则应使用您发布的代码。如果不是,他最好立即创建BitmapSource,而不是创建新的位图。 - Ray Burns
1
嗨,Brandi,你的建议就像一首歌:)。谢谢! 我也在尝试做同样的事情,但我是这样做的:'newBmp = oldBmp.Clone();' Clone 的文档说“创建此图像的精确副本。”,所以我认为我已经做了深拷贝。真正令人困惑的是 Bitmap 构造函数的文档说“从指定的现有图像初始化 Bitmap 类的新实例”,听起来像是只包装现有图像,而实际上它正在进行深拷贝 :)。这只是我还是其他人也感到困惑。 谢谢大家。 - mishal153

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接