как уже видно из заголовка, я сталкиваюсь с AccessViolationException, когда пытаюсь нарисовать элемент управления в .NET, используя объект BufferedGraphics
. Это происходит через некоторое время, раньше или позже. Оценивая адрес объекта, я заметил, что он продолжал увеличиваться по мере выполнения программы. Я уже предпринял несколько мер по сохранению памяти, которые, казалось, немного помогли, но в конечном итоге не решили проблему. Кажется, проблема возникает независимо от того, избавляюсь ли я от графического объекта до окончания функции.
private void checkMemory()
{
long mem = GC.GetTotalMemory(false);
//Console.WriteLine("Allocated memory: " + mem.ToString());
if (mem > criticalMemorySize)
{
Console.WriteLine("GC started");
GC.Collect(1, GCCollectionMode.Forced, true);
}
}
BufferedGraphics graphics;
protected override void OnPaint(PaintEventArgs e)
{
lock (e.Graphics)
{
base.OnPaint(e);
checkMemory();
if (e.ClipRectangle.Width * e.ClipRectangle.Height == 0)
return;
if (graphics == null || graphics.Graphics == null || graphics.Graphics.ClipBounds != e.ClipRectangle)
graphics = _bufferedGraphicsContext.Allocate(e.Graphics, e.ClipRectangle);
PaintBackground(graphics.Graphics);
PaintHeader(graphics.Graphics);
PaintBody(graphics.Graphics);
DrawGrid(graphics.Graphics);
//...
graphics.Render(e.Graphics);
graphics.Graphics.Dispose();
graphics.Dispose();
}
}
Исключение возникает в этой функции при вызове g.DrawString
:
private void PaintBody(Graphics g)
{
Font seriffont = Design.CreateSerifFont(fontSize);
Point mousePos = PointToClient(MousePosition);
int hfeed = headHeight + headLineWidth - 2; //Dunno
for (int y = 0; y < LineCount; y++)
{
int vfeed = 0;
for (int x = 0; x < ColumnCount; x++)
{
String s = "";
Rectangle area = new Rectangle(vfeed, hfeed, colwidth, cellHeight);
switch (_tableData[y][x])
{
case ExBool.DontCare:
s = "*";
break;
case ExBool.False:
s = "0";
break;
case ExBool.True:
s = "1";
break;
default:
s = " ";
break;
}
Color backColor = cellBackColor;
if (_activeHeaderColumn == x)
{
backColor = cellActiveColColor;
}
if (area.Contains(mousePos))
{
backColor = cellHoverColor;
}
if (area.Contains(mousePos) &&
((MouseButtons & MouseButtons.Left) == MouseButtons.Left))
{
backColor = cellActiveColor;
}
g.FillRectangle(new SolidBrush(backColor), area);
g.DrawString(s, seriffont, Brushes.Black, area,
new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
if (x != InputValues.Count() - 1)
{
vfeed += lineWidth + colwidth;
}
else
{
vfeed += typeSepLineWidth + colwidth;
}
}
hfeed += cellHeight + lineWidth;
}
}
И это исключение, которое я получаю:
System.AccessViolationException was unhandled
HResult = -2147467261
Message=Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben.Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist.
Source= System.Drawing
StackTrace:
bei System.Drawing.SafeNativeMethods.Gdip.GdipDrawString(HandleRef graphics, String textString, Int32 length, HandleRef font, GPRECTF& layoutRect, HandleRef stringFormat, HandleRef brush)
bei System.Drawing.Graphics.DrawString(String s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format)
bei KarnaughVeitch.Controls.TruthTableControl.PaintBody(Graphics g)
bei KarnaughVeitch.Controls.TruthTableControl.OnPaint(PaintEventArgs e)
bei KarnaughVeitch.Controls.TruthTableControl.TruthTableControl_MouseMove(Object sender, MouseEventArgs e)
bei System.Windows.Forms.Control.OnMouseMove(MouseEventArgs e)
bei System.Windows.Forms.Control.WmMouseMove(Message& m)
bei System.Windows.Forms.Control.WndProc(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
bei System.Windows.Forms.Application.Run(Form mainForm)
bei KarnaughVeitch.Program.Main()
bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
bei System.Threading.ThreadHelper.ThreadStart()
InnerException:
Кто-нибудь знает, как это решить? Заранее спасибо!
Редактировать:
Переменная Context создается глобально следующим образом:
BufferedGraphicsContext _bufferedGraphicsContext = new BufferedGraphicsContext()
Это было рекомендовано в документации для случая, когда вы будете часто использовать BufferedGraphics
. Функции являются частью пользовательского элемента управления, который позволяет пользователю вводить входные и выходные данные бинарных функций. Поскольку я не знал о подобном элементе управления, я просто написал его сам. Вышеупомянутая функция вызывается каждый раз, когда элемент управления необходимо перекрасить, например. если пользователь двигает мышкой, нажимает на что-то и так далее, для всех этих действий требуется визуальная обратная связь. Как правило, он работает как хотелось бы, за исключением исключения, которое возникает после использования элемента управления в течение некоторого времени...
Редактировать 2:
Поскольку исключение возникает почти исключительно для DrawString
функций, возможно ли, что NullReference (согласно HResult, если я не ошибаюсь) не из-за самого процесса рисования, а из-за одного из аргументов или чего-то еще?
Graphics
не содержит графику; это инструмент, позволяющий рисовать на связанном растровом изображении, включая поверхность элемента управления. Не кэшируйте его «буфером». Для настоящей двойной буферизации вам необходимо «буферизировать» растровое изображение. Или используйте элемент управления DoubleBuffered, например PictureBox. - Не уверен, что делает_bufferedGraphicsContext.Allocate
, но если это в конечном итоге приведет к удалению e.Graphics, вы получите исключение. - person TaW   schedule 09.06.2016Allocate
, если я не ошибаюсь, позволяет мне создать объектBufferedGraphics
, к которому я могу применить функции рисования и визуализировать его позже в реальной графике, когда я закончу. Мне нужно это, чтобы предотвратить мерцание, которое работает довольно хорошо, пока не произойдет исключение. Я полагаю, что он использует растровое изображение внутри. Если я правильно помню документацию, я использую классBufferedGraphics
так, как это должно быть, но все же я не могу объяснить себе, почему существует AccessViolation... - person XChalo   schedule 10.06.2016bufferedGraphicsContext
? - person TaW   schedule 10.06.2016