Answers:
不确定是否要将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所指出的,如果不安全的代码是您的选择,您也可以使用固定的
Marshal.Copy这种过载需要一个开始索引。电话应该是Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
其他方式,
GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Do your stuff...
pinnedArray.Free();
这应该可行,但必须在不安全的上下文中使用:
byte[] buffer = new byte[255];
fixed (byte* p = buffer)
{
IntPtr ptr = (IntPtr)p;
// do you stuff here
}
当心,您必须在固定块中使用指针!一旦您不再位于固定块中,gc便可以移动对象。
您可以Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)用来获取指向数组的内存指针。
这是@ user65157答案的一种说法(顺便说一句,顺便说一句):
我为固定对象创建了一个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()的好方法:
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;
}
在某些情况下,对于IntPtr,可以使用Int32类型(或Int64)。如果可以的话,另一个有用的类是BitConverter。对于您想要的内容,您可以使用例如BitConverter.ToInt32。
Int32作为指针。这是几年前做的不好的做法,它导致了各种移植问题。即使这样Int64也不安全,因为已经有128位架构,并且指针大小会增加。指针仅应表示为指针。
int/ 的唯一有效方案是所使用long的语言没有指针的概念时(例如VB6)。C#支持指针,并且具有IntPtr-根本不需要使用int指针代替指针。如果您在回答中添加清晰的警告和对潜在问题的解释,我将删除-1。