2010-02-25 5 views
7

Ich habe eine nicht verwaltete DLL, die die Folowing Funktion exportiert:Rückkehr Zeiger von nicht verwalteten auf verwaltete Code

SomeData* test(); 

Lassen Sie uns somenehmen als:

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

Jetzt will ich von C# diese Funktion aufrufen Code. Ich beginne die C# Struture, um benutzerdefinierte Serialisieren wie dies erforderlich zu definieren:

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

Und jetzt, ich erkläre die verwaltete Funktion:

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

Und in der i Hauptfunktion haben:

IntPtr ptr = test(); 

Dadurch bekomme ich die MarchalDirectiveException: "Kann 'Rückgabewert' nicht marshallen: Ungültige Kombination aus verwaltetem/nicht verwaltetem Typ (Int/UInt muss mit SysInt oder SysUInt gepaart sein)."

Ich habe den Speicher für SomeData in C# nicht zugeordnet, da ich erwarte, dass dieser Speicher in der C-Funktion zugeordnet ist, und ich würde die Marshal.Copy verwenden, um sie an den verwalteten Speicher zu übergeben.

Irgendwelche Ideen? Danke

------------------------ EDITED AFTER JaredPar ANTWORT ----------------- ---

In der Tat habe ich einen Fehler begangen, wenn der Code zu meiner Frage zu bewältigen. Die eigentliche verwaltete Signatur ich war mit war:

[DllImport ("DynamicLibrary.dll", charset = CharSet.Auto)]
[zurück: MarshalAs (UnmanagedType.LPStruct)]
public static extern IntPtr Test();

Die Antwort von JaredPar ist immer noch relevant. Um das richtige Verhalten zu erhalten, habe ich 2 Möglichkeiten:

1) Verwenden Sie die 'public static extern IntPtr test();' (ohne MarshalAs-Attribut) Signatur und dann Zugriff auf den zurückgegebenen Zeiger wie JaredPar vorgeschlagen.

2) Verwenden Sie das 'public static extern SomeData test();' (mit MarshalAs Attribut) und dann einfach SomeData verwenden sd = test();

Antwort

10

Wenn Sie die verwaltete Funktion deklarieren, müssen Sie die Zeigertypen mit Referenzwerten oder IntPtr Werten vergleichen. In diesem Fall hilft der Modifikator LPStruct nicht. Die einfachste Lösung besteht darin, den Rückgabewert des Tests in einen IntPtr anstelle von SomeData zu konvertieren, da die native Methode einen Zeigerwert zurückgibt. Sie können dann den folgenden Wrapper schreiben

[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

Wie Sie in meiner Bearbeitung sehen können, machte ich einen Fehler, wenn ich die Frage schrieb. Ihre Antwort war hilfreich und funktioniert, aber ich bevorzuge die Auswahl 2) meiner Bearbeitungsbereich. Vielen Dank –