C ++ / CLI Conversione da System :: String ^ a std :: string


90

Qualcuno può inviare un semplice codice che converte,

System::String^

Per,

C ++ std::string

Cioè, voglio solo assegnare il valore di,

String^ originalString;

Per,

std::string newString;

Risposte:


38

Dai un'occhiata ai System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()suoi amici.

Spiacenti, non posso inserire il codice ora; Non ho VS su questa macchina per controllare che si compili prima di inviare.


160

Non lanciarne uno tuo, usa questi pratici (ed estensibili) wrapper forniti da Microsoft.

Per esempio:

#include <msclr\marshal_cppstd.h>

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

2
grazie per questo collegamento utile, questo suggerimento mi ha salvato un sacco di codice. come nota a margine: i modelli / classi sono in #include <msclr \ *. h> (ad esempio #include <msclr \ marshal.h>) e nello spazio dei nomi msclr :: interop, vedere un esempio su msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker

4
Anche se questo è conveniente, manca totalmente il supporto di codifica appropriato. Vedi anche la mia domanda SO: stackoverflow.com/questions/18894551/… . La mia ipotesi è che marshal_as converta le stringhe Unicode nell'ACP in std :: string.
Mike Lischke

Raccomandazione di MS è di utilizzare marshal_context ed eliminarlo dopo che la conversione è stata eseguita. Il collegamento: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko

40

Puoi farlo facilmente come segue

#include <msclr/marshal_cppstd.h>

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

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

+1 per una soluzione breve e semplice e un semplice esempio di lavoro (anche se c'è una parentesi in più alla fine del codice)
Simon Forsberg

Questa è l'unica soluzione che risponde direttamente alla domanda.
Jiminion

8
hmm ... 33 voti positivi per una risposta che era già stata data più di 2 anni prima con quasi le stesse righe di codice. rispetto per aver guadagnato così tanti punti per questo. ;-)
Beachwalker

20

Questo ha funzionato per me:

#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
Traduzione inglese: "Rispondo anche a questo post: p. Questa è la mia funzione."
sivabudh

9

Ecco alcune routine di conversione che ho scritto molti anni fa per un progetto c ++ / cli, dovrebbero comunque funzionare.

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, usa System :: Runtime :: InteropServices :: Marshal o scrivi usando lo spazio dei nomi System :: Runtime :: InteropServices; .
neo

6

Ho passato ore a cercare di convertire un valore ToString della casella di riepilogo di Windows in una stringa standard in modo da poterlo utilizzare con fstream per l'output in un file txt. Il mio Visual Studio non veniva fornito con i file di intestazione di marshalling che diverse risposte che ho trovato dicevano di usare. Dopo tanti tentativi ed errori ho finalmente trovato una soluzione al problema che utilizza semplicemente 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;

Ed ecco la pagina MSDN con l'esempio: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

So che è una soluzione piuttosto semplice, ma mi ci sono volute ORE di risoluzione dei problemi e ho visitato diversi forum per trovare finalmente qualcosa che funzionasse.


6

Ho trovato un modo semplice per ottenere uno std :: string da una String ^ è usare sprintf ().

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

Non c'è bisogno di chiamare le funzioni Marshal!

AGGIORNAMENTO Grazie a Eric, ho modificato il codice di esempio per verificare la dimensione della stringa di input per evitare l'overflow del buffer.


1
È una decisione curiosa introdurre una vulnerabilità di overflow del buffer nel codice solo per evitare di chiamare funzioni appositamente progettate per eseguire il marshalling delle stringhe.
Eric,

Sto semplicemente presentando un approccio diverso se qualcuno non vuole usare le funzioni di marshalling. Ho aggiunto un controllo per le dimensioni per evitare l'overflow.
Ionian316

@Eric Internamente sta effettuando il marshalling per te. Vedi questa risposta SO per i dettagli. Se controlli in anticipo la dimensione, non avrai problemi di overflow e il codice è molto più pulito.
Ionian316

4

C # usa il formato UTF16 per le sue stringhe.
Quindi, oltre a convertire solo i tipi, dovresti anche essere consapevole del formato effettivo della stringa.

Quando si compila per il set di caratteri multibyte, Visual Studio e l'API Win presuppongono UTF8 (in realtà la codifica di Windows che è Windows-28591 ).
Durante la compilazione per il set di caratteri Unicode Visual Studio e l'API Win presuppongono UTF16.

Quindi, è necessario convertire anche la stringa dal formato UTF16 al formato UTF8 e non solo convertirla in std :: string.
Ciò diventerà necessario quando si lavora con formati multi-carattere come alcune lingue non latine.

L'idea è di decidere che rappresenta std::wstring sempre UTF16 .
E rappresenta std::string sempre UTF8 .

Questo non viene applicato dal compilatore, è più una buona politica da avere.

#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 averlo in una sintassi più compatta:

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
Voglio solo sottolineare l'importanza della conversione in UTF8 nel mio caso d'uso: avevo bisogno di passare un percorso di file ricevuto da Win32 OpenFileDialog (dove sono possibili nomi di file con caratteri multibyte, ad esempio nomi di file contenenti caratteri asiatici) al codice del motore tramite uno std :: string, quindi la conversione in UTF8 è stata fondamentale. Grazie per l'ottima risposta!
Jason McClinsey

0

Mi piace stare lontano dal marshaller.

Using CString newString(originalString);

Mi sembra molto più pulito e veloce. Non c'è bisogno di preoccuparsi di creare ed eliminare un contesto.


0

// Ho usato VS2012 per scrivere sotto il codice: convert_system_string in 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;
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.