Search code examples
c#c++commarshalling

Returning a string from an unmanaged c++ dll to c#


I'm trying to call unmanaged c++ from c# but receiving an exception about the return value. The exception:

System.Runtime.InteropServices.MarshalDirectiveException: 'Cannot marshal 'return value': Invalid managed/unmanaged type combination (Arrays can only be marshaled as LPArray, ByValArray, or SafeArray).'

I have a similar function that look the same without the return value (void) that do work without any problems.

I set the platform (compiler) of the c++ project to be v100 (Visual Studio 2010) and use .net 4.5 at the c# project.

The c++ project created a lib+dll files that I put both at the executable folder.

When I try to replace the return value to be "String" at the c# code, the exception converted to be:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

When I remove the return value function property ([return: MarshalAs(UnmanagedType.BStr)]) I receive the following exception:

System.Runtime.InteropServices.MarshalDirectiveException: 'Cannot marshal 'return value': Invalid managed/unmanaged type combination.'

And when I do the combination of: removing the return value function property and converting the return type to string, the application just close itself without catch any exception.

C++ code

extern "C"
{
    ExternalDll_API char* FuncA(char* projectId);
}

ExternalDll_API char* FuncA(char* projectId)
{
    return "abc";
}

C# code

[DllImport("ExternalDll.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern char[] FuncA(string projectId);

var key = FuncA(projectId.ToString());

Solution

  • To receive a null-terminated string from a C++ dll you can do this:

    1. Change the return type to IntPtr:

      [DllImport("ExternalDll.dll")]
      public static extern IntPtr FuncA(string projectId);
      
    2. Retrieve the string from the pointer using Marshal:

      var result = FuncA(someString);
      var strResult = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(result);