我想将IntPtr指针中的数据转换为字节数组。我可以使用以下代码来执行此操作:
IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);
但是上面的代码强制从IntPtr到字节数组的复制操作。当有问题的数据很大时,这不是一个好的解决方案。
有没有办法将IntPtr强制转换为字节数组?例如,以下工作:
byte[] b = (byte[])intPtr
这将消除复制操作的需要。
另外:我们如何确定IntPtr指向的数据长度?
答案 0 :(得分:22)
正如其他人所提到的那样,您无法在不复制的情况下将数据存储在托管 byte[]
中(使用您提供的当前结构*)。但是,如果您实际上不需要它位于托管缓冲区中,则可以使用unsafe
操作直接使用非托管内存。这真的取决于你需要做什么。
所有byte[]
和其他引用类型都由CLR垃圾收集器管理,这是在不再使用时负责内存分配和释放的原因。返回GetBuffer
指向的内存是由C ++代码分配的非托管内存块,(除了内存布局/实现细节)基本上与GC托管内存完全分开。因此,如果要使用GC托管CLR类型(byte[]
)来包含当前保存在IntPtr
指向的非托管内存中的所有数据,则需要将其移动(复制)到内存中GC知道的。这可以通过Marshal.Copy
或使用unsafe
代码或pinvoke的自定义方法或您拥有的内容来完成。
但是,这取决于你想用它做什么。你已经提到了它的视频数据。如果要对数据应用某些转换或过滤器,则可以直接在非托管缓冲区上执行此操作。如果要将缓冲区保存到磁盘,可以直接在非托管缓冲区上进行。
关于长度的主题,除非分配缓冲区的函数也告诉您长度是多少,否则无法知道非托管内存缓冲区的长度。这可以通过多种方式完成,正如评论者提到的那样(结构的第一个领域,方法的参数)。
*最后,如果您可以控制C ++代码,则可以对其进行修改,以便它不负责分配将数据写入的缓冲区,而是提供指向预分配缓冲区的指针。然后,您可以在C#中创建托管 byte[]
,预分配到C ++代码所需的大小,并使用GCHandle
类型来固定它并提供指向C ++的指针代码。
答案 1 :(得分:8)
答案 2 :(得分:2)
您不能让托管阵列占用非托管内存。您可以一次复制一个块的非托管数据,并处理每个块,或者创建一个UnmanagedArray
类,它接受IntPtr
并提供一个仍将使用Marshal.Copy访问数据的索引器
正如@Vinod指出的那样,您可以使用unsafe
代码执行此操作。这将允许您使用类似C的指针直接访问内存。但是,在调用任何不安全的.NET方法之前,您需要将数据封送到托管内存中,因此您几乎只限于自己的类C代码。我认为你根本不应该为此烦恼,只需用C ++编写代码即可。
答案 3 :(得分:1)
查看此Code Project页面,了解使用非托管阵列的解决方案。