问题
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.
回答1:
For anyone coming across this question struggling with the same problem, to summarize what pstrjds already said in a comment:
marshal as a
BSTR
and then instead of theCoTaskMemAlloc
call, createBSTR
objects
which effectively means changing the C#
struct
's definition from
[MarshalAs(UnmanagedType.LPWStr)]
public string TestString;
to
[MarshalAs(UnmanagedType.BStr)]
public string TestString;
and instead of using ::CoTaskMemAlloc
to allocate a string in C++
, ::SysAllocString
needs to be used.
I did not have to change the signature of the C++
struct
, since BSTR
(in my case) was in the end a typedef
for wchar_t*
.
来源:https://stackoverflow.com/questions/46877031/c-sharp-marshalling-a-c-struct-with-wchar-t-member-occasionally-leaves-the-he