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.
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.
C doesn't have strings as first class values; you need to use strcpy() to assign strings.
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.
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++.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With