2010-02-25 12 views
7

Tengo una DLL administrado que exporta la función folowing:que vuelven punteros de no administrado a código administrado

SomeData* test(); 

Asumamos somedata como:

typedef struct _Data Data; 
struct _Data{ 
    int a; 
    int b; 
} 

Ahora quiero llamar a esta función desde C# código. Comienzo a definir el C# Struture necesaria para el cálculo personalizado así:

[StructLayout(LayoutKind.Sequential)] 
public class SomeData 
{ 
    public Int32 a; 
    public Int32 b; 
} 

Y ahora, declaro la función administrada:

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.LPStruct)] 
public static extern SomeData test(); 

Y en la función principal que tengo:

IntPtr ptr = test(); 

Al hacer esto, obtengo la excepción MarchalDirectiveException: "No se puede obtener el 'valor de retorno': Combinación de tipo administrado/no administrado no válido (Int/UInt debe emparejarse con SysInt o SysUInt)."

No asigné la memoria para SomeData en C# ya que espero que esta memoria esté asignada en la función C y ellos usaría Marshal.Copy para pasarla a la memoria administrada.

¿Alguna idea? Gracias

------------------------ EDITADO DESPUÉS JaredPar RESPUESTA ----------------- ---

De hecho, cometí un error al hacer frente al código de mi pregunta. La firma real administrado yo estaba usando era:

[DllImport ("DynamicLibrary.dll", charset = CharSet.Auto)] [
de retorno: MarshalAs (UnmanagedType.LPStruct)]
extern public static prueba IntPtr();

La respuesta de JaredPar sigue siendo relevante. Para obtener el comportamiento correcto, tengo 2 opciones:

1) Use la prueba de IntPtr externa pública estática(); ' (sin el atributo de MarshalAs) y luego acceder al puntero devuelto como sugirió JaredPar.

2) Utilice la prueba de SomeData (ex) de static extern public(); (con el atributo MarshalAs) y luego simplemente use SomeData sd = test();

Respuesta

10

Al declarar la función administrada, debe hacer coincidir los tipos de puntero con los valores de referencia 0 IntPtr. En este caso, el modificador LPStruct no ayudará. La solución más fácil es convertir el valor de retorno de la prueba en IntPtr en lugar de SomeData ya que el método nativo devuelve un valor de puntero. A continuación, puede escribir el siguiente contenedor

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] 
public static extern IntPtr test(); 

public static SomeData testWrapper() { 
    var ptr = test(); 
    try { 
    return (SomeData)Marshal.PtrToStructure(ptr, typeof(SomeData)); 
    } finally { 
    // Free the pointer here if it's allocated memory 
    } 
} 
+0

Como puede ver en mi edición, cometí un error cuando escribí la pregunta. Su respuesta fue útil y funciona, pero prefiero usar la opción 2) de mi sección de edición. Gracias –

Cuestiones relacionadas