Преобразование C ++ / CLI из System :: String ^ в std :: string


91

Может ли кто-нибудь опубликовать простой код, который преобразует,

System::String^

Чтобы,

C ++ std::string

Т.е. я просто хочу присвоить значение,

String^ originalString;

Чтобы,

std::string newString;

Ответы:


38

Зацените System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()и своих друзей.

Извините, не могу отправить код сейчас; У меня нет VS на этом компьютере, чтобы проверить его компиляцию перед публикацией.


162

Не катитесь самостоятельно, используйте эти удобные (и расширяемые) оболочки, предоставляемые Microsoft.

Например:

#include <msclr\marshal_cppstd.h>

System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);

2
спасибо за эту полезную ссылку, эта подсказка сэкономила мне много кода. в качестве примечания: шаблоны / классы находятся в #include <msclr \ *. h> (например, #include <msclr \ marshal.h>) и в пространстве имен msclr :: interop, см. пример на msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker

4
Хотя это удобно, в нем полностью отсутствует надлежащая поддержка кодирования. См. Также мой вопрос SO: stackoverflow.com/questions/18894551/… . Я предполагаю, что marshal_as преобразует строки Unicode в ACP в std :: string.
Майк Лишке

MS рекомендует использовать marshal_context и удалить его после завершения преобразования. Ссылка: msdn.microsoft.com/en-us/library/bb384856.aspx
Руслан Макренко

40

Вы можете легко сделать это следующим образом

#include <msclr/marshal_cppstd.h>

System::String^ xyz="Hi boys"; 

std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);

+1 за короткое и простое решение и простой рабочий пример (хотя в конце вашего кода есть лишняя скобка)
Саймон Форсберг

Это единственное решение, которое прямо отвечает на вопрос.
Jiminion 06

8
хм ... 33 голоса за ответ, который уже был дан более двух лет назад с почти такими же строками кода. уважение за то, что получил за это столько очков. ;-)
Beachwalker 05

20

Это сработало для меня:

#include <stdlib.h>
#include <string.h>
#include <msclr\marshal_cppstd.h>
//..
using namespace msclr::interop;
//..
System::String^ clrString = (TextoDeBoton);
std::string stdString = marshal_as<std::string>(clrString); //String^ to std
//System::String^ myString = marshal_as<System::String^>(MyBasicStirng); //std to String^
prueba.CopyInfo(stdString); //MyMethod
//..
//Where: String^ = TextoDeBoton;
//and stdString is a "normal" string;

3
Английский перевод: «Я собираюсь ответить и на этот пост: п. Это моя функция».
sivabudh

9

Вот несколько процедур преобразования, которые я написал много лет назад для проекта c ++ / cli, они все равно должны работать.

void StringToStlWString ( System::String const^ s, std::wstring& os)
    {
        String^ string = const_cast<String^>(s);
        const wchar_t* chars = reinterpret_cast<const wchar_t*>((Marshal::StringToHGlobalUni(string)).ToPointer());
        os = chars;
        Marshal::FreeHGlobal(IntPtr((void*)chars));

    }
    System::String^ StlWStringToString (std::wstring const& os) {
        String^ str = gcnew String(os.c_str());
        //String^ str = gcnew String("");
        return str;
    }

    System::String^ WPtrToString(wchar_t const* pData, int length) {
        if (length == 0) {
            //use null termination
            length = wcslen(pData);
            if (length == 0) {
                System::String^ ret = "";
                return ret;
            }
        }

        System::IntPtr bfr = System::IntPtr(const_cast<wchar_t*>(pData));
        System::String^ ret = System::Runtime::InteropServices::Marshal::PtrToStringUni(bfr, length);
        return ret;
    }

    void Utf8ToStlWString(char const* pUtfString, std::wstring& stlString) {
        //wchar_t* pString;
        MAKE_WIDEPTR_FROMUTF8(pString, pUtfString);
        stlString = pString;
    }

    void Utf8ToStlWStringN(char const* pUtfString, std::wstring& stlString, ULONG length) {
        //wchar_t* pString;
        MAKE_WIDEPTR_FROMUTF8N(pString, pUtfString, length);
        stlString = pString;
    }

@alap, используйте System :: Runtime :: InteropServices :: Marshal или напишите, используя пространство имен System :: Runtime :: InteropServices; .
neo

6

Я часами пытался преобразовать значение ToString окна списка в стандартную строку, чтобы можно было использовать его с fstream для вывода в текстовый файл. В моей Visual Studio не было файлов заголовков маршала, которые я нашел в нескольких ответах. После стольких проб и ошибок я наконец нашел решение проблемы, которое просто использует System :: Runtime :: InteropServices:

