Первая строка примечаний для Marshal.PtrToStringBSTR
:
Вызывайте этот метод только для строк, которые были выделены с помощью неуправляемых функций SysAllocString и SysAllocStringLen.
Откуда, вероятно, произошел ваш сбой.
Добавьте к этому ваша функция C ++ ожидает BSTR*
(фактически указатель на указатель на первый символ данных в строке), но вы передаете ему указатель на данные.
Помните, что BSTR имеет специальную структуру: он начинается с длины в 4 байта, затем с данных, затем с нулевым значением.Указатель указывает на первый символ data .Так что Marshal.PtrToStringBSTR
смотрит назад от указателя, чтобы найти длину строки - но это не память, которая была выделена Marshal.AllocHGlobal
.
Может случиться так, что ваша функция C ++ делает что-то вроде *data = ....AllocSysString();
- то есть она никогда не читает полученную строку, а вместо этого назначает указатель на строку, которую она выделяет.
В этом случае вы, вероятно, захотите что-то вроде:
[DllImport( ... CallingConvention = CallingConvention.Cdecl)]
public static extern int CppFunc(out IntPtr data);
...
CppFunc(out IntPtr p);
string data = Marshal.PtrToStringBSTR(p);
Marshal.FreeBSTR(p) ;
Здесь мы передаем указатель на указатель.Функция C ++ повторно назначает указатель для указания на первый символ данных в BSTR, и мы используем его для десериализации BSTR, а затем освобождаем его (используя метод, который знает, как освобождать BSTR).
Если это не так, неясно, почему ваша функция C ++ принимает BSTR*
(в отличие от BSTR
), и что она делает с ней.Я думаю, нам нужно понять, прежде чем можно будет сказать что-то еще.
Если ваша функция C ++ взяла вместо BSTR
(помните, что BSTR
сама по себе является указателем), то вы должны использоватьStringBuilder
(с определенной начальной емкостью) - уровень маршаллинга превращает его в указатель, в который может записываться код C ++, и затем вы можете превратить StringBuilder
в строку.
[DllImport( ... CallingConvention = CallingConvention.Cdecl)]
public static extern int CppFunc([MarshalAs(UnmanagedType.BStr)] StringBuilder data);
...
var data = new StringBuilder(512);
CppFunction(data);
string result = data.ToString();