Marshalling System.String to char* and Vice-Versa

By switching from C# with P/Invoke calls to Managed C++ when implementing a managed wrapper for the ANSI C style library I stumbled upon, I wanted to avoid the tedious and error-prone task of writing the P/Invoke signatures for function calls and user-defined types for the structures they used. As a side result I also managed to avoid most of the advanced marshaling issues with complex data structures.

With simple value types not needing any explicit marshaling only strings need special attention since char* and System::String can't be implicitly converted between. The Marshal class implements the methods necessary for doing this as demonstrated in the following snippet:

String^ MCPP::Together(String^ first, String^ second)  
   // marshal managed strings to unmanaged memory   
   IntPtr firstPtr = Marshal::StringToHGlobalAnsi(first);  
   IntPtr secondPtr = Marshal::StringToHGlobalAnsi(second);

   // cast unmanaged buffer to a character array  
   char* firstNative = static_cast<char*>(firstPtr.ToPointer());  
   char* secondNative = static_cast<char*>(secondPtr.ToPointer());

   // perform some unmanaged calls  
   int bufferSize = strlen(firstNative) + strlen(secondNative) + 4;  
   char* resultBuffer = new char[bufferSize];  
   sprintf_s(resultBuffer, bufferSize, "%s + %s", firstNative, secondNative);  

   // marshal unmanaged character array to managed string  
   String^ result = Marshal::PtrToStringAnsi(static_cast<IntPtr>(resultBuffer));  

   // free all unmanaged buffers  
   delete[] resultBuffer;  

   // return managed string  
   return result;  

It should be noted that it wouldn't make any sense switching to unmanaged code to do some string operations only as shown above. This is for demonstration purposes only and you would usually call some unmanaged libraries or the like instead of it. But it is a nice demonstration how cumbersome string operations were in C. If you were doing this once, the sprintf_s function call might have caught your attention. It's a safe implementation of sprintf which prevents buffer overflows.

Another point worth mentioning is that you have to take care of allocated memory for the conversion since your character array is now allocated on the unmanaged heap. Make sure you use the FreeHGlobal method to do it, not the free (used for freeing memory allocated by *alloc calls – ANSI C style) or delete (used for freeing memory allocated by new calls – C++ style) functions.

To reduce the code overhead of string conversions between managed and unmanaged world you might consider wrapping it into a helper class. This should also help preventing unwanted memory leaks during the conversions.

Creative Commons License