2009-08-24 5 views
5

Tengo problemas para seleccionar un puntero a una serie de cadenas. Parece inofensiva como esto:Puntero de mazo a una matriz de cadenas

typedef struct 
{ 
    char* listOfStrings[100]; 
} UnmanagedStruct; 

Esto es en realidad incrustado dentro de otra estructura como esta:

typedef struct 
{ 
    UnmanagedStruct umgdStruct; 
} Outerstruct; 

código no administrado llama de nuevo en código administrado y devuelve Outerstruct como IntPtr con memoria asignada y los valores rellenado .

mundo administrado:

[StructLayout(LayoutKind.Sequential)] 
public struct UnmanagedStruct 
{ 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)] 
    public string[] listOfStrings; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct Outerstruct 
{ 
    public UnmanagedStruct ums; 
} 

public void CallbackFromUnmanagedLayer(IntPtr outerStruct) 
{ 
    Outerstruct os = Marshal.PtrToStructure(outerStruct, typeof(Outerstruct)); 
    // The above line FAILS! it throws an exception complaining it cannot marshal listOfStrings field in the inner struct and that its managed representation is incorrect! 
} 

Si cambio listOfStrings para que sea simplemente un IntPtr, entonces Marshal.PtrToStructure funciona, pero ahora no puedo copiar listOfStrings y extraer las cadenas una a una.

Respuesta

1

OK .. me parece que han conseguido que funcione. Hay que calcular las referencias como IntPtr []

Esto parece funcionar:

[StructLayout(LayoutKind.Sequential)] 
public struct UnmanagedStruct 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=100)] 
    public IntPtr[] listOfStrings; 
} 

for (int i = 0; i < 100; ++i) 
{ 
    if (listOfstrings[i] != IntPtr.Zero) 
     Console.WriteLine(Marshal.PtrToStringAnsi(listOfStrings[i])); 
}  
+0

ByValArray == matriz en contexto, LPArray == un puntero a una matriz. Aunque SizeConst aún debería funcionar con un LPArray, entonces el error al calcular referencias fue un poco extraño. –

+0

Oh, eso también debería funcionar si tiene cadena pública [] listOfStrings, es la ByValArray que hace la diferencia, creo. –

4

Marcar todo lo que no sea una cuerda muy básica es complejo y está lleno de cajas laterales que son difíciles de detectar. Por lo general, es mejor ir con la ruta segura/simple en la definición de estructura y agregar algunas propiedades de envoltura para arreglar un poco las cosas.

En este caso me gustaría ir con la serie de IntPtr y luego añadir una propiedad de contenedor que se convierte en cadenas

[StructLayout(LayoutKind.Sequential)] 
public struct UnmanagedStruct 
{ 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)] 
    public IntPtr[] listOfStrings; 

    public IEnumerable<string> Strings { get { 
     return listOfStrings.Select(x =>Marshal.PtrToStringAnsi(x)); 
    } 
} 
+0

Jared Gracias por validar! Publiqué una respuesta a mi propia pregunta justo antes de ver la tuya. Una pregunta: ¿cómo formateo mi código en las publicaciones? Todos parecían desordenados y alguien tiene que editarlo y corregirlo todo el tiempo. – Dilip

+0

@Dilip, seleccione su fragmento de código y presione CTRL + K. Eso arreglará el formateo al sangrar todo 4 spcaes – JaredPar

+0

@Jared: solo un seguimiento rápido. El código continúa bombardeando si uso UnmanagedType.LPArray. Solo funciona UnmanagedType.ByValArray. Ahora entiendo lo que Keeper Of TheSoul estaba insinuando en sus comentarios. – Dilip

Cuestiones relacionadas