C ++ / CLI Перетворення з System :: String ^ в std :: string


90

Чи може хтось опублікувати простий код, який би перетворив,

System::String^

До,

C ++ std::string

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

String^ originalString;

До,

std::string newString;

Відповіді:


38

Виїзд System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()та його друзі.

На жаль, зараз не вдається надіслати поштовий індекс; У мене немає VS на цій машині, щоб перевірити її компіляцію перед публікацією.


159

Не робіть власні, використовуйте ці зручні (і розширювані) обгортки, надані корпорацією Майкрософт.

Наприклад:

#include <msclr\marshal_cppstd.h>

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

2
thx за це корисне посилання, цей підказка врятував мені багато кодування. як допоміжна примітка: шаблони / класи знаходяться в #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.
Mike Lischke

Рекомендація 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

8
хм ... 33 голоси за відповідь, яка вже була дана більш ніж 2 роками раніше з майже однаковими рядками коду. повага за отримання стільки балів за це. ;-)
Пляжник

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; .
нео

6

Я годинами намагався перетворити значення ToString вікна списку форм у стандартний рядок, щоб я міг використовувати його з fstream для виведення у файл txt. Моя 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 з рядка ^ - це використовувати 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 . Якщо ви попередньо перевірите розмір, у вас не виникне проблем із переповненням, і код набагато чистіший.
Ionian316

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 :: рядок, тому перетворення на 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.