29

长时间运行我的 Windows 窗体应用程序时,有时会出现此异常:

System.ComponentModel.Win32Exception: The operation completed successfully
   at System.Drawing.BufferedGraphicsContext.CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, Int32 ulWidth, Int32 ulHeight, IntPtr& ppvBits)
   at System.Drawing.BufferedGraphicsContext.CreateBuffer(IntPtr src, Int32 offsetX, Int32 offsetY, Int32 width, Int32 height)
   at System.Drawing.BufferedGraphicsContext.AllocBuffer(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
   at System.Drawing.BufferedGraphicsContext.AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
   at System.Drawing.BufferedGraphicsContext.Allocate(IntPtr targetDC, Rectangle targetRectangle)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.DataGridView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

这可能是什么原因?

4

8 回答 8

24

总结一下,我写的自定义网格,基于.Net的DataGridView,使用自定义代码来绘制单元格。我的网格中的行可以跨越多个可视页面。(这是业务需求)

问题是 .Net 为启用了 DoubleBuffering 的控件预先分配了一个内存缓冲区。对于 DataGridViews 网格,缓冲区需要相当大以容纳网格中可能的大行。在极端情况下,一行最多可以跨越 32000 个像素(由于 .net 的限制)。项目中的网格宽度通常在 500 到 800 像素之间。所以生成的缓冲区可以是 (32bpp * 800 * 32000 = ~100MB)

所以简而言之,系统无法创建兼容的图形对象,因为有时它无法保留足够大的缓冲区来容纳所需的数据。

为了解决这个问题,我不得不引入一系列优化:

  • 我的自定义网格中允许的最大行高限制为 1500 像素
  • 更新了缓冲区重新分配代码,仅在新缓冲区大小大于现有缓冲区时执行
  • 确保缓冲区不会在每个数据绑定中重新分配,并预先分配到合理的大小。
  • 查看所有代码并确保在不使用时正确处理非托管资源,如下所示:http: //nomagichere.blogspot.com/2008/03/systemcomponentmodelwin32exception-is.html
于 2011-01-10T15:23:26.463 回答
16

Windows 对每个进程有10000 个句柄的硬性限制。相当无用的异常“操作成功完成”可能表明已达到此限制。

如果这是因为您的代码中的资源泄漏而发生的,那么您很幸运,因为您至少有机会修复您的代码。

不幸的是,对于 WinForms 内部创建的句柄,您几乎无能为力。例如,TreeView 控件大量创建字体句柄使其难以在需要在 UI 中表示非常大的树的场景中使用。

一些有用的链接:

http://support.microsoft.com/kb/327699 http://nomagichere.blogspot.com/2008/03/systemcomponentmodelwin32exception-is.html

于 2011-06-21T16:22:37.953 回答
3

它在极端情况下是由不处理图像引起的。您应该在加载位图时使用 IDisposable 来克服这个问题;

using(Bitmap b = Bitmap.FromFile("myfile.jpg"))
{
   //Do whatever
}
于 2010-12-08T18:41:20.913 回答
3

在创建一个巨大的 PictureBox 时,我曾经遇到过类似的异常。似乎我无法分配足够大的图形。实际上,我所做的是为一个简单的游戏绘制某种地图,并且我有一个放大功能,这基本上创建了一个更大的缓冲区,然后我以更大的比例重新绘制了所有图形。长时间使用此放大功能或玩到足够深的级别会导致此异常。也许您正在创建大量 Graphic 而没有丢弃它们,或者只是一个足够大而无法分配的 Graphic。

于 2011-12-07T15:26:03.657 回答
3

我在 VB.NET 中遇到了同样的问题。原因很奇怪:

在奥地利,我们的 Windows 系统通常有一个 , as comma 和一个 . 作为千位分隔符。如果这是扭曲的(我认为这是美国的标准),Windows 将抛出此错误。改变它应该在奥地利解决了整个事情......

祝你好运!

于 2012-06-13T11:36:51.760 回答
2

发现可能有帮助 - 似乎是图形或控制处置问题

于 2009-07-30T22:42:15.377 回答
1

也可能与内存碎片有关。我们也在应用程序中使用非托管组件,当非托管组件吃掉所有大的连续块时,可能会出现无法为双缓冲图形分配足够大的缓冲区的问题。

于 2009-08-06T12:05:59.853 回答
0

此外,内存泄漏可能会导致引发异常。例如,一个具有 2-3 个 Web 浏览器的应用程序可能会在几分钟内达到超过 1 GB,这是由于 Internet Explorer 中的一个 bug 造成

于 2012-12-21T15:16:44.740 回答