Передать строку C # в C ++ и передать результат C ++ (string, char * .. что угодно) в C # - PullRequest
13 голосов
/ 01 февраля 2010

Я пробовал разные вещи, но я злюсь на Interop.

(здесь слово string относится не к типу переменной, а к "коллекции символов"): У меня есть неуправляемая функция C ++, определенная в DLL, к которой я пытаюсь получить доступ из C #, эта функция имеет строковый параметр и возвращаемое строковое значение, например:

string myFunction(string inputString)
{
}

Какой должна быть строка на стороне C ++? а C # один? а какие параметры для этого нужны DllImport?

Ответы [ 5 ]

18 голосов
/ 01 февраля 2010

Лучшее, что я нашел, - это быть более ясным о том, что здесь происходит. Наличие строки в качестве возвращаемого типа, вероятно, не рекомендуется в этой ситуации.

Распространенным подходом является передача стороне C ++ буфера и размера буфера. Если он недостаточно велик для того, что GetString должен поместить в него, переменная bufferSize модифицируется, чтобы указать, какой будет подходящий размер. Вызывающая программа (C #) будет тогда увеличивать размер буфера до соответствующего размера.

Если это ваша экспортированная функция dll (C ++):

extern "C" __declspec void GetString( char* buffer, int* bufferSize );

Соответствие C # будет следующим:

void GetString( StringBuilder buffer, ref int bufferSize );

Таким образом, чтобы использовать это в C #, вы должны сделать что-то вроде следующего:

int bufferSize = 512;
StringBuilder buffer = new StringBuilder( bufferSize );
GetString( buffer, ref bufferSize );
2 голосов
/ 11 января 2017

Мне пришлось преобразовать Unicode C # строку в многобайтовое представление, чтобы преобразовать в char * в c ++ (это частичное одностороннее решение)

Я нашел следующее очень полезным

string st; 
IntPtr stPtr = Marshal.StringToHGlobalAnsi(st); 
// Do your thing in C++ 

Marshal.FreeHGlobal(stPtr); 

Это может быть неэффективно и не в C #, я новичок в C #.

2 голосов
/ 02 февраля 2010

Возвращаемое значение "string" является проблемой. Маршаллер P / Invoke собирается вызвать CoTaskMemFree () для указателя, который вы возвращаете. Это не будет работать хорошо, если вы не использовали CoTaskMemAlloc () в своем коде C / C ++ для выделения строкового буфера. Что довольно необычно.

Лучшее решение - позволить вызывающей стороне вашего кода передавать указатель на буфер и длину буфера в качестве аргументов. Таким образом, все выделение памяти происходит с одной стороны. Скотт показал тебе, как это сделать.

2 голосов
/ 01 февраля 2010

Самая большая проблема с передачей строк из C ++ обратно в C # - это выделение памяти. GC должен знать, как очистить память, выделенную для этой строки. Поскольку C # имеет обширную поддержку взаимодействия с COm, он знает о COM BSTR и о том, как их распределять и освобождать. Таким образом, самый простой способ сделать это - использовать BSTR на стороне C ++ и string на стороне C #.

Обратите внимание, использование BSTR не означает, что ваша функция должна быть доступна через COM.

2 голосов
/ 01 февраля 2010

Единственный хороший способ сделать это - написать класс-оболочку .NET C ++, используя Управляемые расширения C ++ , а в объекте .NET C ++ вызвать свой родной C ++ код. В управляемых расширениях есть функции для преобразования System.String в char * или любой другой тип неуправляемой строки.

По сути, вы создаете класс .NET с использованием C ++ и выставляете его из сборки, а внутри этой сборки вы можете вызывать свой собственный код C ++. Другой способ - добавить чистую функцию C в ваш код C ++ с помощью P / Invoke, а затем вызвать ваш код C из C # и заставить вашу функцию C вызывать ваш код C ++. Это будет работать, но я стараюсь использовать как можно больше управляемого кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...