2009-08-19 30 views
46

Jak przekonwertować System :: String na std :: string w C++ .NET?C++ .NET convert System :: String na std :: string

+5

nie. Konwertuj na std :: wstring. System.String to kod Unicode, a nie ASCII – MSalters

+6

@ MHH Huh? Wydaje się, że masz wrażenie, że konwersja nie obejmuje tłumaczenia lub że każdy może zawsze wybrać interfejs API, z którym ma zamiar współpracować ... –

Odpowiedz

55

Jest czystsze składnia jeśli używasz najnowszej wersji .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; 
} 

To również daje lepszą Clean-up w obliczu wyjątków.

Jest msdn article dla różnych innych konwersji

+0

Czy to również zajmuje się kodowaniem z UTF-16 (domyślnie .Net) do 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

To jest starsza składnia. Wolę ten, który Colin zasugerował powyżej. – orad

+0

Co się stanie, jeśli sstr() wyrzuci? Czy to nie spowoduje, że cstr stanie się przeciekiem? –

25

iw odpowiedzi na „łatwiejszy sposób” w nowszych wersjach C++/CLI, można to zrobić bez marshal_context. Wiem, że działa to w Visual Studio 2010; nie jestem pewien przed tym.


#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

Zobacz artykuł MSDN, w którym znajduje się link Collin, aby sprawdzić, kiedy używać marshal_as i kiedy używać marshal_context. Ogólnie rzecz biorąc, marshall_context jest potrzebny, gdy niezarządzane zasoby wymagają oczyszczenia. – rotti2

+2

W artykule napisano, że potrzebny jest tylko kontekst, jeśli typ natywny nie ma destruktora, który wykonałby własne czyszczenie. Tak więc w przypadku 'std :: string' jest to potrzebne? –

+1

Kontekst nie jest potrzebny dla 'std :: string'. Kontekst jest wymagany tylko podczas przenoszenia z typu owiniętego do typu nieopakowanego (tzn. Wskaźnik surowy). Jak podano w [Omówienie programu Marshaling w C++] (http://msdn.microsoft.com/en-us/library/bb384865.aspx), istnieją tylko trzy przypadki, w których potrzebny jest kontekst. –

3

miałem zbyt wiele niejednoznacznych błędy wyświetlane z powyższych odpowiedzi (tak, jestem C++ noobem)

ten pracował dla mnie do wysyłania ciąg z C# C++ CLI

C#

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

C++ CLI

funkcja:

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

funkcja, która działa od konwersji String^do 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; 
} 

NA dalszych badań, wydaje się, że jest czystsze i bezpieczniejsze.

Zamiast tego użyłem tej metody.

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

Jak udało ci się pozbyć wszystkich błędów wieloznaczności IServiceProvider? –

+0

Nie pamiętam, aby uzyskać te błędy. Byłem nowy w C++, teraz jestem na innym kontrakcie/projekcie z inną firmą .... przepraszam, powodzenia. –

0

Tworzenie Runtime składnika systemu Windows można użyć:

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

C# używa formatu UTF16 dla swoich strun.
Tak więc, oprócz konwersji typów, powinieneś również być świadomy faktycznego formatu łańcucha.

Podczas kompilacji dla Zestaw znaków wielobajtowych Visual Studio i Win API przyjmują kodowanie UTF8 (w rzeczywistości kodowanie Windows to Windows-28591).
Podczas kompilacji dla Zestaw znaków Unicode Visual Studio i Win API zakładają UTF16.

Musisz więc przekonwertować ciąg znaków z UTF16 na format UTF8, a nie tylko przekonwertować na std :: string.
Będzie to konieczne w przypadku pracy z formatami wieloliterowymi, np. W niektórych językach innych niż łaciński.

Chodzi o to, aby podjąć decyzję, że std::wstringzawsze reprezentuje UTF16.
I std::stringzawsze reprezentuje UTF8.

To nie jest wymuszane przez kompilator, lepiej mieć więcej zasad.

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

Albo mieć go w bardziej zwartej składni:

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