not a lot of experience in C++. Attempting to Marshal char* in C to string in C#, using [MarshalAs(UnmanagedType.LPStr)], but I get a "a heap has been corrupted" exception. It does however work in reverse (string in C# to char* in C). What am I doing wrong here?
More details: on C side, this is the struct:
struct STRUCTV
{
char* _pretext;
char* _result;
};
this is C function signature: void add_all_numbers(STRUCTV *structV);
This is C# side
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct STRUCTV
{
[MarshalAs(UnmanagedType.LPStr)]
public string _pretext;
[MarshalAs(UnmanagedType.LPStr)]
public string _result; //<----THIS ISNT WORKING
}
internal partial class NativeMethods
{
[DllImport(
"Library.dll",
EntryPoint = "function1",
CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
public static extern void function1(ref STRUCTV structV);
}
this is how i use it:
STRUCTV myStruct = new STRUCTV();
myStruct._pretext = "Pretext";
myStruct._result = null;
NativeMethods.function1(ref myStruct); //<---- ntdll.dll : A heap has been corrupted"
Console.WriteLine(myStruct._result);
In case this is important, this is what happens inside C code if that's important:
string resultstring = GetResult();
char* result = new char[resultstring.length() + 1];
strcpy_s(result, resultstring.length() + 1, resultstring.c_str());
structV->_result = result;
Some additional information. it works if I don't marshal the char* as string in _result, and i want to understand why.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct STRUCTV
{
[MarshalAs(UnmanagedType.LPStr)]
public string _pretext;
public IntPtr _result;
}
STRUCTV myStruct = new STRUCTV();
myStruct._pretext = "Pretext";
myStruct._result = IntPtr.Zero;
NativeMethods.function1(ref myStruct);
string resultString = Marshal.PtrToStringAnsi(myStruct._result);
Console.WriteLine(resultString);
The C# code is assuming that it's responsible for passing the
_resultstring into the C++ code as a preallocatedchar*pointer. But, the C++ code is actually allocating its own memory for the_resultstring and returning the pointer back to the C# code. So, you shouldn't marshal the_resultstring usingLPStrthe way you are trying to do, since it's output data not input data.Using
IntPtris one viable way to handle this. You can then useMarshal.PtrToStringAnsi()to convert theIntPtrinto a C#string. However, in this case, do note that the C++ code isnew[]'ing the_resultstring, and C# cannot free that memory. So, you will have to export another function from the C++ code which the C# code can then call to pass the returnedIntPtrback to C++ so it can properlydelete[]the memory, eg:The alternative is to allocate the memory on the C# side instead, and then have the C++ code just fill the memory, eg:
Alternatively:
Read Default Marshalling for Strings on MSDN for more details.