C ++ / CLI-Konvertierung von System :: String ^ in std :: string

90

Kann jemand bitte einen einfachen Code posten, der konvertieren würde,

System::String^

Zu,

C ++ std::string

Dh ich möchte nur den Wert von, zuweisen

String^ originalString;

Zu,

std::string newString;
Sivabudh
quelle

Antworten:

38

Check out System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()und seine Freunde.

Entschuldigung, ich kann jetzt keine Postleitzahl posten. Ich habe kein VS auf diesem Computer, um zu überprüfen, ob es vor dem Posten kompiliert wurde.

Martin
quelle
158

Rollen Sie nicht Ihre eigenen, sondern verwenden Sie diese praktischen (und erweiterbaren) Wrapper von Microsoft.

Beispielsweise:

#include <msclr\marshal_cppstd.h>

System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);
tragomaskhalos
quelle
2
Dank dieses nützlichen Links hat mir dieser Hinweis viel Codierung erspart. Als Randnotiz: Die Vorlagen / Klassen befinden sich in #include <msclr \ *. h> (z. B. #include <msclr \ marshal.h>) und im msclr :: interop-Namespace, siehe ein Beispiel unter msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker
4
Dies ist zwar praktisch, es fehlt jedoch die richtige Codierungsunterstützung. Siehe auch meine SO-Frage: stackoverflow.com/questions/18894551/… . Ich gehe davon aus, dass marshal_as Unicode-Strings in std :: string in ACP konvertiert.
Mike Lischke
MS-Empfehlung lautet, marshal_context zu verwenden und nach der Konvertierung zu löschen. Der Link: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko
39

Sie können dies einfach wie folgt tun

#include <msclr/marshal_cppstd.h>

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

std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);
Sriwantha Attanayake
quelle
+1 für eine kurze und einfache Lösung und ein einfaches Arbeitsbeispiel (obwohl am Ende Ihres Codes eine zusätzliche Klammer steht)
Simon Forsberg
Dies ist die einzige Lösung, die die Frage direkt beantwortet.
Jiminion
7
hmm ... 33 positive Stimmen für eine Antwort, die bereits mehr als 2 Jahre zuvor mit fast denselben Codezeilen gegeben wurde. Respekt dafür, dass ich dafür so viele Punkte gesammelt habe. ;-)
Beachwalker
20

Das hat bei mir funktioniert:

#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;
Alejandro Perea
quelle
2
Englische Übersetzung: "Ich werde auch auf diesen Beitrag antworten: p. Dies ist meine Funktion."
Sivabudh
9

Hier sind einige Konvertierungsroutinen, die ich vor vielen Jahren für ein c ++ / cli-Projekt geschrieben habe. Sie sollten trotzdem funktionieren.

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;
    }
Ben Schwehn
quelle
@alap, benutze System :: Runtime :: InteropServices :: Marshal oder schreibe mit dem Namespace System :: Runtime :: InteropServices; .
Neo
6

Ich habe eine einfache Möglichkeit gefunden, einen std :: string aus einem String ^ zu erhalten, indem ich sprintf () verwende.

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

Sie müssen die Marschallfunktionen nicht aufrufen!

UPDATE Dank Eric habe ich den Beispielcode geändert, um die Größe der Eingabezeichenfolge zu überprüfen und einen Pufferüberlauf zu verhindern.

Ionian316
quelle
1
Es ist eine merkwürdige Entscheidung, eine Pufferüberlauf-Sicherheitsanfälligkeit in Ihren Code einzuführen, um zu vermeiden, dass Funktionen aufgerufen werden, die speziell für Marshall-Strings entwickelt wurden.
Eric
Ich präsentiere einfach einen anderen Ansatz, wenn jemand die Marschallfunktionen nicht verwenden möchte. Ich habe eine Überprüfung der Größe hinzugefügt, um einen Überlauf zu verhindern.
Ionian316
@ Eric Intern Intern ist es Marshalling für Sie. Siehe diese SO-Antwort für Details. Wenn Sie vorher nach der Größe suchen, treten keine Überlaufprobleme auf, und der Code ist viel sauberer.
Ionian316
5

Ich habe stundenlang versucht, einen Windows Form Listbox ToString-Wert in eine Standardzeichenfolge zu konvertieren, damit ich ihn mit fstream zur Ausgabe in eine txt-Datei verwenden kann. Mein Visual Studio enthielt keine Marschall-Header-Dateien, die von mehreren Antworten verwendet wurden. Nach so viel Versuch und Irrtum fand ich endlich eine Lösung für das Problem, das nur System :: Runtime :: InteropServices verwendet:

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;

Und hier ist die MSDN-Seite mit dem Beispiel: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Ich weiß, dass es eine ziemlich einfache Lösung ist, aber ich brauchte STUNDEN, um Fehler zu beheben und mehrere Foren zu besuchen, um endlich etwas zu finden, das funktioniert.

Joe
quelle
4

C # verwendet das UTF16-Format für seine Zeichenfolgen.
Neben der Konvertierung der Typen sollten Sie sich auch des tatsächlichen Formats der Zeichenfolge bewusst sein.

Beim Kompilieren für einen Multi-Byte-Zeichensatz setzt Visual Studio und die Win-API UTF8 voraus (eigentlich Windows- Codierung, Windows-28591 ).
Beim Kompilieren für den Unicode-Zeichensatz nehmen Visual Studio und die Win-API UTF16 an.

Sie müssen also die Zeichenfolge auch vom UTF16- in das UTF8-Format konvertieren und nicht nur in std :: string konvertieren.
Dies ist erforderlich, wenn Sie mit Formaten mit mehreren Zeichen wie einigen nicht-lateinischen Sprachen arbeiten.

Die Idee ist zu entscheiden, dass std::wstring immer UTF16 repräsentiert .
Und repräsentiert std::string immer UTF8 .

Dies wird vom Compiler nicht erzwungen, sondern ist eher eine gute Richtlinie.

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

Oder haben Sie es in einer kompakteren Syntax:

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;
}
Yochai Timmer
quelle
1
Ich möchte nur die Wichtigkeit der Konvertierung in UTF8 in meinem Anwendungsfall hervorheben: Ich musste einen von Win32 OpenFileDialog empfangenen Dateipfad (wo Dateinamen mit Multibyte-Zeichen möglich sind, z. B. Dateinamen mit asiatischen Zeichen) über einen Standard an Engine-Code übergeben :: string, daher war die Konvertierung in UTF8 von entscheidender Bedeutung. Danke für die hervorragende Antwort!
Jason McClinsey
0

Ich halte mich gerne vom Marshaller fern.

Using CString newString(originalString);

Scheint mir viel sauberer und schneller zu sein. Sie müssen sich keine Gedanken über das Erstellen und Löschen eines Kontexts machen.

LL.
quelle
0

// Ich habe VS2012 verwendet, um den folgenden Code zu schreiben: convert_system_string to 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;
        }
Praveer Kumar
quelle