Каков утвержденный способ преобразования из char * в System :: string и обратно в C++ / CLI? Я нашел несколько ссылок на шаблонные функции marshal_to <> в Google, но похоже, что эта функция никогда не использовалась для Visual Studio 2005 (и ее также нет в Visual Studio 2008, AFAIK). Я также видел некоторый код на Блог Стэна Липпмана, но это с 2004 года. Я также видел Marshal :: StringToHGlobalAnsi (). Есть ли метод, который считается «лучшей практикой»?





Мы сделали объект C++ \ CLI, который содержал строку в неманговом коде и выдавал управляемые копии элемента. Код преобразования очень похож на тот, который есть у Стэна в своем блоге (я не могу его точно вспомнить) (если вы используете его код, убедитесь, что вы обновили его, чтобы использовать delete []), но мы позаботились о том, чтобы деструктор справился с выпуском всех неподключенные элементы объекта. Это немного преувеличено, но у нас не было утечек, когда мы использовали устаревшие модули кода C++.
Здесь есть хороший обзор (эта поддержка маршалинга добавлена для VS2008): http://www.codeproject.com/KB/mcpp/OrcasMarshalAs.aspx
Для тех, кому интересно, полное пространство имен для контекста - msclr::interop::marshal_context.
System :: String имеет конструктор, который принимает символ *:
using namespace system;
const char* charstr = "Hello, world!";
String^ clistr = gcnew String(charstr);
Console::WriteLine(clistr);
Получить назад char * немного сложнее, но не так уж и плохо:
IntPtr p = Marshal::StringToHGlobalAnsi(clistr);
char *pNewCharStr = static_cast<char*>(p.ToPointer());
cout << pNewCharStr << endl;
Marshal::FreeHGlobal(p);
+1, конструктор System :: String также принимает длину и кодировку!
Marshal::StringToHGlobalAnsi - плохой вариант по сравнению с marshal_context (как упоминал Мэтью), который использует RAII для автоматического освобождения буфера. Не говоря уже о том, что название полностью неправильное, оно вообще не возвращает HGLOBAL.
Ваш пример не работает для меня в C++ / CLI с использованием .NET 4.6.1. Не существует конструктора System :: String, который принимает char * ... только подписанный char * или wchar_t *
Я давно не был в этом мире, но я считаю, что это все еще должно работать. Согласно документации на docs.microsoft.com/en-us/cpp/windows/…, вы все равно должны иметь возможность gcnew для строки со строкой char * в качестве аргумента. Может можно на signed char * закинуть?
По моему опыту, указатель также не имеет нулевого терминатора. Вам нужно использовать cluster.Length, чтобы узнать, сколько он длится.
Я создал несколько вспомогательных методов. Мне нужно было сделать это, чтобы перейти от старой библиотеки Qt к CLI String. Если кто-нибудь может добавить к этому и сказать мне, кажется ли у меня утечка памяти и что я могу сделать, чтобы исправить это, я был бы очень признателен.
void MarshalString ( String ^ s, wstring& os ) {
using namespace Runtime::InteropServices;
const wchar_t* char = (const wchar_t*)(Marshal::StringToHGlobalUni(s)).ToPointer();
os = char;
}
QString SystemStringToQt( System::String^ str)
{
wstring t;
MarshalString(str, t);
QString r = QString::fromUcs2((const ushort*)t.c_str());
return r;
}
Наверное придется Marshal :: FreeHGlobal (IntPtr ((void *) chars)); Это
@Pat да, извините, я должен был обновить это после этого. Теперь у меня все получилось. Перенос его на .NET увеличил производительность этого приложения в 3 раза. Даже упорядочивание вещей.
Еще одна ссылка на список возможных способов:
Спасибо, но это длинное объяснение. Это ближе к делу:
#include <msclr\marshal.h> // marshal_context context; // my_c_string = context.marshal_as<const char*>(my_csharp_string);