阵列由C#虚拟机写保护

时间:2011-09-12 08:49:10

标签: c# c++ memory

我正在编写一个C#应用程序,我需要将其中的一部分用于C ++以提高速度。 C ++中的函数导出如下:

extern "C" __declspec(dllexport) int fastSegment(char*, int, int);

我在C#中导入此函数如下:

[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static private extern bool fastSegment(byte[] img, int width, int height);

我想要处理的图像如下:

fastSegment(image, 640, 480);

image的大小合适。由于我不想浪费内存并分配新数组,因此我直接在C ++函数中修改了数组。

会发生什么?蓝屏的死亡。我之前从未在Windows 7中看到它。

我的功能仅在image[0]image[1]image[2]中用于测试目的,当我删除时,一切都很好。

我的猜测是虚拟机保护了内存,但我觉得奇怪的是我无法写入内存,或虚拟机并没有简单地抛出异常。有没有办法取消保护缓冲区,还是我必须分配一个新缓冲区?

编辑:

当我写入数据时,它会自动运行程序。可能是这次突然崩溃的原因是什么?

3 个答案:

答案 0 :(得分:2)

你做不到。在这种情况下,您的数组将是只读的。 如果要在本机中更改C#数组,则需要将其作为指针进行编组 看看微软的example 还有一个解释为什么需要这样做。

答案 1 :(得分:2)

允许垃圾收集器移动托管数据。本机代码无法检测到这一点,因此可能会写入错误的内存地址。但是你可以告诉.NET运行时不要移动你的数组。例如。使用GCHandle类:

GCHandle handle = GCHandle.Alloc(image, GCHandleType.Pinned);
try
{
    fastSegment(handle.AddrOfPinnedObject(), 640, 480);
}
finally
{
    // make sure to free the handle to avoid leaks!
    handle.Free();
}

编辑:这只是一种方式,但我认为它说明了问题。请阅读Marshaling between Managed and Unmanaged Code

答案 2 :(得分:0)

您的数据可能会被GC移动 - 但如果您每次运行应用程序时都会遇到崩溃,那么情况就不太可能了。请尝试以下方法之一:

[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern bool fastSegment(IntPtr img, int width, int height);
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
static void FastSegment(byte[] data, int width, int height)
{
    var length = width * height;
    var ptr = Marshal.AllocHGlobal(width * height);
    try
    {
        Marshal.Copy(data, 0, ptr, length);
        fastSegment(ptr, width, height);
        Marshal.Copy(ptr, data, 0, length);
    }
    finally
    {
        Marshal.FreeHGlobal(ptr);
    }
}
// ---- OR ----
[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern bool fastSegment(IntPtr img, int width, int height);
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
static void FastSegment(byte[] data, int width, int height)
{
    var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
    try
    {
        fastSegment(handle.AddrOfPinnedObject(), width, height);
    }
    finally
    {
        handle.Free();
    }
}
// ---- OR ----
[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static unsafe extern bool fastSegment(byte* img, int width, int height);
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
static void FastSegment(byte[] data, int width, int height)
{
    unsafe
    {
        fixed (byte* dataPinned = data)
        {
            fastSegment(dataPinned, width, height);
        }
    }
}