Ситуация: у меня есть управляемое (C#, .NET 2.0) приложение, которое использует неуправляемую (C++) DLL с помощью P/Invoke. Наряду с «простыми» методами (аргументы POD/возвращаемое значение) требуется передавать в код массивы значений boost::variant. Причина этого в том, что эти методы передают данные отчета (аналогично ячейкам Excel, которые могут быть любого типа). Код С# принимает их как «объекты» в штучной упаковке.
Предыдущая реализация требовала использования SafeArray COM VARIANT. Однако из-за плохого кодирования/отсутствия тестирования сортировка привела к утечке памяти. Теперь мне нужно найти другой вариант сортировки данных.
Предыдущая реализация выглядела так: C++:
extern "C" __declspec(dllexport) void GetReport(VARIANT& output) {
// ... here a SafeArray of VARIANT values was created
output.vt = VT_VARIANT | VT_ARRAY;
output.parray = safeArray;
}
С#
[DllImport("CppLibrary.dll")]
private static extern void GetReport(out object output);
//....
object data;
GetReport(data);
object rows = data as object[];
Эта конкретная реализация приводит к утечке памяти, поскольку не освобождает структуры взаимодействия.
Я попытался изменить прототипы, включив директивы сортировки SafeArray:
С++
extern "C" __declspec(dllexport) void GetReport(SAFEARRAY output) { // Also tried SAFEARRAY*, SAFEARRAY&, VARIANT, VARIANT&, VARIANT*
// Internal stuff
}
С#
private static extern void GetReport([Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]ref object[] output);
Однако единственное, чего я добился, это либо пустой результирующий объект(ы), либо сбой из-за повреждения памяти/переполнения стека.
Проблема: как правильно маршалировать такой тип данных (массив структур типа VARIANT) в C#? Я могу сделать C++ DLL COM-библиотекой, но для этого потребуется переписать довольно много кода. Есть ли более простой выход из ситуации? Может быть, я что-то упускаю.