2012-03-16 63 views
19

我想从一个IntPtr指针获取数据到一个字节数组中。我可以使用下面的代码来做到这一点:可以将IntPtr强制转换为字节数组而无需执行Marshal.Copy?

IntPtr intPtr = GetBuff(); 
byte[] b = new byte[length]; 
Marshal.Copy(intPtr, b, 0, length); 

但上面的代码强制从IntPtr到字节数组的复制操作。问题数据很大时,这不是一个好的解决方案。

有没有办法将IntPtr转换为字节数组?例如,将以下工作:

byte[] b = (byte[])intPtr

这将消除复制操作的需要。

另外:我们如何确定IntPtr指向的数据长度?

+1

因为'IntPtr'指向*非托管内存*,所以您应该复制数据! – Yahia 2012-03-16 06:00:37

+3

感谢您的快速回复,但IntPtr是从C++导出函数返回的,所以我可以在任何需要的地方管理和删除它。我不想复制数据,因为数据是视频缓冲区,所以它非常大。复制会造成糟糕的表现。谢谢! – TTGroup 2012-03-16 06:04:57

+1

这是真的没有理由去不安全的做法...你真的应该复制的内容 - 有几种安全的方法来做到这一点(一些比其他人快)... – Yahia 2012-03-16 06:07:07

回答

17

正如其他人所说,是没有办法,你可以存储在一个数据管理byte[]而不复制(与您所提供的现有结构*)。但是,如果您实际上不需要需要它位于受管理的缓冲区中,则可以使用unsafe操作直接使用非托管内存。这实际上取决于你需要做什么。

所有byte[]和其他引用类型都由CLR垃圾收集器管理,这是当不再使用时负责分配内存和释放内存的责任。 GetBuffer返回指向的内存是由C++代码分配的一个非托管内存块,(内存布局/实现细节旁边)基本上完全独立于GC托管内存。因此,如果您想使用GC托管的CLR类型(byte[])来包含当前保存在您的IntPtr指向的非托管内存中的所有数据,它需要移动(复制)到GC知道的内存中。这可以通过Marshal.Copy或通过使用unsafe代码或pinvoke或您有什么自定义方法来完成。

但是,这取决于您想要用它做什么。你已经提到它是视频数据。如果您想要对数据应用某种转换或过滤器,则可以直接在非托管缓冲区上执行此操作。如果你想把缓冲区保存到磁盘上,你可以直接在非托管缓冲区上执行。

关于长度的话题,没有办法知道非托管内存缓冲区的长度,除非分配缓冲区的函数也告诉你长度是多少。正如评论者所说,这可以通过很多方式完成(结构的第一个领域,关于方法的参数)。 *最后,如果你有C++代码的控制权,可以对其进行修改,以便它不负责分配写入数据的缓冲区,而是提供指向预分配缓冲区的指针。然后,您可以在C#中创建一个托管的byte[],预先分配给您的C++代码所需的大小,然后使用GCHandle类型将其固定并提供指向您的C++代码的指针。

+0

感谢您的详细解释,我已经使用不安全的代码来做到这一点:) – TTGroup 2012-03-16 09:05:29

2

您不能让托管阵列占用非托管内存。您可以一次复制一个块中的非托管数据,并处理每个块,或创建一个UnmanagedArray类,该类需要IntPtr并提供一个索引器,该索引器仍将使用Marshal.Copy访问数据。

正如@Vinod指出的,你可以用unsafe代码来做到这一点。这将允许您使用类C指针直接访问内存。但是,在调用任何不安全的.NET方法之前,您需要将数据封送到托管内存中,因此您几乎仅限于自己的类C代码。我不认为你应该打扰这一切,只需用C++编写代码即可。

+0

甚至没有“不安全”的东西? – 2012-03-16 06:06:15

+0

啊,不安全的东西。是的,你可以用不安全的东西做到这一点。你真的想要不安全的东西吗? – zmbq 2012-03-16 06:08:54

+0

不知道,不是我的问题:)但是,即使有大的警告标志,看看如何完成这个*会很有趣。 – 2012-03-16 06:09:53

8

尝试这种情况:

byte* b = (byte*)intPtr; 

需要unsafe(在函数签名,块,或编译器标志/unsafe)。

+5

你应该提到这需要函数签名中的'unsafe'关键字或一对花括号:'usafe {...}' – 2012-03-16 06:13:00

+0

谢谢,我刚刚尝试过。但编译器在构建“指针和固定大小的缓冲区只能在不安全的环境中使用”时会抛出错误。我不明白这个错误,请向我解释。谢谢! – TTGroup 2012-03-16 06:17:37

+2

您的项目需要配置为允许不安全的代码,在答案中陈述的代码需要用不安全的方式进行包装(如@MikeBantegui所说),最重要的是,这为您提供了一个非托管指针,指向非托管内存,而不是CLR字节[]参考 – jeffora 2012-03-16 06:26:51