8 Stimmen

Marshaling-Zeiger auf ein Array von Zeichenketten

Ich habe einige Probleme Marshaling einen Zeiger auf ein Array von Zeichenfolgen. Es sieht harmlos wie folgt aus:

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

Diese ist eigentlich in eine andere Struktur wie diese eingebettet:

typedef struct
{
    UnmanagedStruct umgdStruct;
} Outerstruct;

Nicht verwalteter Code ruft verwalteten Code auf und gibt Outerstruct als IntPtr mit zugewiesenem Speicher und eingetragenen Werten zurück.

Verwaltete 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 ändern, um einfach ein IntPtr dann Marshal.PtrToStructure funktioniert, aber jetzt bin ich nicht in listOfStrings rip und extrahieren Sie die Zeichenfolgen eine nach der anderen.

5voto

JaredPar Punkte 699699

Das Marschieren von etwas anderem als einer sehr einfachen Saite ist komplex und voller schwer zu erkennender Nebenfälle. Es ist in der Regel am besten, mit dem sicheren / einfachen Weg in der Strukturdefinition zu gehen und fügen Sie einige Wrapper-Eigenschaften, um die Dinge ein wenig aufzuräumen.

In diesem Fall würde ich mit dem Array von IntPtr gehen und dann eine Wrapper-Eigenschaft hinzufügen, die sie in Zeichenfolgen konvertiert

[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));
    }
}

1voto

Dilip Punkte 213

OK, ich scheine es zum Laufen gebracht zu haben. Es sollte als IntPtr[] marshaled werden.

Das scheint zu funktionieren:

[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]));
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X