2008-10-09 10 views
25

Tengo la siguiente estructura en C++:Mariscal C++ gama struct en C#

#define MAXCHARS 15 

typedef struct 
{ 
    char data[MAXCHARS]; 
    int prob[MAXCHARS]; 
} LPRData; 

y una función que soy p/invocando a conseguir una serie de 3 de estas estructuras:

void GetData(LPRData *data); 

en C++ yo sólo haría algo como esto:

LPRData *Results; 
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData)); 
GetData(Results); 

Y que iba a funcionar muy bien, pero en C# me parece que no puede conseguir que funcione. He creado un C# estructura 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 inicializar una matriz de 3 de ellos (y todos sus sub-arrays) y pasarlo a esto:

GetData(LPRData[] data); 

Se regresa con éxito, pero los datos en la matriz LPRData no han cambiado.

incluso he tratado de crear una matriz de bytes en bruto del tamaño de 3 de LPRData y pasar eso en un prototipo de función como esta:

GetData (byte [] de datos);

Pero en ese caso obtendré la cadena de "datos" desde la primera estructura LPRData, pero nada después de ella, incluida la matriz "prob" del mismo LPRData.

¿Alguna idea de cómo manejar esto correctamente?

Respuesta

23

Me gustaría probar la adición de algunos atributos a su decloration estructura

[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 pretende representar una variable

JaredPar también es correcto que el uso de la clase IntPtr podría ser útil , pero ha pasado bastante tiempo desde que utilicé PInvoke, así que estoy oxidado.

+1

He utilizado este enfoque, pero tengo excepciones en Mono que las variables se establecen en referencias nulas. Por ejemplo, "prob" es nulo por lo que no quiere funcionar. ¿Se supone que estoy renovando estos en algún momento, o se supone que el marco debe manejarlo de alguna manera? Gracias – swinefeaster

13

Un truco cuando se trata de punteros es utilizar un IntPtr. Luego puede usar Marshal.PtrToStructure en el puntero e incrementar en función del tamaño de la estructura para obtener los 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; 
} 
+2

debe alinearse 11 o bien: cambio '+ =' a '=' y 'ToInt32' a' ToInt64' si se ejecuta de 64 bits; o, elimine 'value.ToInt32()'? – maxwellb

+0

@maxwellb, sí. El código tal como está escrito no es seguro a 64 bits. – JaredPar

+4

lo que estoy consiguiendo en realidad, es que estás asignando incrementos por el incremento de puntero.toInt + sizeof (struct). ¿No sería el incremento solo sizeof (struct)? – maxwellb

2

¿Marcó el parámetro GetData con OutAttribute?

La combinación de la InAttribute y OutAttribute es particularmente útil cuando se aplica a las matrices y, tipos no blittable formateado. Las personas que llaman ven los cambios que un llamado realiza a estos tipos solo cuando aplica ambos atributos.

2

Un tema fue discutido en this question, y el de las conclusiones fue que el parámetro denominado CharSet se debe establecer 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 como sigue:

[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; 
}