¿Podría proporcionar más detalles? ¿Por qué querrías hacerlo?
Grzenio
2
Necesita esto si usa la API de DirectShow, por ejemplo ... para obtener datos de VideoRenderer, debe usar esto ... y el GCHandlemétodo funciona de maravilla ... también el fixedmétodo. : P :))
Cipi
Necesita esto para cualquier cosa que transfiera terrabytes de datos y desea evitar la copia adicional. Use su imaginación.
Brain2000
Respuestas:
93
No estoy seguro de obtener un IntPtr en una matriz, pero puede copiar los datos para usarlos con código no administrado utilizando Mashal.Copy:
Alternativamente, podría declarar una estructura con una propiedad y luego usar Marshal.PtrToStructure, pero eso aún requeriría asignar memoria no administrada.
Editar: Además, como señaló Tyalis, también puede usar el código fijo si no es seguro para usted.
Solo para aclarar, Marshal.Copycon esa sobrecarga se necesita un índice de inicio. La llamada debería serMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
mkenyon
es mejor obtener IntPtr sin crear nueva memoria, como la respuesta de @ user65157.
Lin
208
De otra manera,
GCHandle pinnedArray =GCHandle.Alloc(byteArray,GCHandleType.Pinned);IntPtr pointer = pinnedArray.AddrOfPinnedObject();// Do your stuff...
pinnedArray.Free();
@Cipi Según una de las publicaciones de Eric Lippert, esta debería tener la palabra clave Fixed en lugar de usar el GC
goodguys_activate
muchas gracias. Funciona bien y es bastante fácil. No soy tan hábil en GCHandles y Marshal. ¿Alguien puede decirme qué ventajas tiene el Mariscal y qué GCHandle y dónde usar cuál? Gracias
piggy
1
¿Podría alguien proporcionar la referencia a la publicación de Eric Lippert?
Cameron
3
@piggy: Creo que la desventaja de Marshal es que tienes que hacer una copia de tus datos (lo que puede llevar mucho tiempo y desperdiciar la memoria que puedas necesitar)
Riki
66
@ makerofthings7 No creo que Lippert esté diciendo que use 'fijo' en lugar del GC [para anclar objetos], creo que está diciendo que no use el GC para anclar un objeto indefinidamente, junto con decir que no use fijo para hacer el igual, tampoco.
Cameron
129
Esto debería funcionar pero debe usarse dentro de un contexto inseguro:
byte[] buffer =newbyte[255];fixed(byte* p = buffer){IntPtr ptr =(IntPtr)p;// do you stuff here}
¡cuidado, tienes que usar el puntero en el bloque fijo! El gc puede mover el objeto una vez que ya no esté en el bloque fijo.
Es posible que desee investigar cómo derivar su AutoPinner de SafeHandle ya que esa clase tiene en cuenta las "trampas" de concurrencia y seguridad, así como alentar / usar el patrón IDisposable recomendado.
kkahl
0
Marshal.Copy funciona pero es bastante lento. Más rápido es copiar los bytes en un bucle for. Incluso más rápido es convertir la matriz de bytes en una matriz ulong, copiar tantos ulong como quepan en la matriz de bytes, luego copiar los 7 bytes restantes posibles (el camino que no está alineado con 8 bytes). Lo más rápido es anclar la matriz de bytes en una declaración fija como se propuso anteriormente en la respuesta de Tyalis.
IntPtrGetIntPtr(Byte[] byteBuf){IntPtr ptr =Marshal.AllocHGlobal(byteBuf.Length);for(int i =0; i < byteBuf.Length; i++){Marshal.WriteByte(ptr, i, byteBuf[i]);}return ptr;}
Este es un duplicado más ineficiente de la respuesta aceptada. ¿Por qué copiarías byte por byte en lugar de todos a la vez?
BDL
Encontré el error en la respuesta aceptada en mi código. Llamé a la función dll de C ++ en C #. Parámetro char * usado en c ++, así que usé el método aceptado. [DllImport ("MyDll.dll", EntryPoint = "functionName", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] pero extraño, cuando se utiliza el método aceptado, no se puede obtener IntPtr correcto, se me rompió el búfer , se mostró un poco de búfer como Unicode. así que usé este método
nexdev
-6
En algunos casos, puede usar un tipo Int32 (o Int64) en el caso de IntPtr. Si puede, otra clase útil es BitConverter. Para lo que quieras, puedes usar BitConverter.ToInt32 por ejemplo.
Nunca debe usar Int32 o Int64 en lugar de un puntero . Si tiene que portar su código a una plataforma diferente (32 bits-> 64 bits), tendrá todo tipo de dolores de cabeza.
xxbbcc
55
No, no hay ningún caso válido en el que pueda usar correctamente y de forma segura Int32un puntero. Esta fue una mala práctica realizada hace años y conduce a todo tipo de problemas de portabilidad. Incluso un Int64no es seguro porque ya hay arquitecturas de 128 bits y el tamaño del puntero aumentará. Los punteros solo deben representarse como punteros.
xxbbcc
1
Lo usé en proyectos de .NET CF sin problemas, por supuesto que tendrías problemas si intentas portarlo a otros sistemas, pero hay un código que no está destinado a ser portado.
Alejandro Mezcua
Es cierto que no se planea portar parte del código, pero las cosas pueden cambiar con bastante rapidez. Incluso si su uso en el CF estaba justificado (no lo sé) sigue siendo un mal consejo para una pregunta genérica. El único escenario válido para usar int/ longpara punteros es cuando el lenguaje utilizado no tiene un concepto de ellos (por ejemplo, VB6). C # admite punteros y tiene IntPtr: no hay necesidad de usar un intpuntero en lugar de un puntero. Eliminaré mi -1 si agrega advertencias claras y una explicación de posibles problemas a su respuesta.
xxbbcc
3
Bueno, está comparando el uso de un código de cálculo muy específico con esta pregunta general sobre el uso de punteros en C #. En C # normal no hay escenario en el que esto sea válido. Sé que es una pregunta antigua, pero la rechacé porque la encontré buscando la forma de asignar memoria para un IntPtr; otros también lo verán. Veo su consejo como muy peligroso porque las personas lo seguirán pensando que se salieron con la suya para resolver un problema fácilmente cuando todo lo que tienen son problemas futuros.
GCHandle
método funciona de maravilla ... también elfixed
método. : P :))Respuestas:
No estoy seguro de obtener un IntPtr en una matriz, pero puede copiar los datos para usarlos con código no administrado utilizando Mashal.Copy:
Alternativamente, podría declarar una estructura con una propiedad y luego usar Marshal.PtrToStructure, pero eso aún requeriría asignar memoria no administrada.
Editar: Además, como señaló Tyalis, también puede usar el código fijo si no es seguro para usted.
fuente
Marshal.Copy
con esa sobrecarga se necesita un índice de inicio. La llamada debería serMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
De otra manera,
fuente
Esto debería funcionar pero debe usarse dentro de un contexto inseguro:
¡cuidado, tienes que usar el puntero en el bloque fijo! El gc puede mover el objeto una vez que ya no esté en el bloque fijo.
fuente
Puede usar
Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)
para obtener un puntero de memoria a la matriz.fuente
Aquí hay un giro en la respuesta de @ user65157 (+1 para eso, por cierto):
Creé un contenedor IDisposable para el objeto anclado:
luego úsalo así:
Encontré que esta es una buena manera de no olvidar llamar a Free () :)
fuente
Marshal.Copy funciona pero es bastante lento. Más rápido es copiar los bytes en un bucle for. Incluso más rápido es convertir la matriz de bytes en una matriz ulong, copiar tantos ulong como quepan en la matriz de bytes, luego copiar los 7 bytes restantes posibles (el camino que no está alineado con 8 bytes). Lo más rápido es anclar la matriz de bytes en una declaración fija como se propuso anteriormente en la respuesta de Tyalis.
fuente
fuente
En algunos casos, puede usar un tipo Int32 (o Int64) en el caso de IntPtr. Si puede, otra clase útil es BitConverter. Para lo que quieras, puedes usar BitConverter.ToInt32 por ejemplo.
fuente
Int32
un puntero. Esta fue una mala práctica realizada hace años y conduce a todo tipo de problemas de portabilidad. Incluso unInt64
no es seguro porque ya hay arquitecturas de 128 bits y el tamaño del puntero aumentará. Los punteros solo deben representarse como punteros.int
/long
para punteros es cuando el lenguaje utilizado no tiene un concepto de ellos (por ejemplo, VB6). C # admite punteros y tieneIntPtr
: no hay necesidad de usar unint
puntero en lugar de un puntero. Eliminaré mi -1 si agrega advertencias claras y una explicación de posibles problemas a su respuesta.