我们遇到的问题是,有时会发生AccessViolationException
,并且会在其顶部绘制一个带有白色背景和红叉的简单组框。我们无法可靠地重现这个错误,它只是不时发生。
我们没有做任何特别的事情,我们只是显示一个主窗口,其中包含菜单,工具栏,主面板上的组框以及组框内的一些超链接控件。
从堆栈跟踪中,它似乎是Windows窗体或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)
答案 0 :(得分:1)
长话短说。我发现有一个"" bug""在Dot.Net中,GC将对象从一个位置移动到另一个位置,作为内存优化或碎片整理过程的一部分。这通常发生在将托管内存数组(或映像)的引用发送到未管理的代码段时。数据正被移动到另一个位置,并且由于未托管代码不知道这一点,它会尝试访问" old"数据的位置。这只发生在发布模式,因为在调试模式下内存优化已关闭,因此总是在发布模式下调试,meh ......
不幸的是,没有办法关闭GC碎片整理过程。 您可以尝试调用GC.Collect()并在调用GDI +函数之前等待它完成,但这只会改善情况而不是完全解决它。
我能够绕过这个的唯一方法是手动锁定(固定)数据并在从非托管代码返回后释放它,是的,回到C ++。图像很棘手,因为您需要在所有类和子类中找到对数据的确切引用。
希望这有帮助。
答案 1 :(得分:0)
在所有内容发布之前,您是否致电GdiplusShutdown了?我问了一个类似的问题here,在我的Bitmap被销毁之前我调用了GdiplusShutdown并且还违反了访问权限
答案 2 :(得分:0)
有一些地方存在违规行为,例如:
1)异常:System.AccessViolationException
消息:尝试读取或写入受保护的内存。这通常表明其他记忆已损坏
来源:System.Drawing
at System.Drawing.SafeNativeMethods.Gdip.GdipDrawImageI(HandleRef graphics, HandleRef image, Int32 x, Int32 y)
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y)
at System.Drawing.Graphics.DrawImageUnscaled(Image image, Int32 x, Int32 y)
at Aga.Controls.Tree.TreeViewAdv.DrawTree(PaintEventArgs e)
at Aga.Controls.Tree.TreeViewAdv.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)
代码似乎没有做任何异常。它将图像渲染到缓冲区然后调用: e.Graphics.DrawImageUnscaled(_bufferImage,0,0); 任何其他线程都不会访问缓冲区。
2)
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.Drawing.Graphics.DrawLine(Pen pen, Point pt1, Point pt2)
at SomeMyNamespace.SomeMyControl.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.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.UserControl.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.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
此处OnPaint
方法除了仅绘制一行外不执行任何操作。
传递给DrawLine
的笔(及其笔刷)肯定已经初始化并且没有被处理掉。