C# Convert an Ascii byte array to struct (i.e. with Marshal) - c#

i have a byte array that is sent through sockets. The byte array is a ascii string.
var bytes = Encoding.ASCII.GetBytes("00000250Q+0000SPS_22MFR ");
How can i convert/marshal this byte array into a struct?
internal struct Header
{
public ulong Size;
public string Type;
public ushort Sequence;
public ushort ErrorCode;
public string Sender;
public string Receiver;
}
I already tried it with StructLayout and MarshalAs, but i get either an exception or a very different input/output.
[StructLayout(LayoutKind.Sequential, Size = 26, CharSet = CharSet.Ansi)]
internal struct SitTelegramHeader
{
public ulong Size;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)] public string Type;
public ushort Sequence;
public ushort ErrorCode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)] public string Sender;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)] public string Receiver;
}
Is there any way to do this with Marshal/BinaryFormatter/etc. or do i have to convert it by hand?
Thx for help.

Related

Error in converting c++ union structure to c#

i have some complex structure in c++
typedef struct
{
long Length;
short Type;
union
{
MMTPConxReq ConxReq;
MMTPConxAck ConxAck;
MMTPConxNack ConxNack;
MMTPErrInd ErrInd;
MMTPDcnxReq DcnxReq;
MMTPDcnxAck DcnxAck;
MMTPDataMsg DataMsg;
MMTPSyncAck SyncAck;
MMTPStartReq StartReq;
MMTPStartAck StartAck;
MMTPStartNack StartNack;
MMTPSrvcMsg SrvcMsg;
MMTPDsptchMsg DsptchMsg;
MMTPRcnxReq RcnxReq;
} Data;
Ticks TimeStamp;
} MMTPMsg;
typedef struct
{
char SubsId[FIELD_SIZE_SUBS_ID+1];
int Level;
char Options[FIELD_SIZE_OPTIONS+1];
char AuthData[FIELD_SIZE_AUTH_DATA+1];
} MMTPConxReq;
// Contents of CONX-ACK message.
typedef struct
{
char Options[FIELD_SIZE_OPTIONS+1];
} MMTPConxAck;
// Contents of DATA-MSG message.
typedef struct
{
int SeqNb;
int DataSize;
MMTPAdminData AD;
char Data[FIELD_SIZE_DATA+1];
} MMTPDataMsg;
// Administrative data.
typedef struct
{
int Type;
int Size;
union
{
MMTPAdminDataA1 A1;
MMTPAdminDataA2 A2;
MMTPAdminDataE0 E0;
MMTPAdminDataE1 E1;
MMTPAdminDataG0 G0;
MMTPAdminDataM0 M0;
MMTPAdminDataRR RR;
MMTPAdminGeneric Generic;
} Data;
char Unknown[FIELD_SIZE_ADMIN];
} MMTPAdminData;
in conver to c# (step to step) i create this structs:
[StructLayout(LayoutKind.Sequential)]
internal struct MMTPMsg
{
public Int32 Length;
public MessageType Type;
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10060)]
//public fixed byte Data[10060];
public MMTPMsgData Data;
public Int64 TimeStamp;
}
[StructLayout(LayoutKind.Explicit)]//,Size =10060)]
internal struct MMTPMsgData
{
[FieldOffset(0)]
public MMTPConxReq ConxReq;//12+4+17+9
[FieldOffset(0)]
public MMTPConxAck ConxAck;//17
//[FieldOffset(0)]
//public MMTPConxNack ConxNack;//e
//[FieldOffset(0)]
//public MMTPErrInd ErrInd;//e+4+4+4+(9500+256+24+1)
//[FieldOffset(0)]
//public MMTPDcnxReq DcnxReq;//e+4
//[FieldOffset(0)]
//public MMTPDcnxAck DcnxAck;//4
[FieldOffset(0)]
public MMTPDataMsg DataMsg;//4+4+(4+4+()+256)+9501
//[FieldOffset(0)]
//public MMTPSyncAck SyncAck;
//[FieldOffset(0)]
//public MMTPStartReq StartReq;
[FieldOffset(0)]
public MMTPStartAck StartAck;
//[FieldOffset(0)]
//public MMTPStartNack StartNack;
//[FieldOffset(0)]
//public MMTPSrvcMsg SrvcMsg;
//[FieldOffset(0)]
//public MMTPDsptchMsg DsptchMsg;
//[FieldOffset(0)]
//public MMTPRcnxReq RcnxReq;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]//, CharSet = CharSet.Ansi)]
unsafe internal struct MMTPConxReq
{
public fixed byte SubsId[Constants.FIELD_SIZE_SUBS_ID + 1];
public int Level;
public fixed byte Options[Constants.FIELD_SIZE_OPTIONS + 1];
public fixed byte AuthData[Constants.FIELD_SIZE_AUTH_DATA + 1];
}
internal struct MMTPConxAck
{
//[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.FIELD_SIZE_OPTIONS + 1)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.FIELD_SIZE_OPTIONS + 1)]
public string Options;//[Constants.FIELD_SIZE_OPTIONS + 1];
}
internal struct MMTPDataMsg
{
public int SeqNb;
public int DataSize;
public MMTPAdminData AD;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = Constants.FIELD_SIZE_DATA + 1)]
public byte[] Data;
}
when run the c# app, i get this error
System.TypeLoadException: 'Could not load type 'TestSle.MMTPMsgData' from assembly 'TestSle, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.'
if i comment
this line from MMTPMsgData struct:
[FieldOffset(0)]
public MMTPConxReq ConxReq;//12+4+17+9
no error happen but i need this data.
what is wrong
i can not understand problem
help me please

