Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c#

pinvoke

I am trying to make the absolute simplest minimal example of how to pass strings to and from a C++ DLL in C#.

My C++ looks like this:

using std::string;  extern "C" {     string concat(string a, string b){         return a + b;     } } 

With a header like

using std::string;  extern "C" {     // Returns a + b     __declspec(dllexport) string concat(string a, string b); } 

My C# is

[DllImport("*****.dll", CallingConvention = CallingConvention.Cdecl)]     static extern string concat(string a, string b); } 

And I am calling it with: Console.WriteLine(concat("a", "b"));

But this gives a System.AccessViolationException. This seems like it out to be the most trivial thing to deal with, but I am completely stuck on it. When I tried to do a similar experiment with a function "Add" that took two doubles and returned a double I had no problems.

like image 893
asutherland Avatar asked Dec 23 '13 22:12

asutherland


People also ask

How do you pass strings?

To pass a string by value, the string pointer (the s field of the descriptor) is passed. When manipulating IDL strings: Called code should treat the information in the passed IDL_STRING descriptor and the string itself as read-only, and should not modify these values.

Can you pass a string by value in C?

C doesn't have strings as first class values; you need to use strcpy() to assign strings.

Can you pass a string into a function?

To pass a one dimensional string to a function as an argument we just write the name of the string array variable. In the following example we have a string array variable message and it is passed to the displayString function.

How do you pass a string by reference?

Pass String by Reference in C++ The C++ reference is a name for a variable that already exists. A reference to a variable can't be altered to refer to the other variable once initialized. Pointers or references can be passed as parameters to functions in C++.


1 Answers

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); 
like image 84
David Heffernan Avatar answered Sep 17 '22 12:09

David Heffernan