Marshal.Copy方法在C#.NET中抛出AccessViolationException

5 c# bitmap access-violation

我正在开发一个C#应用程序,可以显示来自摄像头的实时图像.我面对以下代码片段的问题是,当在线程中连续执行此函数时,我在Marshal.Copy中得到AccessViolationException.但是,这在运行一次后成功运行(我得到一个静态图像).我想这与一些内存损坏问题有关.关于如何处理这个问题的任何想法/建议?

    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;
    }
Run Code Online (Sandbox Code Playgroud)

mor*_*lli 9

在我看来,你总是试图将字节数myByteArray.Length复制到位图缓冲区.

你没有检查位图缓冲区实际上是那么大 - 所以可能会写下位图缓冲区的末尾.

尝试检查myByteArray.Length是否大于bmpData.Stride x bmp.Height

如果是这种情况,您需要重新审视您对宽度,高度和像素格式的硬编码值所做的假设.


Guf*_*ffa 6

您不应该立即复制整个图像.位图对象的内存分配可能不是您所期望的.例如,第一扫描线可以最后存储在存储器中,这意味着第二扫描线的数据将在位图对象的分配的存储区域之外结束.此外,扫描线之间可能存在填充以将它们放置在偶数地址上.

一次复制一行,使用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;
}
Run Code Online (Sandbox Code Playgroud)