C ++ / CLI Mengkonversi dari System :: String ^ ke std :: string

91

Bisakah seseorang mengeposkan kode sederhana yang akan mengubah,

System::String^

Untuk,

C ++ std::string

Yaitu, saya hanya ingin memberikan nilai,

String^ originalString;

Untuk,

std::string newString;
sivabudh.dll
sumber

Jawaban:

38

Lihat System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()dan teman-temannya.

Maaf tidak dapat memposting kode sekarang; Saya tidak memiliki VS di mesin ini untuk memeriksanya mengkompilasi sebelum memposting.

Martin
sumber
162

Jangan roll Anda sendiri, gunakan ini berguna (dan extensible) bungkus yang disediakan oleh Microsoft.

Sebagai contoh:

#include <msclr\marshal_cppstd.h>

System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);
tragomaskhalos
sumber
2
terima kasih untuk tautan yang berguna ini, petunjuk ini menghemat banyak pengkodean. sebagai catatan tambahan: template / kelas ada di #include <msclr \ *. h> (misalnya #include <msclr \ marshal.h>) dan di namespace msclr :: interop, lihat contoh di msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker
4
Meskipun ini nyaman, ini sama sekali tidak memiliki dukungan pengkodean yang tepat. Lihat juga pertanyaan SO saya: stackoverflow.com/questions/18894551/… . Asumsi saya adalah bahwa marshal_as mengubah string Unicode ke ACP di std :: string.
Mike Lischke
Rekomendasi MS adalah menggunakan marshal_context dan menghapusnya setelah konversi selesai. Tautan: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko
40

Anda dapat dengan mudah melakukan ini sebagai berikut

#include <msclr/marshal_cppstd.h>

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

std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);
Sriwantha Attanayake
sumber
+1 untuk solusi singkat dan sederhana serta contoh kerja sederhana (meskipun ada tanda kurung tambahan di akhir kode Anda)
Simon Forsberg
Ini adalah satu-satunya solusi yang menjawab pertanyaan secara langsung.
Jiminion
8
hmm ... 33 suara positif untuk jawaban yang sudah diberikan lebih dari 2 tahun sebelumnya dengan baris kode yang hampir sama. rasa hormat untuk mendapatkan begitu banyak poin untuk itu. ;-)
Beachwalker
20

Ini berhasil untuk saya:

#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
sumber
3
Terjemahan bahasa Inggris: "Saya akan menanggapi posting ini juga: p. Ini adalah fungsi saya."
sivabudh
9

Berikut adalah beberapa rutinitas konversi yang saya tulis bertahun-tahun yang lalu untuk proyek c ++ / cli, mereka masih harus berfungsi.

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
sumber
@alap, Gunakan System :: Runtime :: InteropServices :: Marshal atau tulis menggunakan namespace System :: Runtime :: InteropServices; .
neo
6

Saya menghabiskan berjam-jam mencoba untuk mengubah nilai ToString listbox windows form menjadi string standar sehingga saya dapat menggunakannya dengan fstream untuk menghasilkan output ke file txt. Visual Studio saya tidak datang dengan file header marshal yang menurut beberapa jawaban saya gunakan. Setelah begitu banyak trial and error akhirnya saya menemukan solusi untuk masalah yang hanya menggunakan 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;

Dan berikut adalah halaman MSDN dengan contoh: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Saya tahu ini adalah solusi yang cukup sederhana tetapi ini membutuhkan waktu berjam-jam untuk memecahkan masalah dan mengunjungi beberapa forum untuk akhirnya menemukan sesuatu yang berfungsi.

Joe
sumber
6

Saya menemukan cara mudah untuk mendapatkan std :: string dari String ^ adalah dengan menggunakan sprintf ().

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

Tidak perlu memanggil fungsi Marsekal!

UPDATE Terima kasih kepada Eric, saya telah memodifikasi kode sampel untuk memeriksa ukuran string input untuk mencegah buffer overflow.

Ionia316
sumber
1
Merupakan keputusan yang aneh untuk memperkenalkan kerentanan buffer overflow dalam kode Anda hanya untuk menghindari fungsi panggilan yang dirancang khusus untuk menyusun string.
Eric
Saya hanya menyajikan pendekatan yang berbeda jika seseorang tidak ingin menggunakan fungsi marshal. Saya telah menambahkan tanda centang untuk ukuran untuk mencegah luapan.
Ionian316
@Eric Secara internal itu mengatur untuk Anda. Lihat jawaban SO ini untuk detailnya. Jika Anda memeriksa ukurannya sebelumnya, Anda tidak akan mengalami masalah overflow dan kodenya jauh lebih bersih.
Ionian316
4

C # menggunakan format UTF16 untuk stringnya.
Jadi, selain hanya mengonversi tipe, Anda juga harus sadar tentang format string sebenarnya.

Ketika mengkompilasi untuk kumpulan Karakter Multi-byte Visual Studio dan Win API mengasumsikan UTF8 (Sebenarnya pengkodean windows yang Windows-28591 ).
Saat menyusun untuk kumpulan Karakter Unicode Visual studio dan Win API mengasumsikan UTF16.

Jadi, Anda juga harus mengonversi string dari format UTF16 ke UTF8, dan tidak hanya mengonversi ke std :: string.
Ini akan menjadi penting saat bekerja dengan format multi-karakter seperti beberapa bahasa non-latin.

Idenya adalah untuk memutuskan bahwa std::wstring selalu mewakili UTF16 .
Dan std::string selalu mewakili UTF8 .

Ini tidak diberlakukan oleh kompilator, ini lebih merupakan kebijakan yang baik untuk dimiliki.

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

Atau miliki dalam sintaks yang lebih ringkas:

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
sumber
1
Saya hanya ingin menekankan pentingnya mengonversi ke UTF8 dalam kasus penggunaan saya: Saya perlu meneruskan jalur file yang diterima dari Win32 OpenFileDialog (di mana nama file dengan karakter multibyte dimungkinkan, misalnya nama file yang berisi karakter Asia) ke kode mesin melalui std :: string, jadi konversi ke UTF8 sangat penting. Terima kasih atas jawaban yang luar biasa!
Jason McClinsey
0

Saya suka menjauh dari marshaller.

Using CString newString(originalString);

Tampak jauh lebih bersih dan lebih cepat bagi saya. Tidak perlu khawatir tentang membuat dan menghapus konteks.

LL.
sumber
0

// Saya menggunakan VS2012 untuk menulis kode di bawah ini-- convert_system_string ke 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
sumber