В C ++ мы знаем, что все члены UNION совместно используют один и тот же кусок памяти и могут одновременно иметь только один член объекта.
Чтобы реализовать это в C #, нам нужно использовать LayoutKind to Explicit и установить всю начальную точку каждого члена равной 0.
В моем предыдущем примере отображается сообщение об ошибке, указывающее, что смещение типа объекта неправильно выровнено или перекрыто необъектным типом.
Ответ: мы не можем установить для всех членов значение FieldOffSet, равное 0, поскольку не допускается объединение ссылочного типа с типом значения.
- Благодаря объяснению Ганса Пассанта
Я создал копию структуры-члена UNION и изменил тип всех строковых переменных-членов на байты.
Я использовал байты, так как это тип значения, поэтому я могу поместить эту структуру в FieldOffSet (0).
Обратите внимание, я настраиваю FieldOffSet следующей переменной-члена, чтобы я мог получить тот же размер моей строковой переменной.
А также для размера структуры, так как у меня есть последний член байта.
Спасибо Akash Kava и Mario The Spoon за идею и полезную ссылку.
После вызова функции в DLL и передачи этого Struct Obj (ref m_objMsg) в качестве параметра, мне нужно извлечь значения.
Один из способов - получить указатель, который указывает на адрес структуры в неуправляемой памяти, и преобразовать этот указатель в новый
Структура с соответствующими переменными-членами (мои оригинальные структуры).
NEW STRUCTS (BYTES)
////////////////////////////////////////////////////////////////
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 31)]
public struct ConxReq
{
[FieldOffSet(0)]
public byteSubsId;
[FieldOffSet(15)]
public Int32 Level;
[FieldOffSet(19)]
public byte Options;
}
[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct ConxNack
{
[FieldOffSet(0)]
public int nReason;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 25)]
public struct StartReq
{
[FieldOffSet(0)]
public byte MsgId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
protected struct Msg
{
public int Length;
public Int16 Type;
public Data MsgData;
}
StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Data
{
[FieldOffset(0)]
public ConxReq oConxReq;
[FieldOffset(0)]
public ConxNack oConxNack;
[FieldOffset(0)]
public StartReq oStartReq;
}
////////////////////////////////////////////////////////////////
MY ORIGINAL STRUCTS
////////////////////////////////////////////////////////////////
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyConxReq
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
public string SubsId;
public Int32 Level;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
public string Options;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyStartReq
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
public string MsgId;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyConxNack
{
public int nReason;
}
///////////////////////////////////////////////////////////////
Since I have a Msg.Type, i know what kind of struct (type) I could cast the object.
Like for example
ReceiveMessage(m_Session, nTimeOut, ref oMsg);
switch (oMsg.Type)
{
case 0: // ConxReq
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(oMsg.MsgData.ConxReq); // use the new struct (bytes)
Marshal.StructureToPtr(oMsg.MsgData.ConxReq, ptr, false);
MyConxReq oMyConxReq = new MyConxReq;
oMyConxReq = (MyConxReq) Marshal.PtrToStructure(ptr, typeof(MyConxReq)); // convert it to the original struct
Marshal.FreeHGlobal(ptr);
Then you can use now the oMyConxReq object to acccess the member variables directly.
Пожалуйста, дайте мне знать, если у вас есть другой или лучший способ сделать это ...
Пожалуйста, посоветуйте, если то, что я сделал, правильно или я что-то пропустил.
Спасибо большое !!! :)