Маршалинг указатель на массив строк - PullRequest
5 голосов
/ 24 августа 2009

У меня возникли проблемы с маршалингом указателя на массив строк. Это выглядит безобидно, как это:

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

Это на самом деле встроено в другую структуру, подобную этой:

typedef struct
{
    UnmanagedStruct umgdStruct;
} Outerstruct;

Неуправляемый код возвращает обратно в управляемый код и возвращает Outerstruct в виде IntPtr с выделенной памятью и заполненными значениями.

Управляемый мир:

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

Если я изменю listOfStrings на просто IntPtr, тогда Marshal.PtrToStructure работает, но теперь я не могу скопировать в listOfStrings и извлечь строки одну за другой.

Ответы [ 2 ]

4 голосов
/ 24 августа 2009

Выделение чего-либо, кроме очень простой строки, является сложным и полным боковых случаев, которые трудно обнаружить. Обычно лучше использовать безопасный / простой маршрут в определении структуры и добавить некоторые свойства обертки, чтобы немного привести в порядок вещи.

В этом случае я бы использовал массив IntPtr, а затем добавил свойство-обертку, которое преобразует их в строки

[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));
    }
}
1 голос
/ 24 августа 2009

ОК .. Кажется, я получил его на работу. Должно быть маршалировано как IntPtr []

Это похоже на работу:

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