The Marshal.Copy method raises an AccessViolationException in C # .NET.

I am working on a C # application that will display live images from a camera. The problem that I encountered in the following code snippet is that I get an AccessViolationException in Marshal.Copy when I run this function that runs continuously on a thread. But this succeeds when executed once (I get one static image). I assume this is due to a memory issue. Any idea / suggestions on how to deal with this problem?

    private Image ByteArrayToImage(byte[] myByteArray) 
    {
        if (myByteArray != null)
        {
            MemoryStream ms = new MemoryStream(myByteArray);
            int Height = 504;
            int Width = 664;
            Bitmap bmp = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
            Marshal.Copy(myByteArray, 0, bmpData.Scan0, myByteArray.Length);
            bmp.UnlockBits(bmpData);

            return bmp;
        }
        return null;
    }
+5
source share
8 answers

It seems to me that you are always trying to copy the number of bytes of myByteArray.Length into the bitmap buffer.

, - , , , -.

, myByteArray.Length bmpData.Stride x bmp.Height

, , , .

+9

. , . , , , . , .

, bmpData.Stride, :

int offset = 0;
long ptr = bmpData.Scan0.ToInt64();
for (int i = 0; i < Height; i++) {
   Marshal.Copy(myByteArray, offset, new IntPtr(ptr), Width * 3);
   offset += Width * 3;
   ptr += bmpData.Stride;
}
+6

: →

        // Unlock the bits right after Marshal.Copy
        bmp.UnlockBits(bmpData);

- ? . msdn: http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx, :

                        Bitmap bmp = new Bitmap("c:\\picture.jpg");

                        // Lock the bitmap bits.  
                        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                        System.Drawing.Imaging.BitmapData bmpData =
                            bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                            bmp.PixelFormat);

                        // Get the address of the first line.
                        IntPtr ptr = bmpData.Scan0;

                        // Declare an array to hold the bytes of the bitmap.
                        int bytes = bmpData.Stride * bmp.Height;
                        byte[] rgbValues = new byte[bytes];

                        // Copy the RGB values into the array.
                        //This causes read or write protected memory
                        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

exe IDE. , , , , , , , .

0

BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);

- ReadWrite ReadOnly ImageLockMode? , .

0

, , , BitmapData.Stride:

- ( ), . , . , .

, , :

BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
Marshal.Copy(myByteArray, 0, bmpData.Scan0 + 
( bmpData.Stride >= 0 ? 0 : bmpData.Stride*(bmp.Height-1) ),
myByteArray.Length);

: : new Bitmap(Width, Height, PixelFormat.Format24bppRgb);... ?
ILSpy:

public Bitmap(int width, int height, PixelFormat format)
{
    IntPtr zero = IntPtr.Zero;
    int num = SafeNativeMethods.Gdip.GdipCreateBitmapFromScan0(width, height, 0, (int)format, NativeMethods.NullHandleRef, out zero);
    if (num != 0)
    {
            throw SafeNativeMethods.Gdip.StatusException(num);
    }
    base.SetNativeImage(zero);
}

// System.Drawing.SafeNativeMethods.Gdip
[DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
internal static extern int GdipCreateBitmapFromScan0(int width, int height, int stride, int format, HandleRef scan0, out IntPtr bitmap);

:

Bitmap(
  [in]  INT width,
  [in]  INT height,
  [in]  INT stride,
  [in]  PixelFormat format,
  [in]  BYTE *scan0
);

[in]
: INT
Integer, . ( ) (, 2 16 ), . , .

0? , . -? ? ( .NET new Bitmap(Width, Height, PixelFormat.Format24bppRgb)). BitmapData.Stride.

0

rawStride BitmapSource Class. , , , . , , . , , , .

private byte[] CreateImageByteArray(int width, int height, PixelFormat pixelFormat)
{
    int rawStride = (width * pixelFormat.BitsPerPixel + 7) / 8;
    byte[] rawImage = new byte[rawStride * height];

    return rawImage;
}

, , - , Bitmap , . , .

, . . Windows Forms Controls Thread- Windows Forms #.

0

ThreadApartmentState Single Threaded.

, , .

0

( ), .Length.

:

IntPtr ptr = bitmapdata.Scan0;
Marshal.Copy(pixeldata, 0, ptr, pixeldata.Length);

.Length -:

IntPtr ptr = bitmapdata.Scan0;
int bytes = Math.Abs(bitmapdata.Stride) * bmp.Height;
Marshal.Copy(pixeldata, 0, ptr, bytes);

.Length 1 , .

Math.Abs was taken directly to the Microsoft example. Because Stride can be negative for a bitmap from bottom to top.

Microsoft example: https://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.scan0%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396#Examples

(+ Don't forget .Unlock and add it to the try-finally statement.)

0
source

All Articles