Marshal C ++ estructura array en C #
-
06-07-2019 - |
Pregunta
Tengo la siguiente estructura en C ++:
#define MAXCHARS 15
typedef struct
{
char data[MAXCHARS];
int prob[MAXCHARS];
} LPRData;
Y una función en la que estoy invocando para obtener una matriz de 3 de estas estructuras:
void GetData(LPRData *data);
En C ++ simplemente haría algo como esto:
LPRData *Results;
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData));
GetData( Results );
Y funcionaría bien, pero en C # parece que no puedo hacer que funcione. He creado una estructura C # como esta:
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}
Y si inicializo una matriz de 3 de ellos (y todas sus sub-matrices) y la paso a esto:
GetData(LPRData[] data);
Regresa con éxito, pero los datos en la matriz LPRData no han cambiado.
Incluso intenté crear una matriz de bytes sin procesar del tamaño de 3 LPRData y pasarla a un prototipo de función como este:
GetData (byte [] datos);
Pero en ese caso obtendré los "datos" cadena de la primera estructura LPRData, pero nada después, incluido el "prob" matriz del mismo LPRData.
¿Alguna idea de cómo manejar esto correctamente?
Solución
Intentaría agregar algunos atributos a su estructura decloration
[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable]
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}
* Nota TotalBytesInStruct no está destinado a representar una variable
JaredPar también tiene razón en que usar la clase IntPtr podría ser útil, pero ha pasado bastante tiempo desde que usé PInvoke, así que estoy oxidado.
Otros consejos
Un truco cuando se trata de punteros es usar un IntPtr. Luego puede usar Marshal.PtrToStructure en el puntero e incrementar según el tamaño de la estructura para obtener sus resultados.
static extern void GetData([Out] out IntPtr ptr);
LPRData[] GetData()
{
IntPtr value;
LPRData[] array = new LPRData[3];
GetData(out value);
for (int i = 0; i < array.Length; i++)
{
array[i] = Marshal.PtrToStructure(value, typeof(LPRData));
value += Marshal.SizeOf(typeof(LPRData));
}
return array;
}
El Asistente de interoperabilidad PInvoke puede ayudar. http://clrinterop.codeplex.com/releases/view/14120
¿Marcó el parámetro GetData con OutAttribute ?
Combinando InAttribute y OutAttribute es particularmente útil cuando se aplica a matrices y formateado, tipos no blittables. Las personas que llaman ven el cambios que hace un llamado a estos tipos solo cuando aplica ambos atributos.
Se discutió un tema similar en esta pregunta , y la de La conclusión fue que el parámetro con nombre CharSet
debe establecerse en CharSet.Ansi
. De lo contrario, estaríamos haciendo una matriz wchar_t
en lugar de una matriz char
. Por lo tanto, el código correcto sería el siguiente:
[Serializable]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct LPRData
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}