Consider the following struct to be sent over TCP to an unmanaged dll
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct FooMessage
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
public string foo;
//More fields...
}
Using the following function (credit to Cheeso):
public byte[] RawSerialize( T item )
{
int rawSize = Marshal.SizeOf( typeof(T) );
IntPtr buffer = Marshal.AllocHGlobal( rawSize );
Marshal.StructureToPtr( item, buffer, false );
byte[] rawData = new byte[ rawSize ];
Marshal.Copy( buffer, rawData, 0, rawSize );
Marshal.FreeHGlobal( buffer );
return rawData;
}
Problem: The marshaller assumes foo is a null terminated string, whereas the unmanaged dll does not - and actually uses the last char (which always comes out null from the marshaller).
Any ideas ?
Clarification: I can't just change the SizeConst to 43, because I need to maintain the total size of the message, as well as the position of the next fields in the struct (according to an existing ICD)
Since no other answer has been posted, here is the workaround I've found
Also a similar solution by TCP expert Stephen Cleary
You have two, and only two, choices:
One or the other, take your pick.
-- b
You could use StructLayout(LayoutKind.Explicit ...) and tag each field with [FieldOffset(n)]. This will allow you to increase the SizeConst value to 43, and still mark the next field as starting at offset 42. The marshaller will marshal the 42 character string and ignore the 43rd byte appending a null-terminator instead.