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

问题描述:

我有一个在C#中编写的应用程序,它使用编写在C中的DLL。 通过一些委托(函数指针),我设法调用了一个C函数。预计此功能会对某些数据执行大量处理,然后将处理后的二进制数据连同数据大小一起返回到C#代码。将数据从非托管代码(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#代码,以便它可以被用作C#代码byte[]的正确方法。

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

谢谢, 维克拉姆

应使用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); 

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


这个

此外,由于C#代码复制数组,你可以只调用回调后free()从C代码的缓冲区。

否则你需要或者从C导出mylib_free()方法或使用已知的内存分配器(NOT malloc)像LocalAlloc(从C)和Windows下Marshal.FreeHGlobal(从C#)。

+0

如果您的项目中没有托管的C++代码,并且只是这一个调用,那么这是最佳解决方案。 –

+0

+1。这工作。谢谢 :)。但是,我只是在想,这不会引入额外的复制开销吗? –

+0

它的确如此,但它仍然是最好的解决方案,如果您没有任何托管C++并且您没有太多这样的调用,并且性能不是很重要。我的答案可以用来避免额外的副本,但是你必须创建一个C++项目(可以编译成一个点网络程序集)。 –

这是Microsoft为C++/CLI制作的(也称为托管C++)。你可以写这样的功能:

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

这将需要字节的C#阵列,其引脚内存,然后把它作为字节FOO的一个C风格的数组,它的长度。没有必要清理或释放任何东西。固定指针在call_foo结束时超出范围时将自动取消固定。清洁和简单。