2009-08-19 15 views
46

Come si converte System :: String in std :: string in C++ .NET?C++ .NET converti System :: String in std :: string

+5

Non. Converti in std :: wstring. System.String è Unicode, non ASCII – MSalters

+6

@MSalters Huh? Sembra che tu abbia l'impressione che la conversione non includa la traduzione o che tutti possano sempre scegliere con quale API interagiranno ... –

risposta

55

C'è sintassi più pulito se si sta utilizzando una versione recente di .NET

#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; 
    std::string standardString = context.marshal_as<std::string>(managedString); 

    return 0; 
} 

Questo ti dà anche una migliore pulizia di fronte alle eccezioni.

C'è un msdn article per varie altre conversioni

+0

Si occupa anche della codifica da UTF-16 (.Net predefinito) a UTF-8 (std :: string)? – zak

7
stdString = toss(systemString); 

    static std::string toss(System::String^s) 
    { 
    // convert .NET System::String to std::string 
    const char* cstr = (const char*) (Marshal::StringToHGlobalAnsi(s)).ToPointer(); 
    std::string sstr = cstr; 
    Marshal::FreeHGlobal(System::IntPtr((void*)cstr)); 
    return sstr; 
    } 
+1

Questa è la sintassi più vecchia. Preferisco quello che Colin ha suggerito sopra. – orad

+0

Cosa succede se sstr() lancia? Non farebbe in modo che cstr diventi una perdita? –

25

e in risposta al "modo più semplice" nelle versioni successive di C++/CLI, è possibile farlo senza il marshal_context. So che questo funziona in Visual Studio 2010; Non sono sicuro di prima.


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

#include <msclr\marshal_cppstd.h> 

using namespace msclr::interop; 

int main(array<System::String ^> ^args) 
{ 
    System::String^ managedString = "test"; 

    std::string standardString = marshal_as<std::string>(managedString); 

    return 0; 
} 

+1

Guarda l'articolo MSDN Collin collegato per vedere quando usare marshal_as e quando usare marshal_context. In generale, il marshal_context è necessario quando le risorse non gestite devono essere ripulite. – rotti2

+2

L'articolo dice che è necessario un contesto solo se il tipo nativo non ha un distruttore per eseguire la sua pulizia. Quindi, nel caso di 'std :: string', è necessario? –

+1

Il contesto non è necessario per 'std :: string'. Il contesto è necessario solo quando si effettua il marshalling da un tipo spostato a un tipo unwrapped (ovvero puntatore raw). Come elencato in [Panoramica di Marshalling in C++] (http://msdn.microsoft.com/en-us/library/bb384865.aspx), ci sono solo tre istanze in cui è necessario il contesto. –

3

ho avuto troppi errori ambigui che mostra il passo con le risposte di cui sopra (sì, io sono un C++ niubbo)

Questo ha funzionato per me per l'invio di stringa da C# per C++ CLI

C#

bool result; 
result = mps.Import(mpsToolName); 

C++ CLI

funzione:

bool ManagedMPS::Import(System::String^ mpsToolNameTest) 
std::string mpsToolName; 
mpsToolName = toStandardString(mpsToolNameTest); 

funzione che lavora dalla conversione String^a std :: string

static std::string toStandardString(System::String^ string) 
{ 
using System::Runtime::InteropServices::Marshal; 
System::IntPtr pointer = Marshal::StringToHGlobalAnsi(string); 
char* charPointer = reinterpret_cast<char*>(pointer.ToPointer()); 
std::string returnString(charPointer, string->Length); 
Marshal::FreeHGlobal(pointer); 
return returnString; 
} 

ON ulteriori ricerche, sembra che questo è più pulito e più sicuro.

Ho scelto invece di utilizzare questo metodo.

std::string Utils::ToUnmanagedString(String^ stringIncoming) 
{ 
    std::string unmanagedString = marshal_as<std::string>(stringIncoming); 
    return unmanagedString; 
} 
+0

Quindi, come è riuscito a eliminare tutti gli errori di ambiguità di IServiceProvider? –

+0

Non ricordo di aver ricevuto quegli errori. Ero nuovo al C++, ora sono su un altro contratto/progetto con società diversa .... mi dispiace soprattutto. –

0

Creazione di un runtime componenti di Windows è possibile utilizzare:

String^ systemString = "Hello"; 
std::wstring ws1(systemString ->Data()); 
std::string standardString(ws1.begin(), ws1.end()); 
6

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