C ++ / CLI convertendo de System :: String ^ para std :: string

90

Alguém pode postar um código simples que possa converter,

System::String^

Para,

C ++ std::string

Ou seja, eu só quero atribuir o valor de,

String^ originalString;

Para,

std::string newString;
Sivabudh
fonte

Respostas:

38

Confira System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()e seus amigos.

Desculpe, não posso postar código agora; Não tenho VS nesta máquina para verificar se ele compila antes de postar.

Martin
fonte
159

Não crie o seu próprio, use esses invólucros úteis (e extensíveis) fornecidos pela Microsoft.

Por exemplo:

#include <msclr\marshal_cppstd.h>

System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);
tragomaskhalos
fonte
2
Obrigado por este link útil, essa dica me salvou muito de codificação. como observação lateral: os modelos / classes estão em #include <msclr \ *. h> (por exemplo, #include <msclr \ marshal.h>) e no namespace msclr :: interop, veja um exemplo em msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker
4
Embora seja conveniente, falta totalmente o suporte de codificação adequado. Veja também minha pergunta sobre o SO: stackoverflow.com/questions/18894551/… . Minha suposição é que marshal_as converte strings Unicode em ACP em std :: string.
Mike Lischke de
A recomendação da MS é usar marshal_context e excluí-lo após a conversão. O link: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko
40

Você pode fazer isso facilmente da seguinte maneira

#include <msclr/marshal_cppstd.h>

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

std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);
Sriwantha Attanayake
fonte
+1 para uma solução curta e simples e um exemplo de trabalho simples (embora haja um parêntese extra no final do seu código)
Simon Forsberg
Esta é a única solução que responde diretamente à pergunta.
Jiminion
8
hmm ... 33 votos positivos para uma resposta que já foi dada mais de 2 anos antes com quase as mesmas linhas de código. respeito por ganhar tantos pontos por isso. ;-)
Beachwalker
20

Isso funcionou para mim:

#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
fonte
3
Tradução em inglês: "Vou responder a este post também: p. Esta é a minha função."
sivabudh
9

Aqui estão algumas rotinas de conversão que escrevi há muitos anos para um projeto c ++ / cli, elas ainda devem funcionar.

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
fonte
@alap, Use System :: Runtime :: InteropServices :: Marshal ou escreva usando o namespace System :: Runtime :: InteropServices; .
neo
6

Passei horas tentando converter um valor ToString da caixa de listagem do Windows em uma string padrão para que eu pudesse usá-lo com fstream para gerar um arquivo txt. Meu Visual Studio não veio com arquivos de cabeçalho de empacotamento que várias respostas que encontrei diziam para usar. Depois de tantas tentativas e erros finalmente encontrei uma solução para o problema que apenas usa 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;

E aqui está a página do MSDN com o exemplo: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Eu sei que é uma solução muito simples, mas isso me levou HORAS de solução de problemas e visitando vários fóruns para finalmente encontrar algo que funcionasse.

Joe
fonte
6

Eu descobri uma maneira fácil de obter um std :: string de um String ^ usando sprintf ().

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

Não há necessidade de chamar as funções do Marshal!

ATUALIZAÇÃO Graças a Eric, modifiquei o código de amostra para verificar o tamanho da string de entrada para evitar estouro de buffer.

Ionian316
fonte
1
É uma decisão curiosa introduzir uma vulnerabilidade de estouro de buffer em seu código apenas para evitar a chamada de funções especialmente projetadas para marshall strings.
Eric,
Estou simplesmente apresentando uma abordagem diferente se alguém não quiser usar as funções de marechal. Eu adicionei uma verificação para o tamanho para evitar transbordamento.
Ionian316,
@Eric internamente é o marshalling para você. Veja esta resposta do SO para detalhes. Se você verificar o tamanho com antecedência, não terá problemas de estouro e o código é muito mais limpo.
Ionian316 de
4

OC # usa o formato UTF16 para suas strings.
Portanto, além de apenas converter os tipos, você também deve estar ciente do formato real da string.

Ao compilar para o conjunto de caracteres multibyte, o Visual Studio e a API do Win assume UTF8 (na verdade, a codificação do Windows é Windows-28591 ).
Ao compilar para o conjunto de caracteres Unicode, o Visual studio e a API Win assumem UTF16.

Portanto, você deve converter a string do formato UTF16 para UTF8 também, e não apenas converter para std :: string.
Isso se tornará necessário ao trabalhar com formatos de vários caracteres, como alguns idiomas não latinos.

A ideia é decidir que std::wstring sempre representa UTF16 .
E std::string sempre representa UTF8 .

Isso não é imposto pelo compilador, é mais uma boa política de se ter.

#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 use uma sintaxe mais compacta:

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
fonte
1
Só quero enfatizar a importância da conversão para UTF8 no meu caso de uso: eu precisava passar um caminho de arquivo recebido do Win32 OpenFileDialog (onde nomes de arquivo com caracteres multibyte são possíveis, por exemplo, nomes de arquivo contendo caracteres asiáticos) para o código do mecanismo por meio de um std :: string, então a conversão para UTF8 foi vital. Obrigado pela excelente resposta!
Jason McClinsey
0

Gosto de ficar longe do marshaller.

Using CString newString(originalString);

Parece muito mais limpo e rápido para mim. Não precisa se preocupar em criar e excluir um contexto.

LL.
fonte
0

// Usei VS2012 para escrever o código abaixo - convert_system_string para 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
fonte