I have declared a struct
as follows:
// C++
struct TestStruct
{
wchar_t* TestString;
};
and the corresponding managed representation
// C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TestStruct
{
[MarshalAs(UnmanagedType.LPWStr)]
public string TestString;
}
As well as this function:
// C++
__declspec(dllexport) void __stdcall FillMultipleStructs(TestStruct* testStructures, const short arrayLength)
{
for(int i = 0; i < arrayLength; i++)
{
const wchar_t stringToAllocate[] = L"foo";
const unsigned long size = wcslen(stringToAllocate) * sizeof(wchar_t) + sizeof(wchar_t);
wchar_t* allocatedString = static_cast<wchar_t*>(::CoTaskMemAlloc(size));
wcscpy_s(allocatedString, size, stringToAllocate);
(&testStructures[i])->testString = allocatedString;
}
}
which is called by the FillMultipleStructs
method, that takes multiple TestStructs
and initializes them in the C++ code.
// C#
[DllImport("the path", CallingConvention = CallingConvention.StdCall, EntryPoint = "FillMultipleStructs", ExactSpelling = true, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern void _FillMultipleStructs([In, Out] TestStruct[] structures, [MarshalAs(UnmanagedType.I2)] short arrayLength);
public static IEnumerable<TestStruct> FillMultipleStructs(IEnumerable<TestStruct> structures)
{
TestStruct[] structuresArray = structures.ToArray();
_FillMultipleStructs(structuresArray, (short) structuresArray.Length);
return structuresArray;
}
Calling the code works like this:
FillMultipleStructs(
new List<TestStruct>()
{
new TestStruct(),
new TestStruct(),
new TestStruct()
});
Now, the question is: sometimes, the code works, however, sometimes I get an a heap has been corrupted
error. I do not understand where that comes from nor why it does work occasionally and sometimes it does not.
I guess it has to do with the marshalling of the struct
's string member, so, if anyone can tell me where my error is or if anyone can point me in the right direction or show me the proper way to do that, I would gladly appreciate that.
For anyone coming across this question struggling with the same problem, to summarize what pstrjds already said in a comment:
which effectively means changing the
C#
struct
's definition fromto
and instead of using
::CoTaskMemAlloc
to allocate a string inC++
,::SysAllocString
needs to be used.I did not have to change the signature of the
C++
struct
, sinceBSTR
(in my case) was in the end atypedef
forwchar_t*
.