我测试了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();
}
}
答案 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,因此直接修改已损坏它 - 因此句柄无效。