Puede IntPtr ser lanzado en una matriz de bytes sin hacer un Marshal.¿Entendido?


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 de IntPtr en la matriz de bytes. No es una buena solución cuando los datos en cuestión son grandes.

¿Hay alguna manera de convertir un IntPtr a una matriz de bytes? Por ejemplo, sería el siguiente trabajo:

byte[] b = (byte[])intPtr

Esto eliminaría la necesidad de la operación de copia.

También: ¿cómo podemos determinar la longitud de los datos apuntados por IntPtr?

Author: Sabuncu, 2012-03-16

4 answers

Como otros han mencionado, no hay forma de que pueda almacenar los datos en un administrado byte[] sin copiar (con la estructura actual que ha proporcionado*). Sin embargo, si en realidad no necesita que esté en un búfer administrado, puede usar unsafe operaciones para trabajar directamente con la memoria no administrada. Realmente depende de lo que tengas que hacer con él.

Todos los byte[] y otros tipos de referencia son administrados por el Recolector de basura CLR, y esto es lo que es responsable de asignación de memoria y desasignación cuando ya no se usa. La memoria apuntada por el retorno de GetBuffer es un bloque de memoria no administrada asignado por el código C++ y (aparte de los detalles de diseño / implementación de memoria) es esencialmente completamente separada de su memoria administrada GC. Por lo tanto, si desea usar un tipo CLR administrado por GC (byte[]) para contener todos los datos que se encuentran actualmente en su memoria no administrada apuntada por su IntPtr, debe moverse (copiarse) a la memoria que sabe GC sobre. Esto se puede hacer por Marshal.Copy o por un método personalizado usando código unsafe o pinvoke o lo que sea.

Sin embargo, depende de lo que quieras hacer con él. Mencionaste que son datos de video. 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.

En cuanto al tema de la longitud, no hay manera de saber la longitud de un almacenador intermediario de memoria a menos que la función que asignó el almacenador intermediario también le diga cuál es la longitud. Esto se puede hacer de muchas maneras, como los comentaristas han mencionado (primer campo de la estructura, fuera paramtere en el método).

*Finalmente, si usted tiene el control del código C++ podría ser posible modificarlo para que no sea responsable de asignar el búfer en el que escribe los datos, y en su lugar se le proporcione un puntero a un búfer preasignado. A continuación, podría crear un gestionado byte[] en C#, preasignado al tamaño requerido por su código C++, y utilice el GCHandle escriba para anclarlo y proporcionar el puntero a su código C++.

 21
Author: jeffora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-16 06:46:47

Prueba esto:

byte* b = (byte*)intPtr;

Requiere unsafe (en la firma de la función, el bloque o el indicador del compilador /unsafe).

 8
Author: Vinod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-29 16:43:37

No puede hacer que una matriz administrada ocupe memoria no administrada. Puede copiar los datos no administrados un fragmento a la vez, y procesar cada fragmento, o crear una clase UnmanagedArray que tome un IntPtr y proporcione un indexador que seguirá utilizando Marshal.Copia para acceder a los datos.

Como @Vinod ha señalado, puedes hacer esto con el código unsafe. Esto le permitirá acceder a la memoria directamente, utilizando punteros tipo C. Sin embargo, tendrá que ordenar los datos en la memoria administrada antes de llamar cualquier método. NET inseguro, por lo que está prácticamente limitado a su propio código C-like. No creo que debas molestarte con esto en absoluto, simplemente escribe el código en C++.

 2
Author: zmbq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-16 06:17:10

Echa un vistazo a esta página Code Project para encontrar una solución para trabajar con matrices no administradas.

 1
Author: Tsabo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-16 06:15:39