Passing strings from C# to C++ DLL and back -- minimal example

You cannot pass a C++ std::string across an interop boundary. You cannot create one of those in your C# code. So your code can never work.

You need to use interop friendly types at the interop boundary. For instance, null-terminated arrays of characters. That works well when you allocate and deallocate the memory in the same module. So, it's simple enough when passing data from C# to C++.

C++

void foo(const char *str)
{
    // do something with str
}

C#

[DllImport("...", CallingConvention = CallingConvention.Cdecl)
static extern void foo(string str);

....

foo("bar");

In the other direction you would typically expect the caller to allocate the buffer, into which the callee can write:

C++

void foo(char *str, int len)
{
    // write no more than len characters into str
}

C#

[DllImport("...", CallingConvention = CallingConvention.Cdecl)
static extern void foo(StringBuilder str, int len);

....

StringBuilder sb = new StringBuilder(10);
foo(sb, sb.Capacity);

This is the simplest way I like - pass a string in, and use a lambda to get the response

C#

 public delegate void ResponseDelegate(string s);

 [DllImport(@"MyDLL.dll", EntryPoint ="Foo", CallingConvention = CallingConvention.StdCall)]
 public static extern void Foo(string str, ResponseDelegate response);
 ...
 
 Foo("Input", s =>
 {
    // response is returned in s - do what you want with it
 });

C++

 typedef void(_stdcall *LPEXTFUNCRESPOND) (LPCSTR s);

 extern "C"
 {
     __declspec(dllexport) void __stdcall Foo(const char *str, LPEXTFUNCRESPOND respond) 
     {
         // Input is in str
         // Put your response in respond()
         respond("HELLO");
     }
 } 

Tags:

C#

C++

Pinvoke