将数据从非托管代码(C)传递到托管代码(C#)

时间:2011-07-20 14:42:08

标签: c# c

我有一个用C#编写的应用程序,它使用C编写的DLL。 通过一些委托(函数指针),我设法调用C函数。该函数需要对某些数据进行大量处理,然后将处理后的二进制数据与数据大小一起返回C#代码。

托管c#功能的原型是:

private unsafe delegate void MyCallback (IntPtr cs_buf, Int32 cs_size);

我从我的C code打电话给我:

void* c_buf = NULL;
int c_size = 0;

.... some processing here to fill buf and size......

MyCallback (c_buf, c_size);

在托管C#代码中,我需要调用具有原型的MyCallback函数:

void foo (byte[] cs_buf, int cs_size)

现在cs_size值没有问题,但是使用/将二进制缓冲区从C代码传递到C#代码的正确方法是什么,以便它可以用作byte[] C#代码。

如果我正在做的是正确的方法,那么将收到的IntPtr cs_buf转换为byte[]的推荐方法应该是什么?

谢谢, 维克拉姆

2 个答案:

答案 0 :(得分:4)

这就是Microsoft制作C ++ / CLI(也称为托管C ++)的原因。你可以写一个这样的函数:

void call_foo(array<Byte>^ bytes)
{
    pin_ptr<Byte> ptrBuffer = &bytes[bytes->GetLowerBound(0)];
    foo(ptrBuffer, bytes->Length);
}

这将采用C#字节数组,固定其内存,然后将其作为C样式字节数组传递给foo及其长度。没有必要清理或释放任何东西。固定指针在call_foo结束时超出范围时将自动取消固定。干净简单。

答案 1 :(得分:2)

您应该使用Marshal.Copy

  

Marshal.Copy Method (IntPtr, Byte[], Int32, Int32)

     

将数据从非托管内存指针复制到托管8位   无符号整数数组。

假设cs_size是以字节为单位的大小:

var array = new byte[cs_size];
Marshal.Copy(pointer, array, 0, cs_size);
foo(array, cs_size);

顺便说一句,这种情况foo()不需要使用cs_size参数,因为它可以使用数组的.Length属性。


同样有了这个,当C#代码复制数组时,你可以在调用回调之后{C}代码中的free()缓冲区。

否则,您需要从C导出mylib_free()方法或使用已知的内存分配器(非malloc),如LocalAlloc(来自C)和Marshal.FreeHGlobal(来自Windows下的C#)。