Маршаллинговый тип, который ссылается сам на себя

У меня есть следующее (сокращенное) определение функции в моем коде С++:

EXPORT_API Table* OpenTableExport();

где Table — это структура вида:

typedef struct Table
{
  int fCurrKey;
  int fTableNo;
  int fRecSize;
  char fCreating;
  Table* fNextTable;
  Table* fPrevTable;
  MyFileType fFile;
} Table;

Итак, чтобы PInvoke эту функцию из управляемого кода, я, естественно, попробовал следующее:

[DllImport("Export.dll", EntryPoint = "OpenTableExport", CharSet = CharSet.Auto,   CallingConvention = CallingConvention.Cdecl)]
public static extern Table OpenTable();

Со следующим классом таблицы:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class Table
{
    public KeyDescription fCurrKey;
    public int fTableNo;
    public uint fRecSize;
    public byte fCreating;
    public Table fNextTable;
    public Table fPrevTable;
    public FileDescription fFile;

}

Теперь при использовании метода я получаю следующее исключение (перевод с немецкого):

Поле «fNextTable» типа «Таблица» не может быть маршалировано, для этого типа не существует поддержки маршалинга.

Почему .NET в любом случае не может упорядочить члены fNextTable и fPrevTable того же типа, что и упорядочивающий?

Я также могу просто заменить ссылки в определении управляемого класса на IntPtr... но действительно ли это необходимо? (Тогда сортировка будет работать более или менее).


person Daniel    schedule 31.07.2014    source источник
comment
Вам необходимо определить поля Table* как IntPtr.   -  person Alex F    schedule 31.07.2014
comment
Ну хорошо, я видел такую ​​возможность, я просто не понимаю, зачем это нужно (объект, содержащий эти поля, сортируется правильно)   -  person Daniel    schedule 31.07.2014
comment
Когда вы определяете поле как таблицу, вы просите упорядочить другую структуру таблицы, что создает бесконечную рекурсию. IntPtr — это просто указатель, вы получаете его, а затем передаете другому API, ожидающему Table*, или используете методы Marshal для работы с неуправляемой памятью, например PtrToStructure.   -  person Alex F    schedule 31.07.2014
comment
Ах, хорошо, я понимаю, к чему вы клоните, в некотором смысле имеет смысл (хотя рекурсия не обязательно будет бесконечной, я думаю, это зависит от того, как реализована сортировка). Если вы вставите это в ответ, я с радостью приму его, большое спасибо.   -  person Daniel    schedule 31.07.2014


Ответы (1)


Определите структуру следующим образом:

public class Table
{
    public KeyDescription fCurrKey;
    public int fTableNo;
    public uint fRecSize;
    public byte fCreating;
    public IntPtr fNextTable;
    public IntPtr fPrevTable;
    public FileDescription fFile;
}

Протестируйте элементы IntPtr на NULL (IntPtr.Zero) и обработайте их. Вероятно, неуправляемый API содержит другие функции, ожидающие Table*. См. также метод Marshal.PtrToStructure и другие низкоуровневые методы Marshal для обмена управляемой и неуправляемой памятью.

person Alex F    schedule 31.07.2014