c# - ¿Se puede convertir IntPtr en una matriz de bytes sin hacer un Marshal.Copy?
.net (4)
Como han mencionado otros, no hay forma de que pueda almacenar los datos en un byte[]
administrado byte[]
sin copiar (con la estructura actual que ha proporcionado *). Sin embargo, si realmente no necesita que esté en un búfer administrado, puede usar operaciones unsafe
para trabajar directamente con la memoria no administrada. Realmente depende de lo que tengas que hacer con eso.
Todo el byte[]
y otros tipos de referencia son administrados por el recolector de basura CLR, y esto es lo que es responsable de la asignación de memoria y desasignación cuando ya no se usa. La memoria señalada por el retorno de GetBuffer
es un bloque de memoria no administrada asignada por el código C ++ y (aparte de los detalles de diseño / implementación de la memoria) está esencialmente completamente separada de la memoria administrada por GC. Por lo tanto, si desea usar un tipo de CLR administrado por GC ( byte[]
) para contener todos los datos que se mantienen actualmente dentro de la memoria no administrada a la que apunta su IntPtr
, debe ser movido (copiado) a la memoria que el GC conoce. Esto puede ser realizado por Marshal.Copy
o por un método personalizado utilizando código unsafe
o pinvoke o lo que sea.
Sin embargo, depende de lo que quieras hacer con él. Usted ha mencionado que los datos de vídeo. Si desea aplicar alguna transformación o filtro a los datos, probablemente pueda hacerlo directamente en el búfer no administrado. Si desea guardar el búfer en el disco, probablemente pueda hacerlo directamente en el búfer no administrado.
Sobre el tema de la longitud, no hay forma de saber la longitud de un búfer de memoria no administrado a menos que la función que asignó el búfer también le indique cuál es la longitud. Esto se puede hacer de muchas maneras, como han mencionado los comentaristas (primer campo de la estructura, fuera del alcance del método).
* Finalmente, si tiene el control del código C ++, podría ser posible modificarlo para que no sea responsable de asignar el búfer al que escribe los datos y, en cambio, se le proporcione un puntero a un búfer preasignado. Luego, puede crear un byte[]
administrado byte[]
en C #, preasignado al tamaño requerido por su código C ++, y usar el tipo GCHandle
para GCHandle
y proporcionar el puntero a su código C ++.
Quiero obtener datos de un puntero IntPtr en una matriz de bytes. Puedo usar el siguiente código para hacerlo:
IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);
Pero el código anterior fuerza una operación de copia desde IntPtr a la matriz de bytes. No es una buena solución cuando los datos en cuestión son grandes.
¿Hay alguna forma de convertir un IntPtr a una matriz de bytes? Por ejemplo, funcionaría lo siguiente:
byte[] b = (byte[])intPtr
Esto eliminaría la necesidad de la operación de copia.
Además: ¿cómo podemos determinar la longitud de los datos señalados por IntPtr?
No puede tener una matriz administrada ocupar memoria no administrada. Puede copiar los datos no administrados una porción a la vez y procesar cada una, o crear una clase IntPtr
que toma un IntPtr
y proporciona un indexador que aún utilizará Marshal.Copy para acceder a los datos.
Como lo señaló @Vinod, puedes hacerlo con unsafe
código unsafe
. Esto le permitirá acceder directamente a la memoria, utilizando punteros tipo C. Sin embargo, deberá reunir los datos en la memoria administrada antes de llamar a cualquier método .NET inseguro, por lo que está bastante limitado a su propio código tipo C. No creo que debas preocuparte por esto, simplemente escribe el código en C ++.
Visite esta página de Proyecto de código para obtener una solución para trabajar con matrices no administradas.