I tested the code from Stack Overflow question Marshaling unmanaged char** to managed string[], and it works well.
I tried to convert it to Unicode, and then I start getting “The handle is invalid”. Why?
My modified code:
_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);
}
}
And the C# wrapper:
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();
}
}
You are lucky to get the Windows heap manager to catch the bug, you must be using Vista or Windows 7. It is a subtle one and would have been easily missed if you hadn’t used wcsncpy(). The problem is that you allocated maxLen bytes for the string. But you need to allocate maxLen characters. Not the same thing when you use Unicode strings, one character is two bytes. You also got the buffer allocation wrong. Fix:
The heap corruption occurs because of the way wcsncpy() works. If fills the remainder of the buffer with zeros, unlike wcscpy_s(). Since your buffer is too small, that overwrites and corrupts the heap. Windows stepped in when it noticed that the internal heap structure was compromised.