4

我有一些代码出现错误“AccessViolationException 未被用户代码处理:尝试读取或写入受保护的内存......”

违规函数的精简版本如下:

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);
                            }
                        }

错误发生在该行:

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

甚至替换为:

canvasWalk[0] = 0;

迭代变量在每次崩溃时都有不同的值,所以这让我相信外部函数正在修改y位图。xCanvas

如果这实际上是我的问题,有没有办法防止fastBackgroundCanvas被外部修改?我以为LockBits应该这样做...

如果这还不足以回答,这里有一些我已经尝试过:我添加了这一行

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

fastBackground Canvas如果或尺寸正在被其他函数修改,则退出 OnPaint 。

可以使用互斥锁来防止修改位图的函数fastBackgroundCanvas绘图同时运行(我认为它们必须如此)但我宁愿以另一种方式阻止它们,因为 Canvas 是公共的,我不想要要求将互斥锁从类中传递出去。

根据@usr 的建议,这个进一步精简的版本不会失败……一定是 PTD 错误。(程序员太笨了)即算术错误

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);
                            }
                        }
4

1 回答 1

1

将我的评论移到答案中,因为它有助于解决问题:

LockBits 返回的缓冲区不需要 Fixed,因为它是非托管内存。你的指针算法是错误的。找到错误。创建一个简单的重现来帮助找到错误。

于 2013-02-05T21:11:27.767 回答