我想将byte[]
传递给一个方法,在C#中使用IntPtr
参数,这可能吗?如何?
答案 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作为例子。