¿Cómo puedo pasar un puntero a una matriz usando p/invoke en C#?

2 minutos de lectura

avatar de usuario
Randy Sugianto ‘Yuku’

Ejemplo de firma de API C:

void Func(unsigned char* bytes);

En C, cuando quiero pasar un puntero a una matriz, puedo hacer:

unsigned char* bytes = new unsigned char[1000];
Func(bytes); // call

¿Cómo traduzco la API anterior a P/Invoke de modo que pueda pasar un puntero a la matriz de bytes de C#?

avatar de usuario
una esponja

La forma más fácil de pasar una matriz de bytes es declarar el parámetro en su declaración de importación como una matriz de bytes.

[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(byte[]);

byte[] ar = new byte[1000];
Func(ar);

También debería poder declarar el parámetro como IntPtr y ordenar los datos manualmente.

[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(IntPtr p);

byte[] ar = new byte[1000];
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte)) * ar.Length);
Marshal.Copy(ar, 0, p, ar.Length);
Func(p);
Marshal.FreeHGlobal(p);

  • ¿Por qué funcionaría el primer enfoque y el segundo no? Esto es lo que estoy enfrentando en una aplicación de Windows Phone.

    usuario604919

    18 de noviembre de 2014 a las 15:29

  • Sé que esta publicación es un poco vieja, pero Marshal.SizeOf(object) no funciona con matrices. Estoy bastante seguro de que obtendrá una excepción si le pasa una matriz, pero no tengo VS abierto frente a mí en este momento para intentarlo. Para determinar correctamente el tamaño de una matriz, para su ejemplo, el código sería Marshal.SizeOf(typeof(byte)) * ar.Length.

    – 9ee1

    2 de marzo de 2015 a las 6:44


  • Sí, tienes razón 9ee1. Marshal.SizeOf se puede usar para una estructura pero no para una matriz. He actualizado el código de ejemplo en consecuencia. Gracias.

    – una esponja

    18 de marzo de 2015 a las 13:34

avatar de usuario
FlySwat

Puedes usar un código no seguro:

unsafe 
{
     fixed(byte* pByte = byteArray)
     IntPtr intPtr = new IntPtr((void *) pByte);
     Func(intPtr);
}

Si necesita usar un código seguro, puede usar algunos trucos:

IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(byteArray));
Marshal.Copy(byteArray, 0, intPtr, Marshal.SizeOf(byteArray));

Func(intPtr);

Marshal.FreeHGlobal(intPtr);

Sin embargo, el código seguro va a ser lento en mi humilde opinión.

Aquí está la firma apropiada para la función nativa.

[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="Func")]
public static extern  void Func(System.IntPtr bytes) ;

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad