GDI+中随机发生的AccessViolationException问题

15
我们面临的问题是,有时会发生“AccessViolationException”异常,导致一个简单的组合框绘制了白色背景和一个红色交叉图案覆盖在其上面。我们无法可靠地重现这个错误,它只是偶尔发生。
我们没有做任何特殊的事情,只是显示一个带有菜单、工具栏、主面板上的组合框和一些超链接控件的主窗口。
从堆栈跟踪来看,似乎是Windows Forms或GDI+中的一个错误。
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at System.Drawing.SafeNativeMethods.Gdip.GdipDrawLineI(HandleRef graphics, HandleRef pen, Int32 x1, Int32 y1, Int32 x2, Int32 y2)
   at System.Drawing.Graphics.DrawLine(Pen pen, Int32 x1, Int32 y1, Int32 x2, Int32 y2)
   at System.Windows.Forms.GroupBox.DrawGroupBox(PaintEventArgs e)
   at System.Windows.Forms.GroupBox.OnPaint(PaintEventArgs e)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.GroupBox.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) 

我以前没有见过这个,但我想这是可以预料的。你说你无法可靠地重现。快速解决方案可能是将你的 GroupBox 控件的 FlatStyle 属性 设置为 "System"。看起来错误发生在 WinForms 尝试在内部绘制 groupbox 时;如果你让系统绘制它,你将绕过 WinForms 实现和 GDI+。这至少会让你得到一个可工作的构建版本,以便在找出真正的罪魁祸首时部署。也许发布一些代码可以帮助我们解决问题? - Cody Gray
我应该做的第一件事是启动任务管理器,并显示用户对象和GDI对象的计数,以查看应用程序是否泄漏了任何对象。 - Dan Byström
你在调用代码中使用了多个线程吗? - Beachwalker
我曾经遇到过这个问题,不久之前。我似乎记得它是与操作系统相关的,并且是由一个服务包触发的,后来通过一个.NET服务包解决了这个问题。 - Jamie Clayton
2个回答

1
在Dot.Net中,对象会在内存优化或碎片整理过程中从一个位置移动到另一个位置。当将托管内存数组(或图像)的引用发送给非托管代码时,通常会发生这种情况。
数据被移动到不同的位置,由于非托管代码不知道这一点,它试图访问数据的“旧”位置。这只会在Release模式下发生,因为在Debug模式下,内存优化被关闭,所以始终在Release模式下进行调试,呃...
不幸的是,没有办法关闭GC碎片整理过程。您可以尝试调用GC.Collect()并等待其完成后调用您的GDI+函数,但这只会改善情况而不能完全解决问题。
我能够绕过这个问题的唯一方法是手动锁定(固定)数据,并在从非托管代码返回后释放它,是的,回到C ++。对于图像来说比较棘手,因为您需要在所有类和子类中找到数据的确切引用。

0

你在所有东西都被释放之前是否调用了GdiplusShutdown?我曾经问过一个类似的问题这里,在那里我在我的位图被销毁之前调用了GdiplusShutdown,也遇到了访问冲突。


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