Как получить IntPtr из byte[] в C#


Я хочу передать a byte[] к методу принимает в C# это возможно и как?

7   108  

7 ответов:

Не уверен в получении IntPtr в массив, но вы можете скопировать данные для использования с неуправляемым кодом с помощью Mashal.Копия:

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

в качестве альтернативы вы можете объявить структуру с одним свойством, а затем использовать Маршал.PtrToStructure, но это все равно потребует выделения неуправляемой памяти.

Edit: кроме того, как отметил Тялис, вы также можете использовать основные если небезопасный код является опцией для вас

другой путь,

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 (+1 для этого, кстати):

Я создал 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() :)

Маршал.Копирование работает, но довольно медленно. Быстрее скопировать байты в цикле for. Еще быстрее-привести массив байтов к массиву ulong, скопировать столько ulong, сколько помещается в массив байтов, а затем скопировать возможные оставшиеся 7 байтов (след, который не выровнен по 8 байтам). Самый быстрый-закрепить массив байтов в фиксированном операторе, как это было предложено выше в ответе Tyalis.

в некоторых случаях вы можете использовать тип Int32 (или Int64) в случае IntPtr. Если вы можете, еще один полезный класс-BitConverter. Для того, что вы хотите, вы можете использовать BitConverter.ToInt32 например.