BUG: StringBuilder Field in a Structure Cannot Be Marshaled Properly

This article has been archived. It is offered "as is" and will no longer be updated.
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 endMyStrStruct 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.
More information
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: 01/17/2015 05:55:19 - Revision: 3.0

Microsoft .NET Framework 1.0, Microsoft .NET Framework 1.1

  • kbnosurvey kbarchive kbbug kbcominterop kbnofix KB327109