我正在编写一个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]
中用于测试目的,当我删除时,一切都很好。
我的猜测是虚拟机保护了内存,但我觉得奇怪的是我无法写入内存,或虚拟机并没有简单地抛出异常。有没有办法取消保护缓冲区,还是我必须分配一个新缓冲区?
当我写入数据时,它会自动运行程序。可能是这次突然崩溃的原因是什么?
答案 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);
}
}
}