BUG: StringBuilder Field in a Structure Cannot Be Marshaled Properly (327109)



The information in this article applies to:

  • Microsoft .NET Framework 1.0
  • Microsoft Windows .NET Framework 1.1

This article was previously published under Q327109

SYMPTOMS

If you marshal a structure that contains a StringBuilder field to an unmanaged function, the StringBuilder field is not marshaled correctly.

RESOLUTION

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);
    					

STATUS

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.

Modification Type:MinorLast Reviewed:5/28/2003
Keywords:kbbug kbCOMInterop kbnofix KB327109