Маршалировать параметр, который является ссылочным типом - PullRequest
0 голосов
/ 10 июля 2020

Я пытаюсь вернуть класс C# (не структуру!) Из функции C ++ (используя параметр out). Это сторона C#:

[StructLayout(LayoutKind.Sequential)]
public class OutClass
{
    public int X;
}

// This interface function will be mapped to the C++ function
void MarshalOutClass(out OutClass outClass);

Часть C ++ выглядит так:

struct OutClass
{
    int x = 0;
};

extern "C" MARSHAL_TESTS_API void MarshalOutClass(OutClass** out);

Отображение функций работает через специальный механизм и не является частью этого вопроса. Все атрибуты маршалинга обрабатываются нормально.

В C# мы обычно объявляем out аргументы встроенными, например:

MarshalOutClass(out var outClass);
DoSomething(outClass);

Поскольку ссылочные типы C# маршалируются по указателю, я решил, что я придется добавить еще один указатель на параметры ref или out. Поэтому я использую OutClass** на стороне C ++.

Я предполагаю , что C# переводит

MarshalOutClass(out var outClass);

часть примерно в

OutClass outClass = default(OutClass);
MarshalOutClass(ref outClass);

, что является ссылкой на null, или на стороне C ++: указатель на nullptr. Это не будет проблемой для типов значений C# (также известных как struct), потому что по умолчанию они сконструированы экземпляром по умолчанию.

Это означает, что мне придется вручную создать экземпляр моего объекта на стороне C ++ и упорядочить его обратно до C#.

void MarshalOutClass(OutClass** out)
{
    auto ptr = static_cast<OutClass*>(CoTaskMemAlloc(sizeof(OutClass)));
    *ptr = OutClass{};
    *out = ptr;
}

Код вроде работает, но я не уверен, утекаю ли я с этим памятью, или если маршаллер собирается взять ухаживать за ним должным образом. Я не занимаюсь очисткой на стороне C#.

Это подводит меня к следующим вопросам:

  1. - это мое предположение о том, как ref и out переведено на C ++ правильно?
  2. здесь CoTaskMemAlloc правильная функция?
  3. нужно ли мне выполнять какие-либо дополнительные задачи, связанные с управлением памятью (с обеих сторон)?
  4. есть общий подход правильный здесь? Что мне делать по-другому?

Я знаю, что static_cast<OutClass*>(CoTaskMemAlloc(sizeof(OutClass))) здесь немного схематично, но предположим, что OutClass всегда является тривиальным типом.

...