2009-08-24 18 views
5

Mam pewne problemy marshaling wskaźnik do tablicy ciągów. Wygląda nieszkodliwe tak:Marshaling wskaźnik do tablicy ciągów

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

to faktycznie osadzony wewnątrz innej struktury tak:

typedef struct 
{ 
    UnmanagedStruct umgdStruct; 
} Outerstruct; 

kod niezarządzalny oddzwania do kodu zarządzanego i zwraca Outerstruct jako IntPtr z pamięci przydzielonej i wartości wypełnione .

Zarządzane świat:

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

Jeśli zmienię listOfStrings po prostu jako IntPtr, to Marshal.PtrToStructure działa, ale teraz nie mogę zgrać listOfStrings i wyodrębnić ciągi jeden po drugim.

Odpowiedz

1

OK .. I wydaje się, że dostał go do pracy. Należy marshaled jako IntPtr []

To wydaje się działać:

[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 == lokalna tablica, LPArray == wskaźnik do tablicy. Chociaż SizeConst nadal powinien działać z LPArray, więc błąd podczas marszałkowania był trochę dziwny. –

+0

Och, to powinno również działać, jeśli masz publiczne string [] listOfStrings, czyli jego ByValArray, który robi różnicę, w którą wierzę. –

4

Zbieranie wszystkiego poza bardzo prostym ciągiem jest złożone i pełne skrzynek bocznych, które są trudne do wykrycia. Zazwyczaj najlepiej jest wybrać bezpieczną/prostą trasę w definicji struktury i dodać trochę właściwości otoki, aby trochę uporządkować sprawy.

W tym przypadku pójdę z tablicy IntPtr a następnie dodać obiekt wrapper, który konwertuje je na struny

[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 Dzięki za sprawdzenie! Wysłałem odpowiedź na moje własne pytanie właśnie teraz przed zobaczeniem twojego. Jedno pytanie - jak sformatować mój kod w postach? Wszystkie wyglądały na pomieszane, a ktoś musiał je edytować i poprawiać przez cały czas. – Dilip

+0

@Dilip, wybierz fragment kodu i naciśnij CTRL + K. To naprawi formatowanie wciskając wszystko 4 spce – JaredPar

+0

@Jared: tylko krótka obserwacja. Kod nadal bomba, jeśli używam UnmanagedType.LPArray. Działa tylko UnmanagedType.ByValArray. Rozumiem teraz, co powiedział KeeperOf TheSoul w swoich komentarzach. – Dilip