101

Can someone please post a simple code that would convert,

System::String^

To,

C++ std::string

I.e., I just want to assign the value of,

String^ originalString;

To,

std::string newString;
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
sivabudh
  • 31,807
  • 63
  • 162
  • 228

11 Answers11

184

Don't roll your own, use these handy (and extensible) wrappers provided by Microsoft.

For example:

#include <msclr\marshal_cppstd.h>

System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);
Juozas Kontvainis
  • 9,461
  • 6
  • 55
  • 66
tragomaskhalos
  • 2,733
  • 2
  • 17
  • 10
  • 2
    thx for this useful link, this hint saved me a lot of coding. as a side note: the templates/classes are in #include (e.g. #include ) and in the msclr::interop namespace, see an example at http://msdn.microsoft.com/de-de/library/vstudio/bb384859(v=vs.90).aspx) – Beachwalker Feb 11 '13 at 14:09
  • 4
    While this is convenient it totally lacks proper encoding support. See also my SO question: http://stackoverflow.com/questions/18894551/string-marshalling-with-marshal-as-and-encodings. My assumption is that marshal_as converts Unicode strings to the ACP in std::string. – Mike Lischke Aug 18 '15 at 13:28
  • MS Recommendation is to use marshal_context and delete it after conversion has been done. The link : https://msdn.microsoft.com/en-us/library/bb384856.aspx – Ruslan Makrenko Aug 09 '18 at 13:36
42

You can easily do this as follows

#include <msclr/marshal_cppstd.h>

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

std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);
VladL
  • 12,769
  • 10
  • 63
  • 83
Sriwantha Attanayake
  • 7,694
  • 5
  • 42
  • 44
  • +1 for a short and simple solution and simple working example (although there's an extra parenthesis at the end of your code) – Simon Forsberg Jul 01 '12 at 20:18
  • This is the only solution that directly answers the question. – Jiminion Jun 06 '14 at 12:41
  • 12
    hmm... 33 upvotes for an answer that was already given more than 2 years earlier with nearly the same lines of code. respect for gaining so many points for that. ;-) – Beachwalker Aug 05 '16 at 07:52
38

Check out System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni() and its friends.

Sorry can't post code now; I don't have VS on this machine to check it compiles before posting.

bluish
  • 26,356
  • 27
  • 122
  • 180
Martin
  • 5,392
  • 30
  • 39
20

This worked for me:

#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;
Ian Mackinnon
  • 13,381
  • 13
  • 51
  • 67
Alejandro Perea
  • 231
  • 2
  • 3
9

Here are some conversion routines I wrote many years ago for a c++/cli project, they should still work.

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
  • 4,505
  • 1
  • 27
  • 45
  • @alap, Use **System::Runtime::InteropServices::Marshal** or write **using namespace System::Runtime::InteropServices;**. – neo Aug 31 '17 at 09:31
7

I found an easy way to get a std::string from a String^ is to use sprintf().

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

No need to call the Marshal functions!

UPDATE Thanks to Eric, I've modified the sample code to check for the size of the input string to prevent buffer overflow.

Ionian316
  • 2,303
  • 2
  • 28
  • 36
  • 2
    It's a curious decision to introduce a buffer overflow vulnerability in your code just to avoid calling functions specially designed to marshall strings. – Eric Sep 09 '15 at 01:15
  • I'm simply presenting a different approach if someone doesn't want to use the marshal functions. I've added a check for the size to prevent overflow. – Ionian316 Sep 09 '15 at 20:12
  • @Eric Internally it is marshalling for you. See [this SO answer](http://stackoverflow.com/a/11831686/1516125) for details. If you check for the size beforehand, you won't have any overflow issues and the code is much cleaner. – Ionian316 Sep 18 '15 at 14:46
6

I spent hours trying to convert a windows form listbox ToString value to a standard string so that I could use it with fstream to output to a txt file. My Visual Studio didn't come with marshal header files which several answers I found said to use. After so much trial and error I finally found a solution to the problem that just uses 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;

And here is the MSDN page with the example: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

I know it's a pretty simple solution but this took me HOURS of troubleshooting and visiting several forums to finally find something that worked.

Joe
  • 61
  • 1
  • 1
4

C# uses the UTF16 format for its strings.
So, besides just converting the types, you should also be conscious about the string's actual format.

When compiling for Multi-byte Character set Visual Studio and the Win API assumes UTF8 (Actually windows encoding which is Windows-28591 ).
When compiling for Unicode Character set Visual studio and the Win API assume UTF16.

So, you must convert the string from UTF16 to UTF8 format as well, and not just convert to std::string.
This will become necessary when working with multi-character formats like some non-latin languages.

The idea is to decide that std::wstring always represents UTF16.
And std::string always represents UTF8.

This isn't enforced by the compiler, it's more of a good policy to have.

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

Or have it in a more compact 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
  • 48,127
  • 24
  • 147
  • 185
  • 1
    I just want to emphasize the importance of converting to UTF8 in my use case: I needed to pass a file path received from Win32 OpenFileDialog (where file names with multibyte characters are possible, e.g. file names containing Asian characters) to engine code via a std::string, so the conversion to UTF8 was vital. Thanks for the excellent answer! – Jason McClinsey Sep 07 '19 at 01:21
0

I like to stay away from the marshaller.

Using CString newString(originalString);

Seems much cleaner and faster to me. No need to worry about creating and deleting a context.

LL.
  • 129
  • 1
  • 12
0

// I used VS2012 to write below code-- 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
  • 912
  • 1
  • 12
  • 25
0

For me, I was getting an error with some of these messages. I have an std::string. To convert it to String^, I had to do the following String^ sysString = gcnew String(stdStr.c_str()); where sysString is a System::String^ and stdStr is an std::string. Hope this helps someone

You may have to #include <string> for this to work