如何从C#中的byte []获取IntPtr

时间:2009-02-11 16:23:38

标签: c# .net

我想将byte[]传递给一个方法,在C#中使用IntPtr参数,这可能吗?如何?

8 个答案:

答案 0 :(得分:189)

另一种方式,

GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Do your stuff...
pinnedArray.Free();

答案 1 :(得分:114)

这应该有用,但必须在不安全的环境中使用:

byte[] buffer = new byte[255];
fixed (byte* p = buffer)
{
    IntPtr ptr = (IntPtr)p;
    // do you stuff here
}
小心,你必须使用固定块中的指针!一旦你不再在固定的块中,gc可以移动对象。

答案 2 :(得分:85)

不确定是否将IntPtr添加到数组中,但您可以使用Mashal.Copy复制数据以用于非托管代码:

IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
// Call unmanaged code
Marshal.FreeHGlobal(unmanagedPointer);

或者,您可以使用一个属性声明一个结构,然后使用Marshal.PtrToStructure,但这仍然需要分配非托管内存。

编辑另外,正如Tyalis指出的那样,如果您选择不安全的代码,也可以使用修复

答案 3 :(得分:17)

您可以使用Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)来获取指向数组的内存指针。

答案 4 :(得分:12)

这是@ user65157答案的转折点(+1为此,BTW):

我为固定对象创建了一个IDisposable包装器:

class AutoPinner : IDisposable
{
   GCHandle _pinnedArray;
   public AutoPinner(Object obj)
   {
      _pinnedArray = GCHandle.Alloc(obj, GCHandleType.Pinned);
   }
   public static implicit operator IntPtr(AutoPinner ap)
   {
      return ap._pinnedArray.AddrOfPinnedObject(); 
   }
   public void Dispose()
   {
      _pinnedArray.Free();
   }
}

然后就这样使用它:

using (AutoPinner ap = new AutoPinner(MyManagedObject))
{
   UnmanagedIntPtr = ap;  // Use the operator to retrieve the IntPtr
   //do your stuff
}

我发现这是一个不忘记叫Free()的好方法:)

答案 5 :(得分:0)

Marshal.Copy有效,但速度很慢。更快的是复制for循环中的字节。更快的是将字节数组转换为ulong数组,复制尽可能多的ulong以适应字节数组,然后复制可能的剩余7个字节(不是8字节对齐的跟踪)。最快的是将字节数组固定在固定语句中,如上面Tyalis的答案中所提出的那样。

答案 6 :(得分:-1)

IntPtr GetIntPtr(Byte[] byteBuf)
{
    IntPtr ptr = Marshal.AllocHGlobal(byteBuf.Length);
    for (int i = 0; i < byteBuf.Length; i++)
    {
       Marshal.WriteByte(ptr, i, byteBuf[i]);
    }
    return ptr;
}

答案 7 :(得分:-5)

在某些情况下,您可以在IntPtr的情况下使用Int32类型(或Int64)。如果可以,另一个有用的类是BitConverter。根据你的需要,你可以使用BitConverter.ToInt32作为例子。