If you marshal a structure that contains a
StringBuilder field to an unmanaged function, the
StringBuilder field is not marshaled correctly.
If you must initialize a buffer to some value before you
pass to an unmanaged function, use one of the following workarounds:
- Use the StringBuilder class, and apply to ANSI and Unicode strings. For example:
StringBuilder buffer = new StringBuilder("content", 100);
buffer.Append((char)0);
buffer.Append('*', buffer.Capacity - 8); //add anything to the end
MyStrStruct mss;
mss.buffer = buffer.ToString();
mss.size = mss.buffer.Length;
Win32.TestStringInStruct(ref mss); // call unmanaged function
- Use the Marshal class, and apply only to Unicode strings. For example:
IntPtr pMem = Marshal.AllocCoTaskMem(100);
String inString = "content";
Marshal.Copy(inString.ToCharArray(), 0, pMem, inString.Length);
MyStrStruct mss;
mss.buffer = pMem;
mss.size = 100;
Win32.TestStringInStruct(ref mss); // call unmanaged function
String outString = Marshal.PtrToStringAuto(mss.buffer);
Marshal.FreeCoTaskMem(pMem);
Microsoft has confirmed that this is a bug in the Microsoft
products that are listed at the beginning of this article.
To reproduce this problem, use the following code:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Test
{
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public Int32 cb;
public StringBuilder lpReserved;
public StringBuilder lpDesktop;
public StringBuilder lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
/*
Original unmanaged structure:
typedef struct _STARTUPINFO
{
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
*/
class TestAPI
{
[DllImport("kernel32.dll")]
public static extern void GetStartupInfo(ref STARTUPINFO lpStartupInfo);
[STAThread]
static void Main(string[] args)
{
STARTUPINFO startinfo = new STARTUPINFO();
startinfo.lpReserved = new StringBuilder(256);
startinfo.lpDesktop = new StringBuilder(256);
startinfo.lpTitle = new StringBuilder(256);
GetStartupInfo(ref startinfo);
}
}
}
If you compile and run this code, you receive a
System.TypeLoadException exception, which contains the following information:
Marshaler restriction: StringBuilders can not be used in
structure fields. The same effect can usually be achieved by using a String
field and preinitializing it to a string with length matching the length of the
appropriate buffer.
Article ID: 327109 - Last Review: February 23, 2007 - Revision: 2.6
APPLIES TO
- Microsoft .NET Framework 1.0
- Microsoft .NET Framework 1.1
| kbbug kbcominterop kbnofix KB327109 |