Is a fixed blocking required?

I have code that has the error "AccessViolationException was not handled by user code: Attempting to read or write protected memory ..."

A stripped down version of the offending function looks like this:

protected override void OnPaint(PaintEventArgs pe)
{
    if ((updatingFastBackground) || (Calculating)) return; //ADDED FOR DEBUGGING, SEE BELOW
            BitmapData canvasData = Canvas.LockBits(new Rectangle(Point.Empty, Canvas.Size), ImageLockMode.WriteOnly, FastPixelFormat);
            BitmapData fbgData = fastBackground.LockBits(new Rectangle(Point.Empty, fastBackground.Size), ImageLockMode.ReadOnly, FastPixelFormat);
            try
            {
                unsafe
                {
                    byte* canvasDataScan0 = (byte*)canvasData.Scan0.ToPointer();
                    byte* fbgDataScan0 = (byte*)fbgData.Scan0.ToPointer();
                    Rectangle spriteBounds = new Rectangle(Point.Empty, ButtonImages.ImageSize);
                    for (int i = 0; i < ButtonImages.Images.Count; i++)
                    {
                        // Button offset location
                        Point l = new Point(
                            (int)((i % columnCount) * hStep + myIVM.Location.X),
                            (int)((i / columnCount) * vStep + myIVM.Location.Y));
                        // Paint at current location?
                        if (buttonPaintBounds.Contains(l))
                        {
                            BitmapData spriteData = buttonBitmaps[i].LockBits(spriteBounds, ImageLockMode.ReadOnly, FastPixelFormat);
                            try
                            {
                                int spriteLeft = Math.Max(l.X, 0);
                                int spriteRight = Math.Min(l.X + ButtonImages.ImageSize.Width, canvasData.Width);
                                int spriteTop = Math.Max(l.Y, 0);
                                int spriteBottom = Math.Min(l.Y + ButtonImages.ImageSize.Height, canvasData.Height);
                                int spriteWidth = spriteRight - spriteLeft;
                                int spriteHeight = spriteBottom - spriteTop;
                                byte* canvasRowLeft = canvasDataScan0 + (spriteTop * canvasData.Stride) + spriteLeft * 4;
                                byte* spriteRowLeft =
                                    (byte*)spriteData.Scan0.ToPointer() +
                                    Math.Max((spriteTop - l.Y), 0) * spriteData.Stride +
                                    Math.Max((spriteLeft - l.X), 0) * 4;
                                for (int y = 0; y < spriteHeight; y++)
                                {
                                    canvasRowLeft += canvasData.Stride;
                                    spriteRowLeft += spriteData.Stride;
                                    Byte* canvasWalk = (Byte*)canvasRowLeft;
                                    Byte* spriteWalk = (Byte*)spriteRowLeft;
                                    for (int x = 0; x < spriteWidth; x++)
                                    {
                                        if (spriteWalk[3] != 255)
                                        {
                                            canvasWalk[0] = (byte)(canvasWalk[0] * spriteWalk[3] / 255 + spriteWalk[0]);
                                            canvasWalk[1] = (byte)(canvasWalk[1] * spriteWalk[3] / 255 + spriteWalk[1]);
                                            canvasWalk[2] = (byte)(canvasWalk[2] * spriteWalk[3] / 255 + spriteWalk[2]);
                                        }
                                        canvasWalk += 4;
                                        spriteWalk += 4;
                                    }
                                }
                                thesePoints.Add(l);
                            }
                            finally
                            {
                                buttonBitmaps[i].UnlockBits(spriteData);
                            }
                        }

      

Line error:

canvasWalk[0] = (byte)(canvasWalk[0] * spriteWalk[3] / 255 + spriteWalk[0]);

      

and even when replaced with:

canvasWalk[0] = 0;

      

Iterative variables y

and x

have different values ​​on each failure, so this leads me to believe that an external function is modifying the bitmap Canvas

.

If this is really my problem, is there a way to prevent change fastBackground

and Canvas

externally? I thought I LockBits

had to do it ...

If that's not enough to answer, here are some more attempts: I added the line

if ((updatingFastBackground) || (Calculating)) return;

      

to exit OnPaint if fastBackground

Canvas

or the dimensions are changed by other functions.

I could use a mutex to prevent functions that change bitmaps fastBackground

and Canvas

from starting at the same time as paint (which I think they should be), but I'd rather block them in a different way: Canvas is public and I I don't want to require the transfer of the mutex from the class.

per @usr suggestion, this extra stripped down version doesn't fail ... Should have been a PTD bug. (the programmer is too dumb) i.e. arithmetic error

protected override void OnPaint(PaintEventArgs pe)
{
    if ((updatingFastBackground) || (Calculating)) return; //ADDED FOR DEBUGGING, SEE BELOW
            BitmapData canvasData = Canvas.LockBits(new Rectangle(Point.Empty, Canvas.Size), ImageLockMode.WriteOnly, FastPixelFormat);
            BitmapData fbgData = fastBackground.LockBits(new Rectangle(Point.Empty, fastBackground.Size), ImageLockMode.ReadOnly, FastPixelFormat);
            try
            {
                unsafe
                {
                    byte* canvasDataScan0 = (byte*)canvasData.Scan0.ToPointer();
                    byte* fbgDataScan0 = (byte*)fbgData.Scan0.ToPointer();
                    Rectangle spriteBounds = new Rectangle(Point.Empty, ButtonImages.ImageSize);
                    for (int i = 0; i < ButtonImages.Images.Count; i++)
                    {
                        // Button offset location
                        Point l = new Point(
                            (int)((i % columnCount) * hStep + myIVM.Location.X),
                            (int)((i / columnCount) * vStep + myIVM.Location.Y));
                        // Paint at current location?
                        if (buttonPaintBounds.Contains(l))
                        {
                            BitmapData spriteData = buttonBitmaps[i].LockBits(spriteBounds, ImageLockMode.ReadOnly, FastPixelFormat);
                            try
                            {
                                byte* canvasRowLeft = canvasDataScan0;
                                byte* spriteRowLeft = (byte*)spriteData.Scan0.ToPointer();
                                for (int y = 0; y < 145; y++)
                                {
                                    canvasRowLeft += canvasData.Stride;
                                    spriteRowLeft += spriteData.Stride;
                                    Byte* canvasWalk = (Byte*)canvasRowLeft;
                                    Byte* spriteWalk = (Byte*)spriteRowLeft;
                                    for (int x = 0; x < 145; x++)
                                    {
                                        if (spriteWalk[3] != 255)
                                        {
                                            canvasWalk[0] = 0;
                                            canvasWalk[1] = 0;
                                            canvasWalk[2] = 0;
                                        }
                                        canvasWalk += 4;
                                        spriteWalk += 4;
                                    }
                                }
                                thesePoints.Add(l);
                            }
                            finally
                            {
                                buttonBitmaps[i].UnlockBits(spriteData);
                            }
                        }

      

+3


source to share


1 answer


Moving my comment to the answer because it helped solve the problem:



Fixed not required for the buffer returned by LockBits because it is unmanaged memory. Pointer arithmetic is incorrect. Find the error. Create a simple registry to find the error.

+1


source







All Articles