How to marshal wchar[]

I've found plenty of information about how to marshal wchar_t and wchar* on the internet, but right now I am trying to marshal the WINBIO_STRING type, which is defined as wchar[256]. Marshalling it as an array of char[] works, but then every other element in the array is \0, and I would like to avoid this. Is there a more proper way to marshal this data (which is a member of a struct, the WINBIO_UNIT_SCHEMA struct in particular). This is my code:
[StructLayout(LayoutKind.Sequential)]
public struct BiometricUnitSchema
{
public int UnitId;
public BiometricPoolType PoolType;
public BiometricType BiometricFactor;
public BiometricSubtype SensorSubType;
public BiometricCapabilities Capabilities;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public char[] DeviceInstanceId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public char[] Description;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public char[] Manufacturer;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public char[] Model;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public char[] SerialNumber;
public BiometricVersion FirmwareVersion;
}
I also have the problem of the FirmwareVersion field always containing MajorVersion and MinorVersion values of 0, but I am not sure if this result is incorrect or simply misleading.
I fixed this problem by marshaling WINBIO_STRING as a string in C# instead of a char[]. I also had to add a Unicode charset to my structure.
My new structure:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct BiometricUnitSchema
{
public int UnitId;
public BiometricPoolType PoolType;
public BiometricType BiometricFactor;
public BiometricSubtype SensorSubType;
public BiometricCapabilities Capabilities;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string DeviceInstanceId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Manufacturer;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Model;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string SerialNumber;
public BiometricVersion FirmwareVersion;
}

Convert the _WTSClient struct from C++ to C#

