Вы не знаете. P/Invoke может работать только с сигнатурами функций, совместимыми с C, что означает, что указатели должны быть на обычные данные, а не на полные классы C++.
Если вы можете переписать код C++, измените его так, чтобы он вызывал SysAllocString
и возвращал BSTR
, который представляет собой строковый тип, предоставляемый ОС, предназначенный для обмена данными между компонентами, написанными на разных языках. P/invoke уже имеет всю необходимую магию для получения BSTR
, просто используйте тип C# string
в объявлении p/invoke.
Если вы не можете изменить подпись C++, вам придется ее обернуть. Либо используйте C++/CLI, который может работать как с классами C++, так и с .NET, или используйте стандартный C++ и создайте и верните BSTR
, копируя данные из std::wstring
.
Для нескольких строк вы можете использовать предоставленный ОС тип массива (SAFEARRAY), который может содержать внутри BSTR и опять же не зависит от языка. Или может быть проще просто объединить и разделить, используя соответствующий символ-разделитель (не появляющийся естественным образом в данных).
Здесь есть действительно полезная информация: https://msdn.microsoft.com/en-us/magazine/mt795188.aspx
Запустив .NET Framework (реализация Microsoft в Windows), вы можете использовать вспомогательные классы:
#include <windows.h>
#include <atlbase.h>
#include <atlsafe.h>
#include <string>
extern "C" __declspec(dllexport) LPSAFEARRAY GetFileList()
{
std::vector<std::wstring> myList;
//Code that populates the list correctly
size = myList.size();
CComSafeArray<BSTR> sa(size);
int i=0;
for( auto& item : myList ) {
CComBSTR bstr(item.size(), &item[0]);
sa.SetAt(i++, bstr.Detach()); // transfer ownership to array
}
return sa.Detach(); // transfer ownership to caller
}
На стороне C# p/invoke обрабатывает все это:
[DllImport("NativeDll.dll"),
return:MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
public static extern string[] GetFileList();
Ваш вопрос предполагает, что вы можете быть на Linux. К сожалению, документация, которую я нашел, говорит, что p/invoke Mono вообще не знает, что делать с массивами переменного размера. Таким образом, вы застряли, делая все вручную, включая освобождение (код в вашем вопросе пропускает new wstring[size]
- С# абсолютно не знает, как вызвать оператор С++ delete[]
). Посмотрите на Mono.Unix.UnixMarshal.PtrToStringArray
.
person
Ben Voigt
schedule
09.05.2017
std::wstring
в сигнатуре функции, а не просто используется внутри. - person Ben Voigt   schedule 09.05.2017