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.
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?
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.
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. 😎
Oh… these are HTML comments. Wish that was noted somewhere…
template<> ShogString marshal_as<ShogString>(String^ str)
{…}
Very nice! I really need to get my c++/cli back on.
wow..
excellent!
Thanks a lot!!
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….
hi all.
Hey Nish,I have purcased book written by you on C++/CLI.Can you guide me how to warap enums.