2009-08-03 13 views
3

Struktur mit einem String-Rangier habe ich ein C++ structPInvoke Fehler, wenn in ihm

struct UnmanagedStruct 
{ 
    char* s; 
    // Other members 
};

und ein C# struct

struct ManagedStruct { 
    [MarshalAs(UnmanagedType.LPStr)] 
    string s; 
    // Other members 
}

die C++ Bibliothek

extern "C" UnmanagedStruct __declspec(dllexport) foo(char* input); 

aussetzt Und es ist importiert wie

[DllImport("SomeDLL.dll", CharSet = CharSet.Ansi)] 
    static extern ManagedStruct foo(string input); 

Jedoch, wenn ich diese Funktion aufrufen bekomme ich

MarshalDirectiveException unhandled war

Methode der Art Signatur nicht kompatibel ist PInvoke.

Die Sache ist, funktioniert dieser Funktionsaufruf, wenn ich die char * s und die Zeichenfolge s aus den Strukturen entfernen.

Antwort

4

Verwenden Sie für diese Art von Szenario keinen String direkt. Wechseln Sie stattdessen den Typ zu einem IntPtr-Wert und verwenden Sie Marshal.PtrToStringAuto/Ansi/Uni entsprechend. In diesem Fall ist PtrToStringAnsi die beste Wahl, da Ihr systemeigener Code char* verwendet.

struct ManagedStruct { 
    IntPtr s; 
    public string sAsString { get { return Marshal.PtrToStringAnsi(s); } } 
} 
+0

Warum muss ich das tun? Ich habe diese Frage früher gestellt und die Leute sagten alle, es würde "einfach funktionieren". – DevDevDev

+0

@SteveM, Strings + PInvoke = schwierig. Strings funktionieren nur in vielen Szenarien, aber nur in vielen anderen :). Strings als Felder einer Struktur sind besonders herausfordernd, weil es ein großes Problem der Speicherverwaltung gibt. Was sollte die CLR insbesondere mit dem Speicher tun, der zum Erstellen der verwalteten Zeichenfolge verwendet wird? Sollte es es befreien oder nichts tun? Im Allgemeinen, wenn die CLR so etwas sieht, wird davon ausgegangen, dass sie die Daten freigeben muss und CoTaskMemFree auf den Wert aufruft, der in Ihrem Szenario wahrscheinlich falsch ist. – JaredPar

+0

(Fortsetzung). Wenn Sie sich jemals darüber im Klaren sind, wie ein String gemarshallt werden soll (und es ist kein Inline-Array), verwenden Sie IntPtr und übergeben Sie den String manuell. Dies hat eine viel bessere Chance zu arbeiten – JaredPar