Tales from the Unmanaged Side – System.String –> char* (pt. 2)

A while ago, I posted an entry about marshalling a managed System.String into an unmanaged C string, specifically a plain char*. The solution I suggested, back in 2007, involved calling Marshal::StringToHGlobalAuto method to allocate memory and copy the string data into it, and then cast the HGlobal pointer into a char*.

It seems that in Visual Studio 2008 a new way of doing it was added, as part of the new Marshalling Library. This library provides a whole set of conversions between System.String and popular unmanaged string representations, like char*, wchar_t*, BSTR, CStringT and others I am even less familiar with.

The smarter string representations, like std::string, have their own destructors so I can carelessly let them drop out of scope without worrying about leaks. The more primitive ones, like char*, need to be explicitly released, so that’s why the Marshalling Library contains a new (managed) class called marshal_context which gives me exactly this explicit release.

Let’s compare my old code with the new:

   1:  const char* unmanagedString = NULL;
   2:  try
   3:  {
   4:      String^ managedString = gcnew String("managed string");
   5:      // Note the double cast.
   6:      unmanagedString = (char*)(void*)Marshal::StringToHGlobalAnsi(managedString);
   7:  }
   8:  finally
   9:  {
  10:      // Don't forget to release. Note the ugly casts again.
  11:      Marshal::FreeHGlobal((IntPtr)(void*)unmanagedString);
  12:  }

And the new:

   1:  marshal_context^ context = gcnew marshal_context();
   2:  String^ managedString = gcnew String("managed string");
   3:  const char* unmanagedString = context->marshal_as<const char*>( managedString );

Much shorter, I’m sure you’ll agree. And neater – no need for all the icky, icky casting between different pointer types. And most importantly, I don’t have to explicitly release the char* – the marshal_context class keeps a reference to all the strings that were marshalled through it, and when it goes out of scope its destructor makes sure to release them all. Very efficient, all in all.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.