2009-06-03 22 views

Respuesta

37

Salida System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni() y sus amigos.

En este momento no se puede publicar código de ahora; No tengo VS en esta máquina para verificar que se compile antes de publicar.

9

Aquí hay algunas rutinas de conversión que escribí hace muchos años para un proyecto de C++/cli, debería 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; 
    } 
+0

¿Qué se necesita para funcionar? Incluye archivos, etc. ????? – alap

+0

@alap, Use ** System :: Runtime :: InteropServices :: Marshal ** o write ** usando el espacio de nombres System :: Runtime :: InteropServices; **. – neo

118

No haga rodar su propio, utilizar these envoltorios práctico (y extensibles) 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

thx para este útil enlace, esta pista me ha ahorrado mucha codificación. como nota al margen: las plantillas/clases están en #include (por ejemplo, #include ) y en el espacio de nombres msclr :: interop, vea un ejemplo en http://msdn.microsoft.com/de -de/library/vstudio/bb384859 (v = vs.90) .aspx) – Beachwalker

+2

Si bien es conveniente, carece totalmente del soporte de codificación adecuado. Ver también mi pregunta ASÍ: http://stackoverflow.com/questions/18894551/string-marshalling-with-marshal-as-and-encodings. Mi suposición es que marshal_as convierte cadenas Unicode al ACP en std :: string. –

19

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; 
+2

Traducción al inglés: "Voy a responder a esta publicación también: p. Esta es mi función". – sivabudh

+0

Muchas gracias, Alejandro! – sivabudh

5

pasé horas tratando de convertir un valor de cuadro de lista ToString forma de ventanas a una cadena estándar para que pudiera usarlo con fstream para dar salida a un archivo txt. My Visual Studio no incluía los archivos de encabezado de Marshal, que respondían varias respuestas que encontré usar. Después de tanto ensayo y error, finalmente he encontrado una solución al problema que solo utiliza el sistema de tiempo de ejecución :: :: 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

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

36

Usted puede hacer esto 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); 
+0

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

+0

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

+2

hmm ... 33 upvotes por 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 para eso. ;-) – Beachwalker

4

He encontrado una manera fácil de conseguir un std :: string de una cadena^es utilizar sprintf().

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

¡No hace falta llamar a las funciones de Marshal!

ACTUALIZACIÓN Gracias a Eric, he modificado el código de muestra para verificar el tamaño de la cadena de entrada para evitar el desbordamiento de la memoria intermedia.

+1

Es una curiosa decisión introducir una vulnerabilidad de desbordamiento de búfer en el código solo para evitar funciones de llamada especialmente diseñadas para cadenas de servidores. – Eric

+0

Simplemente estoy presentando un enfoque diferente si alguien no quiere usar las funciones de Mariscal. He agregado un cheque para el tamaño para evitar el desbordamiento. – Ionian316

+0

@Eric Internamente se está organizando para usted. Ver [esta respuesta SO] (http: // stackoverflow.com/a/11831686/1516125) para más detalles. Si comprueba el tamaño de antemano, no tendrá problemas de desbordamiento y el código es mucho más limpio. – Ionian316

0

me gusta estar lejos del contador de referencias.

Using CString newString(originalString); 

Parece mucho más limpio y más rápido para mí. No necesita preocuparse por crear y eliminar un contexto.

0

// utilicé VS2012 a escribir a continuación code-- 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; 
     } 
1

C# utiliza el formato UTF16 por 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 Conjunto de caracteres de varios bytes Visual Studio y la API de Windows asume UTF8 (En realidad, la codificación de Windows que es Windows-28591).
Al compilar para Conjunto de caracteres Unicode Visual Studio y la API de Windows asumen UTF16.

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

La idea es decidir que std::wstringsiempre representa UTF16.
Y std::stringsiempre representa UTF8.

Esto no se aplica por el compilador, es más una buena política que tener.

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

#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 lo tiene 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; 
} 
Cuestiones relacionadas