145 votes

Comment obtenir IntPtr à partir de byte[] en C#

Je veux passer un byte[] à une méthode prend un paramètre IntPtr en c#, est-ce possible et comment.

226voto

user65157 Points 1109

D'une autre manière :

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

145voto

Cela devrait fonctionner mais doit être utilisé dans un contexte non sécurisé :

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

Attention, vous devez utiliser le pointeur dans le bloc fixe ! Le gc peut déplacer l'objet dès que vous n'êtes plus dans le bloc fixe.

101voto

Richard Szalay Points 42486

Je ne sais pas s'il est possible d'obtenir un IntPtr dans un tableau, mais vous pouvez copier les données pour les utiliser dans un code non géré en utilisant Mashal.Copy :

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

Vous pourriez aussi déclarer une structure avec une seule propriété et utiliser Marshal.PtrToStructure, mais cela nécessiterait encore l'allocation de mémoire non gérée.

Editar: De plus, comme Tyalis l'a souligné, vous pouvez également utiliser Correction de si le code non sécurisé est une option pour vous

20voto

Sakthi Points 51

Vous pourriez utiliser Marshal.UnsafeAddrOfPinnedArrayElement(array, 0) pour obtenir un pointeur mémoire sur le tableau.

16voto

dlchambers Points 882

Voici une variante de la réponse de @user65157 (+1 pour cela, BTW) :

J'ai créé un wrapper IDisposable pour l'objet épinglé :

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();
   }
}

puis l'utiliser comme suit :

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

Je trouve que c'est un bon moyen de ne pas oublier d'appeler Free() :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X