void MarshalString ( String ^ s, string& os ) {
   using namespace Runtime::InteropServices;
   const char* chars = 
      (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
   os = chars;
   Marshal::FreeHGlobal(IntPtr((void*)chars));
}

//this is the code to use the function:
scheduleBox->SetSelected(0,true);
string a = "test";
String ^ c = gcnew String(scheduleBox->SelectedItem->ToString());
MarshalString(c, a);
filestream << a;

А вот страница MSDN с примером: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

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


6

Я нашел простой способ получить std :: string из String ^ - использовать sprintf ().

char cStr[50] = { 0 };
String^ clrString = "Hello";
if (clrString->Length < sizeof(cStr))
  sprintf(cStr, "%s", clrString);
std::string stlString(cStr);

Не нужно вызывать функции Маршала!

ОБНОВЛЕНИЕ Благодаря Эрику я изменил пример кода, чтобы проверить размер входной строки, чтобы предотвратить переполнение буфера.


1
Любопытное решение - ввести в код уязвимость переполнения буфера, чтобы избежать вызова функций, специально разработанных для маршалинга строк.
Эрик

Я просто представляю другой подход, если кто-то не хочет использовать маршалированные функции. Я добавил проверку размера, чтобы предотвратить переполнение.
Ionian316,

@Eric Внутри вас все устраивает. Подробнее см. Этот SO-ответ . Если вы заранее проверите размер, у вас не будет проблем с переполнением, а код станет намного чище.
Ионический 316

4

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

При компиляции для многобайтового набора символов Visual Studio и Win API предполагает UTF8 (на самом деле кодировка Windows, которая является Windows-28591 ).
При компиляции для набора символов Unicode Visual studio и Win API используют UTF16.

Итак, вы также должны преобразовать строку из формата UTF16 в формат UTF8, а не просто преобразовать в std :: string.
Это станет необходимым при работе с многосимвольными форматами, такими как некоторые нелатинские языки.

Идея состоит в том, чтобы решить, что std::wstring всегда представляет UTF16 .
А такжеstd::string всегда представляет UTF8 .

Это не обеспечивается компилятором, это более хорошая политика.

#include "stdafx.h"
#include <string>
#include <codecvt>
#include <msclr\marshal_cppstd.h>

using namespace System;

int main(array<System::String ^> ^args)
{
    System::String^ managedString = "test";

    msclr::interop::marshal_context context;

    //Actual format is UTF16, so represent as wstring
    std::wstring utf16NativeString = context.marshal_as<std::wstring>(managedString); 

    //C++11 format converter
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    //convert to UTF8 and std::string
    std::string utf8NativeString = convert.to_bytes(utf16NativeString);

    return 0;
}

Или используйте более компактный синтаксис:

int main(array<System::String ^> ^args)
{
    System::String^ managedString = "test";

    msclr::interop::marshal_context context;
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    std::string utf8NativeString = convert.to_bytes(context.marshal_as<std::wstring>(managedString));

    return 0;
}

1
Я просто хочу подчеркнуть важность преобразования в UTF8 в моем случае использования: мне нужно было передать путь к файлу, полученный из Win32 OpenFileDialog (где возможны имена файлов с многобайтовыми символами, например, имена файлов, содержащие азиатские символы) в код движка через std :: string, поэтому преобразование в UTF8 было жизненно важным. Спасибо за отличный ответ!
Джейсон МакКлинси

0

Мне нравится держаться подальше от маршаллера.

Using CString newString(originalString);

Мне кажется намного чище и быстрее. Не нужно беспокоиться о создании и удалении контекста.


0

// Я использовал VS2012 для написания кода ниже - convert_system_string в Standard_Sting

        #include "stdafx.h"
        #include <iostream>
        #include <string> 

        using namespace System;
        using namespace Runtime::InteropServices; 


        void MarshalString ( String^ s, std::string& outputstring )
        {  
           const char* kPtoC =  (const char*) (Marshal::StringToHGlobalAnsi(s)).ToPointer();                                                        
           outputstring = kPtoC;  
           Marshal::FreeHGlobal(IntPtr((void*)kPtoC));  
        }   

        int _tmain(int argc, _TCHAR* argv[])
        {
             std::string strNativeString;  
             String ^ strManagedString = "Temp";

             MarshalString(strManagedString, strNativeString);  
             std::cout << strNativeString << std::endl; 

             return 0;
        }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.