I am trying to serialize the following c# structure:
[Serializable]
[StructLayout(LayoutKind.Sequential, Size = 70, CharSet = CharSet.Ansi)]
public struct USSDContinueModel
{
[MarshalAs(UnmanagedType.U4)]
public uint Command_Length;
[MarshalAs(UnmanagedType.U4)]
public uint Command_ID;
[MarshalAs(UnmanagedType.U4)]
public uint Command_Status;
[MarshalAs(UnmanagedType.U4)]
public uint Sender_ID;
[MarshalAs(UnmanagedType.U4)]
public uint Receiver_ID;
[MarshalAs(UnmanagedType.U1)]
public uint Ussd_Version;
[MarshalAs(UnmanagedType.U1)]
public uint Ussd_Op_Type;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string MsIsdn;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string Service_Code;
[MarshalAs(UnmanagedType.U1)]
public uint Code_Scheme;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 182)]
public string Ussd_Content;
// Calling this method will return a byte array with the contents
// of the struct ready to be sent via the tcp socket.
public byte[] Serialize()
{
// allocate a byte array for the struct data
var buffer = new byte[Marshal.SizeOf(typeof(USSDContinueModel))];
// Allocate a GCHandle and get the array pointer
var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var pBuffer = gch.AddrOfPinnedObject();
// copy data from struct to array and unpin the gc pointer
Marshal.StructureToPtr(this, pBuffer, false);
gch.Free();
return buffer;
}
// this method will deserialize a byte array into the struct.
public void Deserialize(ref byte[] data)
{
var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
this = (USSDContinueModel)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(USSDContinueModel));
gch.Free();
}
}
when i try to serialize an instance of the structure say:
public USSDContinueModel continueModel;
continueModel.Command_Length = 174;
continueModel.Command_ID = 0x00000070;
continueModel.Command_Status = 0;
continueModel.Sender_ID = 0x01000005;
continueModel.Receiver_ID = 0x2900AB12;
continueModel.Ussd_Version = 0x20;
continueModel.Ussd_Op_Type = 0x01;
continueModel.MsIsdn = "08098765476";
continueModel.Service_Code = "*308";
continueModel.Code_Scheme = 0x44;
continueModel.Ussd_Content = "1. Continue if you are 18+ 2. Exit i";
I keep getting the error "Type: USSDcontinueModel cannot be marshalled as an unmanaged structure; no meaningful size or offset can be computed".
I noticed this happens when i set the Ussd_Version, Ussd_Op_Type and Code_Scheme as [MarshalAs(UnmanagedType.U1)] but it works fine with [MarshalAs(UnmanagedType.U4)].
Is [MarshalAs(UnmanagedType.U1)] unmarshallable? what do i do?
The problem is that the definition:
[MarshalAs(UnmanagedType.U1)]
public uint Ussd_Op_Type;
is ambiguous as to what size the members could be. If the interop marshal uses the member's size, it will calculate 4 bytes, whereas if it uses the MarshalAs
attribute it will calculate 1 byte. Changing the member to use the correct size type,
[MarshalAs(UnmanagedType.U1)]
public byte Ussd_Op_Type;
should fix the issue.
So after taking @theB's recommendation of declaring the U1 data types as bytes. The problem was resolved. The updated structure definition follows:
[Serializable]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack=1)]
public struct USSDContinueModel
{
[MarshalAs(UnmanagedType.U4)]
public uint Command_Length;
[MarshalAs(UnmanagedType.U4)]
public uint Command_ID;
[MarshalAs(UnmanagedType.U4)]
public uint Command_Status;
[MarshalAs(UnmanagedType.U4)]
public uint Sender_ID;
[MarshalAs(UnmanagedType.U4)]
public uint Receiver_ID;
[MarshalAs(UnmanagedType.U1)]
public byte Ussd_Version;
[MarshalAs(UnmanagedType.U1)]
public byte Ussd_Op_Type;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string MsIsdn;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string Service_Code;
[MarshalAs(UnmanagedType.U1)]
public byte Code_Scheme;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 182)]
public string Ussd_Content;
// Calling this method will return a byte array with the contents
// of the struct ready to be sent via the tcp socket.
public byte[] Serialize()
{
// allocate a byte array for the struct data
var buffer = new byte[Marshal.SizeOf(typeof(USSDContinueModel))];
// Allocate a GCHandle and get the array pointer
var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var pBuffer = gch.AddrOfPinnedObject();
// copy data from struct to array and unpin the gc pointer
Marshal.StructureToPtr(this, pBuffer, false);
gch.Free();
return buffer;
}
// this method will deserialize a byte array into the struct.
public void Deserialize(ref byte[] data)
{
var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
this = (USSDContinueModel)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(USSDContinueModel));
gch.Free();
}
}
User contributions licensed under CC BY-SA 3.0