2009-06-03 18 views

risposta

37

Check out System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni() e suoi amici.

Non è possibile inserire il codice ora; Non ho VS su questa macchina per controllarlo prima della pubblicazione.

9

Qui ci sono alcune routine di conversione che ho scritto molti anni fa per un progetto C++/CLI, essi dovrebbero funzionano ancora.

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

Cosa è necessario eseguire? Includi file ecc. ????? – alap

+0

@alap, utilizzare ** System :: Runtime :: InteropServices :: Marshal ** o scrivere ** utilizzando lo spazio dei nomi System :: Runtime :: InteropServices; **. – neo

118

Non roll your own, utilizzare these a portata di mano (ed estensibili) involucri forniti da Microsoft.

Ad esempio:

#include <msclr\marshal_cppstd.h> 

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

thx per questo link utile, questo suggerimento mi ha salvato un sacco di codice. come nota a margine: i modelli/classi sono in #include (ad esempio #include ) e nel msclr :: spazio dei nomi di interoperabilità, vedere un esempio su http://msdn.microsoft.com/default -de/library/vstudio/bb384859 (v = vs.90) .aspx) – Beachwalker

+2

Mentre questo è conveniente, manca totalmente il supporto di codifica appropriato. Vedi anche la mia domanda SO: http://stackoverflow.com/questions/18894551/string-marshalling-with-marshal-as-and-encodings. La mia ipotesi è che marshal_as converte le stringhe Unicode nell'ACP in std :: string. –

19

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

Traduzione inglese: "Ho intenzione di rispondere anche a questo post: p. Questa è la mia funzione." – sivabudh

+0

Muchas gracias, Alejandro! – sivabudh

5

ho passato ore a cercare di convertire un valore casella di riepilogo ToString Windows Form in una stringa standard in modo che ho potuto usarlo con fstream per l'output in un file txt. Il mio Visual Studio non è venuto con i file di intestazione di marshal che diverse risposte ho trovato detto di utilizzare. Dopo tanto tentativi ed errori ho finalmente trovato una soluzione al problema che utilizza solo sistema :: 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; 

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

lo so è una soluzione piuttosto semplice ma mi ci sono voluti ORE di risoluzione dei problemi e visitando diversi forum per trovare finalmente qualcosa che funzionasse.

36

Si può facilmente fare questo nel modo seguente

#include <msclr/marshal_cppstd.h> 

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

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

+1 per una soluzione semplice e breve e un semplice esempio di lavoro (anche se alla fine del codice c'è una parentesi aggiuntiva) –

+0

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

+2

hmm ... 33 upvotes per una risposta che era già stata data più di 2 anni prima con quasi le stesse linee di codice. rispetto per guadagnare così tanti punti per quello. ;-) – Beachwalker

4

Ho trovato un modo semplice per ottenere uno std :: string da una stringa^è quello di utilizzare sprintf().

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

Non è necessario chiamare le funzioni di Maresciallo!

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

+1

È una decisione curiosa introdurre una vulnerabilità di buffer overflow nel codice solo per evitare di chiamare funzioni appositamente progettate per le stringhe di marshall. – Eric

+0

Sto semplicemente presentando un approccio diverso se qualcuno non desidera utilizzare le funzioni di marshalling. Ho aggiunto un controllo per la dimensione per prevenire l'overflow. – Ionian316

+0

@Eric Internamente sta eseguendo il marshalling per te. Vedi [questa risposta SO] (http: // StackOverflow.it/a/11831686/1516125) per i dettagli. Se controlli in anticipo la dimensione, non avrai problemi di overflow e il codice è molto più pulito. – Ionian316

0

Mi piace stare lontano dal marshaller.

Using CString newString(originalString); 

Sembra molto più pulito e veloce per me. Non c'è bisogno di preoccuparsi di creare e cancellare un contesto.

0

// Ho usato VS2012 di scrivere sotto 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# utilizza il formato UTF16 per le sue corde.
Quindi, oltre alla semplice conversione dei tipi, è necessario essere consapevoli del formato effettivo della stringa.

Durante la compilazione per Set di caratteri multi-byte Visual Studio e l'API Win presuppongono UTF8 (In realtà la codifica di Windows che è Windows-28591).
Durante la compilazione per Set di caratteri Unicode Visual Studio e l'API Win assumono UTF16.

Quindi, è necessario convertire anche la stringa da UTF16 a UTF8 e non solo convertire in std :: string.
Questo diventerà necessario quando si lavora con formati a più caratteri come alcune lingue non latine.

L'idea è quella di decidere che std::wstringsempre rappresenta UTF16.
E std::stringsempre rappresenta UTF8.

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

#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 fa 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; 
} 
Problemi correlati