Conversion C ++ / CLI de System :: String ^ vers std :: string

90

Quelqu'un peut-il s'il vous plaît poster un code simple qui convertirait,

System::String^

À,

C ++ std::string

Ie, je veux juste attribuer la valeur de,

String^ originalString;

À,

std::string newString;
sivabudh
la source

Réponses:

38

Découvrez System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()et ses amis.

Désolé, impossible de publier le code maintenant; Je n'ai pas de VS sur cette machine pour vérifier qu'elle se compile avant de publier.

Martin
la source
160

Ne roulez pas les vôtres, utilisez ces wrappers pratiques (et extensibles) fournis par Microsoft.

Par exemple:

#include <msclr\marshal_cppstd.h>

System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);
tragomaskhalos
la source
2
merci pour ce lien utile, cette astuce m'a sauvé beaucoup de codage. en remarque: les modèles / classes sont dans #include <msclr \ *. h> (par exemple #include <msclr \ marshal.h>) et dans l'espace de noms msclr :: interop, voir un exemple sur msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker
4
Bien que cela soit pratique, il manque totalement un support d'encodage approprié. Voir aussi ma question SO: stackoverflow.com/questions/18894551/… . Mon hypothèse est que marshal_as convertit les chaînes Unicode en ACP dans std :: string.
Mike Lischke
La recommandation MS est d'utiliser marshal_context et de le supprimer une fois la conversion effectuée. Le lien: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko
40

Vous pouvez facilement le faire comme suit

#include <msclr/marshal_cppstd.h>

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

std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);
Sriwantha Attanayake
la source
+1 pour une solution courte et simple et un exemple de travail simple (bien qu'il y ait une parenthèse supplémentaire à la fin de votre code)
Simon Forsberg
C'est la seule solution qui répond directement à la question.
Jiminion
8
hmm ... 33 votes positifs pour une réponse déjà donnée plus de 2 ans plus tôt avec à peu près les mêmes lignes de code. respect pour gagner autant de points pour cela. ;-)
Beachwalker
20

Cela a fonctionné pour moi:

#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
la source
3
Traduction française: "Je vais également répondre à ce message: p. C'est ma fonction."
sivabudh
9

Voici quelques routines de conversion que j'ai écrites il y a de nombreuses années pour un projet c ++ / cli, elles devraient toujours fonctionner.

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
la source
@alap, utilisez System :: Runtime :: InteropServices :: Marshal ou écrivez en utilisant l'espace de noms System :: Runtime :: InteropServices; .
neo
6

J'ai passé des heures à essayer de convertir une valeur ToString de liste de forme Windows en une chaîne standard afin de pouvoir l'utiliser avec fstream pour la sortie dans un fichier txt. Mon Visual Studio n'est pas fourni avec des fichiers d'en-tête de marshal que plusieurs réponses que j'ai trouvées utilisaient. Après tant d'essais et d'erreurs, j'ai finalement trouvé une solution au problème qui utilise simplement 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;

Et voici la page MSDN avec l'exemple: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Je sais que c'est une solution assez simple, mais cela m'a pris des HEURES de dépannage et de visite de plusieurs forums pour enfin trouver quelque chose qui fonctionnait.

Joe
la source
6

J'ai trouvé un moyen simple d'obtenir une std :: string à partir d'un String ^ est d'utiliser sprintf ().

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

Inutile d'appeler les fonctions Marshal!

MISE À JOUR Merci à Eric, j'ai modifié l'exemple de code pour vérifier la taille de la chaîne d'entrée afin d'éviter un débordement de tampon.

Ionien316
la source
1
C'est une décision curieuse d'introduire une vulnérabilité de dépassement de tampon dans votre code juste pour éviter d'appeler des fonctions spécialement conçues pour rassembler des chaînes.
Eric
Je présente simplement une approche différente si quelqu'un ne veut pas utiliser les fonctions de marshal. J'ai ajouté une vérification de la taille pour éviter tout débordement.
Ionian316
@Eric En interne, il organise pour vous. Voir cette réponse SO pour plus de détails. Si vous vérifiez la taille au préalable, vous n'aurez aucun problème de débordement et le code est beaucoup plus propre.
Ionian316
4

C # utilise le format UTF16 pour ses chaînes.
Donc, en plus de simplement convertir les types, vous devez également être conscient du format réel de la chaîne.

Lors de la compilation pour le jeu de caractères multi-octets, Visual Studio et l'API Win supposent UTF8 (en fait l'encodage Windows qui est Windows-28591 ).
Lors de la compilation pour jeu de caractères Unicode Visual Studio et l'API Win supposent UTF16.

Ainsi, vous devez également convertir la chaîne du format UTF16 au format UTF8, et pas seulement la convertir en std :: string.
Cela deviendra nécessaire lorsque vous travaillez avec des formats à plusieurs caractères comme certaines langues non latines.

L'idée est de décider que représente std::wstring toujours UTF16 .
Et représente std::string toujours UTF8 .

Ce n'est pas imposé par le compilateur, c'est plus une bonne politique à avoir.

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

Ou ayez-le dans une syntaxe plus compacte:

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
la source
1
Je veux juste souligner l'importance de la conversion en UTF8 dans mon cas d'utilisation: j'avais besoin de passer un chemin de fichier reçu de Win32 OpenFileDialog (où les noms de fichiers avec des caractères multi-octets sont possibles, par exemple les noms de fichiers contenant des caractères asiatiques) au code moteur via un std :: string, donc la conversion en UTF8 était vitale. Merci pour l'excellente réponse!
Jason McClinsey
0

J'aime rester à l'écart du marshaller.

Using CString newString(originalString);

Cela me semble beaucoup plus propre et plus rapide. Pas besoin de s'inquiéter de la création et de la suppression d'un contexte.

LL.
la source
0

// J'ai utilisé VS2012 pour écrire le code ci-dessous - convert_system_string en 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
la source