I have been trying to convert this struct to C# for the last couple of days, but to no avail...
https://msdn.microsoft.com/en-us/library/windows/desktop/bb736369(v=vs.85).aspx
typedef struct _WTSCLIENT {
TCHAR ClientName[CLIENTNAME_LENGTH + 1];
TCHAR Domain[DOMAIN_LENGTH + 1 ];
TCHAR UserName[USERNAME_LENGTH + 1];
TCHAR WorkDirectory[MAX_PATH + 1];
TCHAR InitialProgram[MAX_PATH + 1];
BYTE EncryptionLevel;
ULONG ClientAddressFamily;
USHORT ClientAddress[CLIENTADDRESS_LENGTH + 1];
USHORT HRes;
USHORT VRes;
USHORT ColorDepth;
TCHAR ClientDirectory[MAX_PATH + 1];
ULONG ClientBuildNumber;
ULONG ClientHardwareId;
USHORT ClientProductId;
USHORT OutBufCountHost;
USHORT OutBufCountClient;
USHORT OutBufLength;
TCHAR DeviceId[MAX_PATH + 1];
} WTSCLIENT, *PWTSCLIENT;
This is my attempt so far:
[StructLayout( LayoutKind.Sequential )]
public struct _WTSCLIENT {
[MarshalAs( UnmanagedType.LPTStr )]
public String ClientName;
[MarshalAs( UnmanagedType.LPTStr )]
public String Domain;
[MarshalAs( UnmanagedType.LPTStr )]
public String UserName;
[MarshalAs( UnmanagedType.LPTStr )]
public String WorkDirectory;
[MarshalAs( UnmanagedType.LPTStr )]
public String InitialProgram;
public Byte EncryptionLevel;
public uint ClientAddressFamily;
[MarshalAsAttribute( UnmanagedType.ByValArray)]
public byte[] ClientAddress;
public ushort HRes;
public ushort VRes;
public ushort ColorDepth;
[MarshalAs( UnmanagedType.LPTStr )]
public String ClientDirectory;
public uint ClientBuildNumber;
public uint ClientHardwareId;
public ushort ClientProductId;
public ushort OutBufCountHost;
public ushort OutBufCountClient;
public ushort OutBufLength;
[MarshalAs( UnmanagedType.LPTStr )]
public String DeviceId;
}
I use it like this:
WTSQuerySessionInformation( serverHandle, si.SessionID, WTS_INFO_CLASS.WTSClientInfo, out clientInfoPtr, out bytes );
clientInfo = (_WTSCLIENT)Marshal.PtrToStructure( clientInfoPtr, typeof( _WTSCLIENT ) );
...but it bombs out silently, so obviously I have not matched the structure...
Can anyone help me with the struct conversion to C#
TIA...
--
Dag.
Try
[StructLayout(LayoutKind.Sequential)]
public struct WTSCLIENT
{
private const int CLIENTNAME_LENGTH = 20;
private const int DOMAIN_LENGTH = 17;
private const int USERNAME_LENGTH = 20;
private const int MAX_PATH = 260;
private const int CLIENTADDRESS_LENGTH = 30;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CLIENTNAME_LENGTH + 1)]
public string ClientName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = DOMAIN_LENGTH + 1)]
public string Domain;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = USERNAME_LENGTH + 1)]
public string UserName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
public string WorkDirectory;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
public string InitialProgram;
public byte EncryptionLevel;
public uint ClientAddressFamily;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CLIENTADDRESS_LENGTH + 1)]
public ushort[] ClientAddress;
public ushort HRes;
public ushort VRes;
public ushort ColorDepth;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
public string ClientDirectory;
public uint ClientBuildNumber;
public uint ClientHardwareId;
public ushort ClientProductId;
public ushort OutBufCountHost;
public ushort OutBufCountClient;
public ushort OutBufLength;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
public string DeviceId;
}
It should work. Its Marshal.SizeOf is the "right" one, both at 32 and 64 bits, both Ansi and Unicode.
If you are using the Unicode version of the methods change the first line to:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
You could try the P/Invoke Interop Assistant
For your ULONG ClientBuildNumber; and all other ULONG s in C++, you have used the C# type uint. It could be an error that your definition of ULONG is a different size than uint.
Maybe you can try using ulong in C# (unsigned 64-bit, 0 to 18,446,744,073,709,551,615). This should match the standard Microsoft C++ ULONG definition.
MSDN C++
MSDN C# ulong

Another PInvoke - error message says source not found?

