0

I have searched far and wide for an answer to my question, and all the solutions are not acceptable, not applicable, and/or confusing.

I am needing to return a string from a function implemented in C++ back to the calling code in C#.

The returned string needs to be returned as a parameter rather than a return value since I need to pass/return multiple strings for some functions. The length of the string varies, so I can't just allocate a buffer, etc.

Any help would be appreciated.

NOTE: The solution posted and mentioned by Justin and/or others is NOT a solution for my use case. As I stated in the question, I do not know the size of the string prior to making the call to the C++ code. I can't pre-allocate a StringBuffer and pass it to the C++ code.

3 Answers3

2

One way is to declare the parameter as ref IntPtr. So:

static extern void DoSomething(ref IntPtr returnedString);

So you call it and get a string with:

IntPtr pstr;
DoSomething(ref pstr);
string theString = Marshal.PtrToStringAnsi(pstr);

However, it's important to remember that the returned pointer was allocated by your C++ code. If you want it to be deallocated, you'll need to call the C++ code to do it.

You might also want to look at Marshal.PtrToStringAuto, and other similar functions.

Note also that this copies the data from the pointer to the string. If you want to refer to the string in place, you'll have to play with IntPtr and the Marshal class, or delve into the wonderful world of unsafe code and pointers.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • `Marshal.PtrToStringAnsi` is good if you have to communicate with a binary blob. It's never a good choice if you have control of both sides. – Ben Voigt Aug 19 '13 at 14:29
  • @BenVoigt: Understood. From the Q, I figured he didn't have control. – Jim Mischel Aug 19 '13 at 16:24
  • What does the C++ prototype look like? Is it: void DoSomething(int* returnedString); ? The C++ code is Native, not managed. – Stephen osella Aug 19 '13 at 20:18
  • @Stephenosella: The C++ prototype would be `void DoSomething(char* returnedString);` Or, if you're returning Unicode strings: `TCHAR * returnedString);` – Jim Mischel Aug 19 '13 at 20:20
  • So something like: std::string str = "The quick brown fox jumps over the lazy dog"; returnedString = new char[str.length() + 1]; str.copy(returnedString, str.length() - 1, 0); – Stephen osella Aug 19 '13 at 23:53
0

Adding to Jim Michel's answer, I would create a helper function, like

String FromCppString(IntPtr a_Pointer)
{
    String result = Marshal.PtrToStringAnsi(a_Pointer);
    FreeCppString(a_Pointer);
    return result;
}

where FreeCppString is another function exported from C++, freeing the string properly. The original c++ function will just allocate as many strings as necessary and put them into parameters. The C# function will use FromCppString() to extract them.

Codeguard
  • 7,787
  • 2
  • 38
  • 41
0

Use the portable (multi-compiler multi-language) string provided by the platform for the express purpose of passing strings between components implemented in different languages -- BSTR.

In C++, you use SysAllocString or SysAllocStringLen. P/invoke already knows how to deal with these (convert to .NET string and call SysFreeString) as long as you use the right signature.

extern static void DoSomething([MarshalAs(UnmanagedType.BStr)] out String returnedString);

And then simply call it:

string theString;
DoSomething(out theString);

That's it, no special conversions or cleanup necessary, since p/invoke took care of it.

For more information, read this MSDN page on string handling in p/invoke

NOTE: I guess none of the examples in the link are exactly this case, so here's the C++ prototype

void DoSomething(__out BSTR *s);
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • What does the C++ prototype look like? Is it: void DoSomething(char** returnedString); ? The C++ code is Native. – Stephen osella Aug 19 '13 at 20:14
  • @Stephenosella: `SysAllocString` and `SysFreeString` are native functions available when you `#include `. You can either use Unicode, or `SysAllocStringByteLen` and `[MarshalAs(UnmanagedType.AnsiBStr)]` – Ben Voigt Aug 19 '13 at 20:21