Unicode字符串和FreeHGlobal问题?

时间:2011-07-22 13:40:34

标签: c# c++ exception dll interop

我测试了Stack Overflow问题 Marshaling unmanaged char** to managed string[] 中的代码,效果很好。

我试图将其转换为Unicode,然后我开始得到“句柄无效”。为什么呢?

我修改过的代码:

_declspec(dllexport) void TestArray(wchar_t** OutBuff, int Count, int MaxLength)
{
    for(int i=0; i<Count; i++)
    {
        wchar_t buff[25];
        _itow(i, buff, 10);
        wcsncpy(OutBuff[i], buff, MaxLength);
    }
}

和C#包装器:

class Program
{
    [DllImport("Native.dll", EntryPoint = "?TestArray@@YAXPAPA_WHH@Z", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern void TestArray([MarshalAs(UnmanagedType.LPArray)]
    IntPtr[] OutBuff, int Count, int MaxLength);

    static void Main(string[] args)
    {
        int count = 10;
        int maxLen = 50;
        IntPtr[] buffer = new IntPtr[maxLen];
        for (int i = 0; i < count; i++)
            buffer[i] = Marshal.AllocHGlobal(maxLen);

        TestArray(buffer, count, maxLen);

        string[] output = new string[count];
        for (int i = 0; i < count; i++)
        {
            output[i] = Marshal.PtrToStringUni(buffer[i]);
            Marshal.FreeHGlobal(buffer[i]); // Crash is here, when count is 1.
            Console.WriteLine(output[i]);
        }
        Console.ReadKey();
    }
}

2 个答案:

答案 0 :(得分:2)

您很幸运能够让Windows堆管理器捕获该错误,您必须使用Vista或Windows 7.这是一个微妙的,如果您没有使用wcsncpy(),很容易错过。问题是您为字符串分配了maxLen bytes 。但是你需要分配maxLen 字符。使用Unicode字符串时,不一样,一个字符是两个字节。你也得到了错误的缓冲区分配。修正:

        IntPtr[] buffer = new IntPtr[count];   // NOTE: not maxLen
        for (int i = 0; i < count; i++) 
            buffer[i] = Marshal.AllocHGlobal(maxLen * sizeof(Char)); 

由于wcsncpy()的工作方式,会发生堆损坏。如果用wcscpy_s()填充缓冲区的剩余部分,则为零。由于缓冲区太小,会覆盖并破坏堆。当Windows注意到内部堆结构受到损害时,Windows介入。

答案 1 :(得分:0)

您传递了IntPtr数组并直接在本机函数中对其进行了修改(将其视为指向指针的指针)。由于IntPtr来自managed world,因此直接修改已损坏它 - 因此句柄无效。