Передайте строку С# на С++ и передайте результат С++ (строка, char *.. безотносительно) к С#
Я пробовал разные вещи, но я злюсь с Interop.
(здесь словосочетание не относится к варианту типа, а "набор из char" ):
У меня есть неуправляемая функция С++, определенная в dll, которую я пытаюсь получить с С#, эта функция имеет строковый параметр и возвращаемое значение строки следующим образом:
string myFunction(string inputString)
{
}
Что должно быть на стороне С++? и С# один? и для каких параметров нужен DllImport для этого?
Ответы
Ответ 1
То, что я нашел для работы лучше всего, - это более конкретное описание того, что происходит здесь. Наличие этой строки в качестве возвращаемого типа, вероятно, не рекомендуется в этой ситуации.
Общий подход заключается в том, чтобы сторона С++ передавала буфер и размер буфера. Если он недостаточно велик для того, что ему нужно положить в GetString, переменная bufferSize изменяется, чтобы указать, какой будет соответствующий размер. Затем вызывающая программа (С#) увеличит размер буфера до соответствующего размера.
Если это ваша экспортированная DLL-функция (С++):
extern "C" __declspec void GetString( char* buffer, int* bufferSize );
Соответствие С# будет следующим:
void GetString( StringBuilder buffer, ref int bufferSize );
Итак, чтобы использовать это в С#, вы должны сделать что-то вроде следующего:
int bufferSize = 512;
StringBuilder buffer = new StringBuilder( bufferSize );
GetString( buffer, ref bufferSize );
Ответ 2
Единственный хороший способ, которым я знаю это сделать, - написать класс оболочки .NET С++ с помощью Управляемые расширения С++, а внутри объекта .NET С++ вызывается собственный С++-код. В управляемых расширениях есть функции для преобразования System.String в char * или любой другой тип неуправляемой строки.
В принципе, вы создаете .NET-класс с использованием С++ и выставляете его из сборки, а внутри этой сборки вы можете вызвать собственный С++-код. Другим способом является добавление чистой C-функции к вашему С++-коду с использованием P/Invoke, а затем вызов вашего C-кода из С#, и ваша функция C вызовет ваш код на С++. Это будет работать, но я стараюсь как можно больше использовать управляемый код.
Ответ 3
Самая большая проблема с передачей строк из С++ обратно в С# - выделение памяти. GC должен уметь знать, как очистить память, выделенную для этой строки. Поскольку С# имеет обширную поддержку взаимодействия COm, он знает о COM BSTR и как распределять и освобождать их. Таким образом, самый простой способ сделать это - использовать BSTR
на стороне С++ и string
на стороне С#.
Примечание. Использование BSTR не означает, что ваша функция должна быть открыта через COM.
Ответ 4
Возвращаемое значение строки является проблемой. Маршрутизатор P/Invoke будет вызывать CoTaskMemFree() на возвращаемом указателе. Это не сработает, если вы не использовали CoTaskMemAlloc() в коде на C/С++, чтобы выделить строковый буфер. Это довольно необычная вещь.
Лучшее решение - позволить вызывающему вашему коду передать указатель на буфер и длину буфера в качестве аргументов. Таким образом, все распределение памяти происходит с одной стороны. Скотт показал вам, как это сделать.
Ответ 5
Мне пришлось преобразовать строку Unicode С# в многобайтовое представление, чтобы преобразовать в char * в С++ (это частичное одностороннее решение)
Я нашел следующие очень полезные
string st;
IntPtr stPtr = Marshal.StringToHGlobalAnsi(st);
// Do your thing in C++
Marshal.FreeHGlobal(stPtr);
Это может быть неэффективным, а не способом С#, я новичок в С#, надеюсь, что это поможет