Using marshal_as for mixed-mode string conversions

The need to marshal between native and managed types is a very frequent scenario in mixed-mode programming. This is specially true when it comes to strings – when you’ve got MFC strings, COM strings, standard C++ strings and CLR strings and need to convert between those types. In fact that’s what prompted me to write the StringConvertor class for managed-unmanaged string conversions. While I did realize that I had misspelled converter as convertor I decided to leave it like that so I got a unique class-name and that way I could avoid Google dilution (there are dozens of other StringConverter classes, specially Java based ones).

Anyway, in the Orcas release of Visual C++, the VC++ team have added a mixed-mode marshalling library which primarily consists of the marshal_as template function. While marshal_as is technically not limited to string conversions, that is its most important role as of now. Using it is very similar to using one of the C++ cast operators such as static_cast – though be aware that you are not really casting here, you are doing a conversion – which may or may not be a different thing from a mere cast.

Here’s a code snippet that shows how to convert various native strings to System::String

String^ clrString;

const char* pcszHello = "hello world";
clrString = marshal_as<String^>(pcszHello);

wchar_t* pwszHello = L"hello wide world";
clrString = marshal_as<String^>(pwszHello);

bstr_t bstrtHello("hello bstr_t world");
clrString = marshal_as<String^>(bstrtHello);

std::string stdHello = "hello from std::string";
clrString = marshal_as<String^>(stdHello);

CString mfcString("hello from CString");
clrString = marshal_as<String^>(mfcString);

CComBSTR atrBSTR(L"hello from CComBSTR");
clrString = marshal_as<String^>(atrBSTR);

The reverse conversion is also similar.

String^ clrString = "Original System::String";

std::string stdHello = marshal_as<std::string>(clrString);
CString mfcString = marshal_as<CString>(clrString);
CComBSTR atrBSTR = marshal_as<CComBSTR>(clrString);

You cannot directly use marshal_as for converting a String^ to a const char*, a const wchar_t* or a BSTR – because those conversions require the unmanaged resources to be freed after use. For those, you need to use a context object as shown below.

marshal_context context;

const char* pcszHello = context.marshal_as<const char*>(clrString);
const wchar_t* pcwszHello = context.marshal_as<const wchar_t*>(clrString);
BSTR bstrString = context.marshal_as<BSTR>(clrString);

Console::WriteLine(context._clean_up_list.Count);

The context object keeps track of the allocated objects and frees them in its destructor. Internally it maintains a linked list of objects that are allocated, and the output of the Console::WriteLine in the above code will be 3 (as we have allocated three objects using the context object). Initially I found this a little annoying to do, but I couldn’t think of any alternate solution that was more elegant and where we could avoid using the context object. In fact, in my StringConvertor class I had internally used an std::vector to store all allocated objects so I could free them in the destructor.

Advertisements

9 thoughts on “Using marshal_as for mixed-mode string conversions

  1. So… Have CString, std::string, and CComBSTR been modified to internally use a marshal_context object? Or is marshal_context just a convenience, so that you can use marshal_as without having to worry about manually managing the memory / references created?

  2. Hey Shog,

    CString, std::string etc. do not need a context object since you don’t need to keep track of allocated resources. For instance in the case of CString, a CString object is returned by value and copied over to the left hand side variable. And it’s not really about convenience either; since we do not have control over how the memory is allocated, we can’t be sure how to delete the memory. Calling delete may not be appropriate for instance.

  3. Ah, i get it. So i could do something like,
    template ShogString marshal_as(String^ str)
    {…}

    …and internally use whatever technique made sense based on my class.

    Heh, that’s pretty slick. 😎

  4. Hi, to all.

    I have a question about constructing own namespace structure.

    I mean that when i create the structure such as System::Data::Odbc.

    Is there any different, possible way like the following?

    namespace System
    {
    namespace Data
    {
    namespace Odbc
    {
    //To do…
    }
    }
    }

    This makes me little tired..

    anyway, is there any different way for it?

    and, I already tried to like following

    System::Data::Odbc… surely.. it’s impossible….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s