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;
Marshal::FreeHGlobal(firstPtr);
Marshal::FreeHGlobal(secondPtr);
// 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.