2010-01-01 14 views
5

tengo una estructura de C++ que tiene este aspecto:No se puede formar una estructura que contiene una unión

struct unmanagedstruct 
{ 
    int    flags; 
    union 
    { 
     int    offset[6]; 
     struct 
     { 
      float   pos[3]; 
      float   q[4]; 
     } posedesc; 
    } u; 
}; 

Y yo estoy tratando de Mariscal que al igual que en C#:

[StructLayout(LayoutKind.Explicit)] 
public class managedstruct { 
    [FieldOffset(0)] 
    public int flags; 

    [FieldOffset(4), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)] 
    public int[] offset; 

    [StructLayout(LayoutKind.Explicit)] 
    public struct posedesc { 
     [FieldOffset(0), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)] 
     public float[] pos; 

     [FieldOffset(12), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)] 
     public float[] q; 
    } 

    [FieldOffset(4)] 
    public posedesc pose; 
} 

Sin embargo, cuando intento cargar datos en mi estructura, solo están disponibles los primeros 3 elementos de la matriz offset (la longitud de la matriz es 3). Puedo confirmar que sus valores son correctos, pero aún necesito los otros 3 elementos. ¿Estoy haciendo algo obviamente mal?

estoy usando estas funciones para cargar la estructura:

private static IntPtr addOffset(IntPtr baseAddress, int byteOffset) { 
    switch (IntPtr.Size) { 
     case 4: 
      return new IntPtr(baseAddress.ToInt32() + byteOffset); 
     case 8: 
      return new IntPtr(baseAddress.ToInt64() + byteOffset); 
     default: 
      throw new NotImplementedException(); 
    } 
} 

public static T loadStructData<T>(byte[] data, int byteOffset) { 
    GCHandle pinnedData = GCHandle.Alloc(data, GCHandleType.Pinned); 
    T output = (T)Marshal.PtrToStructure(addOffset(pinnedData.AddrOfPinnedObject(), byteOffset), typeof(T)); 
    pinnedData.Free(); 
    return output; 
} 

Cargando ejemplo:

managedstruct mystruct = loadStructData<managedstruct>(buffer, 9000); 

Avísame si necesita más información.

+1

cómo se supone que el código de clasificación para saber cuándo hay que formar la unión como 'int []' 'flotar o []'? ¿Se supone que debe elegir para cada elemento de la matriz, o es siempre uno o el otro? –

Respuesta

1

No estoy 100% seguro de esto, pero creo que la Unión significa que se utiliza la misma memoria para ambos miembros. En el caso de la estructura C++, una estructura int [] o una posedesc. Entonces el tamaño de la estructura será sizeof (int) + sizeof (posedisc). Es decir, Union no significa que tendrá tanto un int [] como un posedisc, tendrá memoria compartida que puede ser cualquiera de esos tipos en C++, pero solo uno o el otro en tierra administrada.

Así que creo que probablemente necesite dos estructuras administradas, una que tenga desplazamiento y otra que tenga posedisc. Puede elegir uno u otro en su llamada a LoadStruct. Opcionalmente, podría crear un campo byte [] y tener propiedades calculadas que conviertan esos bytes en los tipos deseados.

0

Una posible causa de problema podría ser el hecho de que en C++, int tiene un tamaño que depende de la arquitectura.

En otras palabras, en algunas circunstancias, su matriz offset en la estructura C++ puede ser en realidad una matriz de valores de 64 bits.

Ahora, en su estructura C#, siempre que utilizó el atributo MarshalAs, no especifica el parámetro ArraySubType.

Según la documentación, cuando se omite ArraySubType, se supone que la estructura a ser movilizados de acuerdo con el tipo de la matriz administrada, pero tal vez el hecho de que la matriz offset en la estructura C++ no se transmite accros 48 bytes en lugar de 24, está causando el problema que encontraste.

Mi sugerencia sería la de tratar de cambiar todo int a long en la estructura C++ para asegurarse de que el tamaño es siempre la misma, y ​​también añadir el parámetro ArraySubType en todos sus atributos MarshalAs para las matrices.

+0

El tamaño de 'long' también depende de la arquitectura. Sugiero 'int32_t' o cualquiera de los otros tipos de tamaño fijo de' stdint.h'. –

0

Un poco tarde a la fiesta, pero mi mejor conjetura es que la matriz offset se sobreescribe por pos matriz cuando el contador de referencias llega al campo, y será la referencia que se sobreescribe, no los elementos reales. Por lo tanto, offset siempre será de longitud 3 (e intente con GetType, debe devolver Single[]. Esto es lo que obtiene para las referencias superpuestas).

Así que, o se puede eliminar q y establecer pos 'tamaño a 7, o puede utilizar fixed matrices (aunque no estoy seguro de cómo se va a conseguir marshalled).

Cuestiones relacionadas