Как получить IntPtr из байта [] в C # - PullRequest
117 голосов
/ 11 февраля 2009

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

Ответы [ 7 ]

190 голосов
/ 11 февраля 2009

Другой способ,

GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Do your stuff...
pinnedArray.Free();
116 голосов
/ 11 февраля 2009

Это должно работать, но должно использоваться в небезопасном контексте:

byte[] buffer = new byte[255];
fixed (byte* p = buffer)
{
    IntPtr ptr = (IntPtr)p;
    // do you stuff here
}

будьте осторожны, вы должны использовать указатель в фиксированном блоке! Gc может переместить объект, если вы больше не находитесь в фиксированном блоке.

85 голосов
/ 11 февраля 2009

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

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

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

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

17 голосов
/ 19 мая 2011

Вы можете использовать Marshal.UnsafeAddrOfPinnedArrayElement(array, 0), чтобы получить указатель памяти на массив.

13 голосов
/ 24 мая 2014

Вот поворот ответа @ 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 ():)

0 голосов
/ 20 августа 2011

Marshal.Copy работает, но довольно медленно. Быстрее копировать байты в цикле for. Еще быстрее преобразовать байтовый массив в массив ulong, скопировать столько ulong, сколько помещается в байтовом массиве, а затем скопировать оставшиеся 7 байтов (трейл, который не выровнен по 8 байтов). Самым быстрым является закрепление байтового массива в фиксированном выражении, как предложено выше в ответе Тялиса.

0 голосов
/ 11 февраля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...