[ACCEPTED]-Pass C# string to C++ and pass C++ result (string, char*.. whatever) to C#-interop
What I've found to work best is to be more 14 explicit about what's going on here. Having 13 a string as return type is probably not 12 recommended in this situation.
A common 11 approach is to have the C++ side be passed 10 the buffer and buffer size. If it's not 9 big enough for what GetString has to put 8 in it, the bufferSize variable is modified 7 to indicate what an appropriate size would 6 be. The calling program (C#) would then 5 increase the size of the buffer to the appropriate 4 size.
If this is your exported dll function 3 (C++):
extern "C" __declspec void GetString( char* buffer, int* bufferSize );
Matching C# would be the following:
void GetString( StringBuilder buffer, ref int bufferSize );
So 2 to use this in C# you would then do something 1 like the following:
int bufferSize = 512; StringBuilder buffer = new StringBuilder( bufferSize ); GetString( buffer, ref bufferSize );
The only good way that I know of doing this 14 is to write a .NET C++ wrapper class using 13 Managed C++ Extensions, and within the .NET C++ object call your 12 native C++ code. There are functions in 11 the managed extensions to convert a System.String 10 to a char* or any other type of unmanaged 9 string.
Basically you create a .NET class 8 using C++ and expose it from an assembly, and 7 internally to that assembly you can call 6 your native C++ code. The other way is 5 to add a pure C function to your C++ code 4 using P/Invoke and then call your C code 3 from C# and have your C function call your 2 C++ code. This will work, but I tend to 1 try to use managed code as much as possible.
The biggest problem with passing strings 10 from C++ back to C# is the memory allocation. The 9 GC should be able to know how to cleanup 8 the memory allocated for this string. Since 7 C# has extensive COm interop support, it 6 does know about COM BSTRs and how to allocate 5 and deallocate these. Thus the easiest way 4 to do this would be to use
BSTR on the C++ side 3 and
string on the C# side.
Note, using BSTRs does 2 not imply that your function has to be expose 1 through COM.
The "string" return value is the problem. The 10 P/Invoke marshaller is going to call CoTaskMemFree() on 9 the pointer you return. That's not going 8 to work well unless you used CoTaskMemAlloc() in 7 your C/C++ code to allocate the string buffer. Which 6 is a fairly unusual thing to do.
The best 5 solution is to allow the caller of your 4 code to pass a pointer to a buffer and the 3 buffer length to you as arguments. That 2 way all memory allocation happens on one 1 side. Scott showed you how to do this.
I had to convert a unicode C# string to 5 a multibyte representation in order to convert 4 to char* in c++ (this is partial one way 3 solution)
I found the following very useful 2
string st; IntPtr stPtr = Marshal.StringToHGlobalAnsi(st); // Do your thing in C++ Marshal.FreeHGlobal(stPtr);
This may be inefficient and not in C# manner, I'm 1 new to C#.
More Related questions