简体   繁体   中英

How to convert C++/CLI string to const char*

I've got a C++/CLI DLL I plan to use as an adapter between my C# DLL and native C++ clients. I need to pass strings in both directions. The adapter is compiled with VS2013 but needs to support clients built with VS2008 so I'm using const char* in the API. But what I've got isn't working even when both are VS2013-built.

Elsewhere, I found advice to use msclr\\marshal.h, so I created:

using namespace msclr::interop;
System::String^ ToCliString(const char* s)
{
    System::String ^result = marshal_as<System::String^>(s);
    return result;
}    
const char* ToCppString(System::String^ s)
{
    msclr::interop::marshal_context context;
    const char* result = context.marshal_as<const char*>(s);
    return result;
}

To test these, I created a round-trip conversion method in my C++/CLI DLL:

const char* Foo(const char *cstar)
{
    System::String^ cli = ::ToCliString(cstar);

    if (cli == "abc")
    {
        MessageBox::Show("const char* -> CLI: OK");
    }

    const char* cstar2 = ::ToCppString(cli);

    if (std::strcmp(cstar2, "abc") == 0)
    {
        MessageBox::Show("CLI -> const char*: OK");
    }
    else if (std::strcmp(cstar2, "") == 0)
    {
        MessageBox::Show("ToCppString returned empty string");
    }
    else
    {
        MessageBox::Show("ToCppString returned something else");
    }

    return cstar2;
}

When the native C++ client calls Foo("abc"), the 1st message gets displayed, the "returned something else" message gets displayed and the client receives junk (îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþÞ›vÚ§). So it would seem my 2nd conversion is not working.

UPDATE

Here's the final solution I used.

I used zneaks' advice to marshall to std::string and PaulMcKenzie's advice to pass a caller-allocated char* instead of returning const char*. Thank you both.

void ToCppString(System::String^ input, char* output)
{
    std::string temp= marshal_as<std::string>(input);
    strcpy(output, temp.c_str());
}

void Foo(const char* input, char* output)
{
    System::String^ cli = ::ToCliString(input);
    ::ToCppString(cli, output);
}

The problem is that the marshal_context owns the char pointer that you got, so it is deallocated when your function returns :

This example creates a context for marshaling from a System::String to a const char * variable type.The converted data will not be valid after the line that deletes the context.

Consider using marshal_as<std::string> instead, since the string is allowed to outlive the marshal_context .

Additionally, please be aware that VC++ 2008 express does not contains marshal header files (marshal.h and others), so you have to use VC++ 2008 pro or onwards. Looks like those header files are included in express edition since VS2010.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM