Как конвертировать 'System :: String ^' в 'TCHAR'? - PullRequest
2 голосов
/ 14 апреля 2011

я задал вопрос здесь с участием C ++ и C # общения. Проблема была решена, но привела к новой проблеме.

возвращает строку (C #)

return Marshal.PtrToStringAnsi(decryptsn(InpData));

это ожидает TCHAR * (C ++)

lpAlpha2[0] = Company::Pins::Bank::Decryption::Decrypt::Decryption("123456");

Я гуглил, как решить эту проблему, но я не уверен, почему в строке есть морковь (^). Будет ли лучше изменить возврат из String на что-то еще, что C ++ будет принимать? или мне нужно сделать преобразование, прежде чем присваивать значение?

Ответы [ 3 ]

4 голосов
/ 14 апреля 2011

Синтаксис String^ - это C ++ / CLI talk для "(сборка мусора) ссылки на System.String".

У вас есть несколько вариантов преобразования String в строку C, что является другим способом выражения TCHAR*. Мой предпочтительный способ в C ++ - хранить преобразованную строку в строковом типе C ++, либо std::wstring, либо std::string, в зависимости от того, строите ли вы проект как Unicode или MBCS.

В любом случае вы можете использовать что-то вроде этого:

std::wstring tmp = msclr::interop::marshal_as<std::wstring>( /* Your .NET String */ );

или

std::string tmp = msclr::interop::marshal_as<std::string>(...);

Как только вы преобразовали строку в правильный формат широкой или узкой строки, вы можете получить доступ к ее строковому представлению C, используя функцию c_str(), например, так:

callCFunction(tmp.c_str());

Предполагая, что callCFunction ожидает, что вы передадите его в C-стиле char* или wchar_t* (что TCHAR* будет "ухудшаться" в зависимости от ваших настроек компиляции.

4 голосов
/ 14 апреля 2011

String имеет ^, потому что это маркер для управляемой ссылки. По сути, он используется так же, как * в неуправляемой земле, за исключением того, что он может указывать только на тип объекта, а не на другие типы указателей или на void.

TCHAR - это #defined (или, возможно, typedefed, я не помню) либо char, либо wchar_t, в зависимости от определения препроцессора _UNICODE. Поэтому я бы использовал это и написал бы код дважды.

Любой встроенный:

TCHAR* str;
String^ managedString
#ifdef _UNICODE
str = (TCHAR*) Marshal::StringToHGlobalUni(managedString).ToPointer();
#else
str = (TCHAR*) Marshal::StringToHGlobalAnsi(managedString).ToPointer();
#endif

// use str.

Marshal::FreeHGlobal(IntPtr(str));

или в виде пары методов преобразования, которые предполагают, что выходной буфер уже выделен и достаточно велик. Перегрузка метода должна заставить его выбрать правильный, в зависимости от того, как определен TCHAR.

void ConvertManagedString(String^ managedString, char* outString)
{
    char* str;
    str = (char*) Marshal::StringToHGlobalAnsi(managedString).ToPointer();    
    strcpy(outString, str);    
    Marshal::FreeHGlobal(IntPtr(str));
}

void ConvertManagedString(String^ managedString, wchar_t* outString)
{
    wchar_t* str;
    str = (wchar_t*) Marshal::StringToHGlobalUni(managedString).ToPointer();    
    wcscpy(outString, str);    
    Marshal::FreeHGlobal(IntPtr(str));
}
2 голосов
/ 14 апреля 2011

Это действительно бессмысленный способ задать вопрос, но если вы имеете в виду, как преобразовать String ^ в char *, то вы используете тот же самый маршаллер, который вы использовали ранее, только назад:

char* unmanagedstring = (char *) Marshal::StringToHGlobalAnsi(managedstring).ToPointer();

Редактировать: не забудьте освободить память, выделенную, когда вы закончите, используя Marshal::FreeHGlobal.

...