The struct that i have built in c# when run against the function does not give me one of the error message that tell me something is wrong with the struct. It says that a source file could not be found. Again, I don't know much about this DLL b/c of lack of documentation. But I am still thinking it is because I set the struct up wrong. Most likely i'm thinking the 3rd struct where it is referencing a struct within the struct.
i was hoping for some feedback on the work I did.
Thanks for the assistance.
This is what was provided in C:
int BatchTotal_Transactions(int transType, pTGiftCardReqBatchTotal req, pTGiftCardRespBatchTotal resp, int (*Com)(char *));
typedef struct _tagGiftCardReqBatchTotal
{
char Password[9];
char OperatorID[9];
char BatchNum[14];
char StartDate[11];
char EndDate[11];
unsigned char Type;
} TGiftCardReqBatchTotal, *pTGiftCardReqBatchTotal;
typedef struct _tagGiftCardRespBatchTotal
{
char Result;
char TerminalId[17];
unsigned char DispMsgControl;
char DispMsg[256];
char Display[41];
char Date[11];
char Time[9];
char RespCode[4];
char BatchNum[14];
char ErrorFlag;
char CustLang;
char UserLang;
char OpenDate[17];
char ClosedDate[17];
char StartDate[11];
char EndDate[11];
char BatchStatus;
int CardTypeNum;
TGiftCardTotals GctHost[MAX_CARD_CODES];
TGiftCardTotals GctTRS[MAX_CARD_CODES];
} TGiftCardRespBatchTotal, *pTGiftCardRespBatchTotal;
typedef struct _tagGiftCardTotals
{
unsigned short CardCode;
unsigned short PurchaseNum;
long PurchaseTotal;
unsigned short RefundNum;
long RefundTotal;
unsigned short RedemptionNum;
long RedemptionTotal;
unsigned short CorrectionNum;
long CorrectionTotal;
long PurchaseBenefitTotal;
long RefundBenefitTotal;
long RedemptionBenefitTotal;
} TGiftCardTotals, *pTGiftCardTotals;
And this is how I did it in C#:
[DllImport("batch.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern int BatchTotal_Transactions(int transType, ref giftCardReqBatchTotal req, ref giftCardRespBatchTotal resp, IntPtr com);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct _tagGiftCardReqBatchTotal
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string Password;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string OperatorID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string BatchNum;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string StartDate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string EndDate;
public byte Type;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct _tagGiftCardRespBatchTotal
{
public byte Result;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string TerminalId;
public byte DispMsgControl;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string DispMsg;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public string Display;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string Date;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string Time;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public string RespCode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string BatchNum;
public byte ErrorFlag;
public byte CustLang;
public byte UserLang;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string OpenDate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string ClosedDate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string StartDate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string EndDate;
public byte BatchStatus;
int CardTypeNum;
[MarshalAs(UnmanagedType.Struct, SizeConst = 1024)]
public _tagGiftCardTotals GctHost;
[MarshalAs(UnmanagedType.Struct, SizeConst = 1024)]
public _tagGiftCardTotals GctTRS;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct _tagGiftCardTotals
{
public UInt16 CardCode;
public UInt16 PurchaseNum;
public int PurchaseTotal;
public UInt16 RefundNum;
public int RefundTotal;
public UInt16 RedemptionNum;
public int RedemptionTotal;
public UInt16 CorrectionNum;
public int CorrectionTotal;
public int PurchaseBenefitTotal;
public int RefundBenefitTotal;
public int RedemptionBenefitTotal;
}
Are you sure the error isn't the following:
Specified module could not be found.
If this is the error then it is because the dll could not be found. Make sure the dll is in your path:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.value.aspx

Marshall array of structures

I've spent a lot of time to look for the solution but still don't find it out.
I have 2 classes:
[StructLayout(LayoutKind.Sequential)]
public class Result
{
public int Number;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public string Name;
public int Size;
}
[StructLayout(LayoutKind.Sequential)]
public class CoverObject
{
public int NumOfResults;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 4)]
public Result[] Results;
}
My expectation that the command Marshal.SizeOf(typeof(CoverObject)) will return 52, but not, it's just 20. Thus, all of marshall and unmarshall that I use later are not working.
Seeming it only counts the first member (Number) in Result class. Did I do anything wrong?
Change your classes to structs
[StructLayout(LayoutKind.Sequential)]
public struct Result
{
public int Number;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public string Name;
public int Size;
}
[StructLayout(LayoutKind.Sequential)]
public struct CoverObject
{
public int NumOfResults;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 4)]
public Result[] Results;
}
some where else:
Marshal.SizeOf(typeof(CoverObject)) // it will return 52

Categories