I was never really into the C world (went straight into C++ and from there into other OO languages like C#) and I now want to use C++/CLI as a bridge between C++ Builder and .net core dlls (and since the VC++ ABI is not necessarily the same as C++ Builder, via a C-style DLL interface). Both sides are 64bit.
Almost all examples I have found use only numbers for the interfaces, but I am concerned with in/out of strings (more precisely Unicode strings, wchar_t). Here I am not 100% sure in the application without causing memory leaks, I would also like to take over all allocations in the C++ Builder application, for out strings create the buffer on the C++ Builder side.
How to copy the content of a managed string into a buffer passed via wchar_t** without allocating memory on the C++/CLI side? I have only found one example where the string from the C++/CLI application is passed as a return value and then released via a second call. I also get an error in the VS for this case because of an unimplemented abstract method when using IntPtr (see below).
The interface should essentially look like this:
#ifndef NetWrapperC_HEADER
#define NetWrapperC_HEADER
#ifdef NETWRAPPER_EXPORTS
#define NETWRAPPER __declspec(dllexport)
#else
#define NETWRAPPER __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
NETWRAPPER void DoSomething(wchar_t* input, wchar_t** output, int64_t output_len);
#ifdef __cplusplus
}
#endif
#endif
What I found would lead to the following interface, but I want to allocate the output buffer at the caller:
NETWRAPPER wchar_t* DoSomething(wchar_t* input);
NETWRAPPER void FreeString(wchar_t* text);
With the example found, the whole thing would probably be implemented as follows:
wchar_t* DoSomething(
wchar_t* text)
{
System::String^ input = gcnew System::String(text);
System::String^ output = DotNetDLL::DoSomething(input);
// In the example, the return value was formed as follows, I am already puzzled by the double conversion.
return (wchar_t*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalUni(output);
}
void FreeStringResult(
wchar_t* const text)
{
// Not only do I actually want to avoid such a call, but a note in the Visual Studio also makes me nervous: "IntPtr...is a unimplemented interface method"
System::Runtime::InteropServices::Marshal::FreeHGlobal(System::IntPtr::IntPtr(text));
}
I would prefer to have the signature in such a way that the buffer was allocated by the caller, and the content of the return string would be copied into it without memory allocation. Does anyone have an example of this?
cu André