我有一个用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[]
的推荐方法应该是什么?
谢谢, 维克拉姆
答案 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#)。