2011-07-22 51 views
1

我测试了堆栈溢出问题代码Marshaling unmanaged char** to managed string[],它运行良好。Unicode字符串和FreeHGlobal问题?

我试图将它转换为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 = "[email protected]@[email protected]", 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

如果你没有使用过wcsncpy(),你很幸运能够获得Windows堆管理器来捕获错误,你必须使用Vista或Windows 7。问题是,您为字符串分配了maxLen 字节。但是您需要分配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就介入了。

0

您传递一个IntPtr阵列和直接在本地功能改性它(把它当作指针到指针) 。由于IntPtr来自managed world,因此直接修改已损坏它 - 因此该句柄无效。

+0

那么,它适用于ANSI版本。如果直接修改会导致腐败,如何重写代码以传递字符串之间的动态数组? – Assaf