2009-08-24 17 views
5

Ich habe Probleme, einen Zeiger auf ein Array von Strings Marshalling. Es sieht harmlos wie folgt aus:Marshalling-Zeiger auf ein Array von Strings

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

Dies ist eigentlich in einer anderen Struktur wie folgt eingebettet:

typedef struct 
{ 
    UnmanagedStruct umgdStruct; 
} Outerstruct; 

Unmanaged Code ruft zurück in verwaltetem Code und gibt Outerstruct als IntPtr mit Speicher zugeordnet und gefüllt Werte in .

Managed Welt:

[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! 
} 

Wenn ich listOfStrings so ändere, dass es einfach ein IntPtr ist, dann funktioniert Marshal.PtrToStructure, aber jetzt kann ich nicht in listOfStrings rippen und die Strings einzeln extrahieren.

Antwort

1

OK .. Ich habe zu haben scheinen Strings konvertiert sie zu arbeiten. Es sollte als IntPtr []

scheint gemarshallt werden dies funktioniert:

[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 == In-Place-Array, LPArray == Ein Zeiger auf ein Array. Obwohl SizeConst immer noch mit einem LPArray arbeiten sollte, war der Fehler beim Marshalling ein wenig seltsam. –

+0

Oh, das sollte auch funktionieren, wenn Sie öffentliche string [] listOfStrings haben, es ist der ByValArray, der den Unterschied macht, glaube ich. –

4

Das Marshalling von allem außer einer sehr einfachen Saite ist komplex und voller Side Cases, die schwer zu erkennen sind. Es ist normalerweise am besten, mit der sicheren/einfachen Route in der Struct-Definition zu gehen und ein paar Wrapper-Eigenschaften hinzuzufügen, um die Dinge etwas aufzuräumen.

In diesem Fall habe ich mit der Anordnung von IntPtr gehen würde und dann eine Wrapper-Eigenschaft hinzufügen, die sie

[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 Dank für die Validierung! Ich habe gerade eine Antwort auf meine eigene Frage gepostet, bevor ich deine gesehen habe. Eine Frage - wie formatiere ich meinen Code in Posts? Sie sahen alle durcheinander und jemand muss es ständig bearbeiten und korrigieren. – Dilip

+0

@Dilip, wählen Sie Ihr Code-Snippet und drücken Sie STRG + K. Das wird die Formatierung durch Einrücken alles 4 spcaes – JaredPar

+0

@Jared beheben: nur eine kurze Folge. Der Code bombardiert weiter, wenn ich UnmanagedType.LPArray verwende. Nur UnmanagedType.ByValArray funktioniert. Ich verstehe jetzt, was KeeperOfTheSoul in seinen/ihren Kommentaren angedeutet hat. – Dilip

Verwandte Themen