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

これが実際に私の問題である場合、外部から変更されないようfastBackgroundにする方法はありますか?CanvasLockBitsはそれをすることになっていたと思った...

それだけでは答えられない場合は、もう少し試してみました。行を追加しました

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

fastBackground Canvasまたは寸法が他の関数によって変更されている場合は、OnPaintを終了します。

ミューテックスを使用して、ビットマップを変更し、ペイントと同時に実行されないようにすることもできますが(必要だと思います)、Canvasが公開されているため、別の方法でブロックしたいと思います。クラスからミューテックスを渡す必要があります。fastBackgroundCanvas

@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 によって返されるバッファーはアンマネージ メモリであるため、固定は必要ありません。あなたのポインター演算は間違っています。バグを見つけます。バグを見つけるのに役立つ簡単な再現を作成します。

于 2013-02-05T21:11:27.767 に答える