C#使用wchar_t *成员编组C ++结构偶尔会使堆损坏

时间:2017-10-22 17:21:07

标签: c# c++ struct pinvoke marshalling

我已声明struct如下:

// C++
struct TestStruct
{
    wchar_t* TestString;
};

和相应的托管代表

// C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TestStruct
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public string TestString;
}

以及此功能:

// 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;
    }
}

FillMultipleStructs方法调用,它需要多个TestStructs并在C ++代码中初始化它们。

// 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;
}

调用代码的方式如下:

FillMultipleStructs(
    new List<TestStruct>()
    {
        new TestStruct(),
        new TestStruct(),
        new TestStruct()                       
    });

现在,问题是:有时,代码有效,但有时我会收到a heap has been corrupted错误。我不明白它来自哪里,也不知道它为什么偶尔起作用,有时它不起作用。

我想这与struct的字符串成员的编组有关,所以,如果有人能告诉我我的错误在哪里,或者是否有人可以指出我正确的方向或显示我是正确的方法,我很乐意欣赏。

1 个答案:

答案 0 :(得分:0)

对于遇到同样问题而遇到这个问题的人来说,总结pstrjds在评论中已经说过的内容:

  

作为var allMenuItems = fileMaintenanceToolStripMenuItem.Descendants(); 编组,然后代替BSTR来电,   创建CoTaskMemAlloc个对象

实际上意味着从

更改BSTR C#的定义
struct

[MarshalAs(UnmanagedType.LPWStr)]
public string TestString;

而不是使用[MarshalAs(UnmanagedType.BStr)] public string TestString; ::CoTaskMemAlloc中分配字符串,而是需要使用C++

我无需更改::SysAllocString C++的签名,因为struct(在我的情况下)最终为BSTR typedef }。