Conversión de C ++ / CLI de System :: String ^ a std :: string


90

¿Alguien puede publicar un código simple que convierta,

System::String^

A,

C ++ std::string

Es decir, solo quiero asignar el valor de,

String^ originalString;

A,

std::string newString;

Respuestas:


38

Echa un vistazo System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()y sus amigos.

Lo siento, no puedo publicar código ahora; No tengo VS en esta máquina para verificar que se compila antes de publicar.


160

No enrolle el suyo, use estos prácticos (y extensibles) contenedores proporcionados por Microsoft.

Por ejemplo:

#include <msclr\marshal_cppstd.h>

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

2
Gracias por este enlace útil, esta sugerencia me ahorró mucha codificación. como nota al margen: las plantillas / clases están en #include <msclr \ *. h> (por ejemplo, #include <msclr \ marshal.h>) y en el espacio de nombres msclr :: interop, vea un ejemplo en msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker

4
Si bien esto es conveniente, carece totalmente de soporte de codificación adecuado. Consulte también mi pregunta SO: stackoverflow.com/questions/18894551/… . Mi suposición es que marshal_as convierte cadenas Unicode al ACP en std :: string.
Mike Lischke

La recomendación de MS es usar marshal_context y eliminarlo después de que se haya realizado la conversión. El enlace: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko

40

Puede hacer esto fácilmente de la siguiente manera

#include <msclr/marshal_cppstd.h>

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

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

+1 para una solución breve y simple y un ejemplo de trabajo simple (aunque hay un paréntesis adicional al final de su código)
Simon Forsberg

Esta es la única solución que responde directamente a la pregunta.
Jiminion

8
hmm ... 33 votos a favor para una respuesta que ya se dio más de 2 años antes con casi las mismas líneas de código. respeto por ganar tantos puntos por eso. ;-)
Beachwalker

20

Esto funcionó para mí:

#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
Traducción al español: "Voy a responder a esta publicación también: p. Esta es mi función".
sivabudh

9

Aquí hay algunas rutinas de conversión que escribí hace muchos años para un proyecto c ++ / cli, aún deberían funcionar.

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, use System :: Runtime :: InteropServices :: Marshal o escriba usando el espacio de nombres System :: Runtime :: InteropServices; .
neo

6

Pasé horas tratando de convertir un valor ToString de listbox de Windows Form a una cadena estándar para poder usarlo con fstream para generar un archivo txt. Mi Visual Studio no venía con archivos de encabezado marshal que varias respuestas que encontré decían usar. Después de tanto ensayo y error, finalmente encontré una solución al problema que solo usa 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;

Y aquí está la página de MSDN con el ejemplo: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Sé que es una solución bastante simple, pero esto me tomó HORAS de resolución de problemas y visitar varios foros para finalmente encontrar algo que funcionó.


6

Encontré una manera fácil de obtener un std :: string de un String ^ es usar sprintf ().

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

¡No es necesario llamar a las funciones Marshal!

ACTUALIZACIÓN Gracias a Eric, modifiqué el código de muestra para verificar el tamaño de la cadena de entrada para evitar el desbordamiento del búfer.


1
Es una decisión curiosa introducir una vulnerabilidad de desbordamiento de búfer en su código solo para evitar llamar a funciones especialmente diseñadas para marshall strings.
Eric

Simplemente estoy presentando un enfoque diferente si alguien no quiere usar las funciones de mariscal. Agregué un cheque para el tamaño para evitar desbordes.
Ionian316

@Eric Internamente se está organizando para usted. Consulte esta respuesta SO para obtener más detalles. Si verifica el tamaño de antemano, no tendrá problemas de desbordamiento y el código es mucho más limpio.
Ionian316

4

C # usa el formato UTF16 para sus cadenas.
Por lo tanto, además de convertir los tipos, también debe ser consciente del formato real de la cadena.

Al compilar para el conjunto de caracteres de varios bytes, Visual Studio y la API de Win asumen UTF8 (en realidad, la codificación de Windows es Windows-28591 ).
Al compilar para el juego de caracteres Unicode, Visual Studio y la API de Win asumen UTF16.

Por lo tanto, también debe convertir la cadena de formato UTF16 a UTF8, y no solo convertirla a std :: string.
Esto será necesario cuando trabaje con formatos de varios caracteres como algunos idiomas no latinos.

La idea es decidir que std::wstring siempre representa UTF16 .
Y std::string siempre representa UTF8 .

Esto no es impuesto por el compilador, es más una buena política.

#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;
}

O tenerlo en una sintaxis más compacta:

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
Solo quiero enfatizar la importancia de convertir a UTF8 en mi caso de uso: necesitaba pasar una ruta de archivo recibida de Win32 OpenFileDialog (donde son posibles los nombres de archivo con caracteres multibyte, por ejemplo, nombres de archivo que contienen caracteres asiáticos) al código del motor a través de un std :: string, por lo que la conversión a UTF8 fue vital. ¡Gracias por la excelente respuesta!
Jason McClinsey

0

Me gusta alejarme del alguacil.

Using CString newString(originalString);

Me parece mucho más limpio y rápido. No hay necesidad de preocuparse por crear y eliminar un contexto.


0

// Usé VS2012 para escribir el siguiente código: convert_system_string a 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;
        }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.