Как объединить структуру struct с marshal.sizeof c # / Переполнение стека

Проблема в том, что я пытаюсь использовать структуру c ++ в моей программе на c #.

Мы используем почтовые слоты для связи с пользовательским интерфейсом, и нет другого способа сделать это из-за сложности и возраста, и он работает на более чем 1000 компьютерах по всему миру.

Наша структура выглядит так

// Message data
typedef struct _t_messageData
{
t_messageHeader header;
t_messageBody body;
t_messageParameter parameter;
} t_messageData;

typedef struct _t_messageHeader
{
UCHAR  stx;
UCHAR  packetType;
USHORT packetCount;
USHORT checksum;
UCHAR  sourceAddress;
USHORT sourcePID;
UCHAR  destinationAddress;
USHORT destinationPID;
UCHAR  destinationNet;
USHORT packetSequenceNumber;
USHORT packetID;
} t_messageHeader;

// Message body
typedef struct _t_messageBody
{
char    order[4];
USHORT  module;
USHORT  station;
USHORT  part;
USHORT  position;
} t_messageBody;

// Message parameter
typedef union _t_messageParameter
{
t_internalProcessData internalProcess;
char data[PACKET_DATA_SIZE];
} t_messageParameter;typedef struct _t_internalProcessData
{
USHORT command;
UCHAR data[PACKET_DATA_SIZE-2];
} t_internalProcessData;

В c # все размеры фиксируются этими значениями.

public const int PACKET_HEADER_SIZE = 17;
public const int PACKET_BODY_SIZE = 12;
public const int PACKET_COMPLETE_SIZE = 4204;
public const int PACKET_DATA_SIZE = PACKET_DATA_SIZE = 4175;

Теперь проблема не с заголовком или телом, которым было довольно просто управлять.
Проблема в союзе.

class MailslotData
{
// Message header
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct SMessageHeader
{
public byte stx;
public byte packetType;
public ushort packetCount;
public ushort checksum;
public byte sourceAddress;
public ushort sourcePID;
public byte destinationAddress;
public ushort destinationPID;
public byte destinationNet;
public ushort packetSequenceNumber;
public ushort packetID;
};

// Message body
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct SMessageBody
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public char[] order;
public ushort placeHolder1;     // Old ModuleNbr
public ushort station;
public ushort part;
public ushort placeHolder2;     // Old PositionNbr
};

Теперь здесь возникает проблема. Союз.
С помощью Fieldoffset я могу вставить байтовый массив и ударник, которые имеют одинаковый размер, в одно и то же место.

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct SMessageParameter
{
[FieldOffset(0)]
public SInternalProcessData strInternalProcess;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = PACKET_DATA_SIZE)]
public byte[] data;
};

Определяя его таким образом, я получаю ArgumentException в CalculateChecksum ().
Я объявляю свою структуру с новым, и я использую только SInternalProcess, как показано здесь.

public void CreateInternalProcessMessage(ushort station, ushort part, ushort command)
{
CreateMessageHeader(PACKETTYPE_SINGLE_PACKET, ADDRESS_USERINT, PID_USERINT, DESTINATIONNET_USERINT, 0);

CreateMessageBody (INTERNAL_PROCESS_MESSAGE.ToCharArray(), station, part);

messageData.parameter.strInternalProcess.command = command;
messageData.header.packetCount += (ushort)Marshal.SizeOf (messageData.parameter.strInternalProcess.command);

messageData.parameter.strInternalProcess.data = new byte[PACKET_DATA_SIZE - 2];

messageData.parameter.strInternalProcess.data[0] = (byte)ETX;
messageData.header.packetCount += 1;
CalculateChecksum();
}

В CalculateChecksum () я получу ArgumentException {«Тип не может быть маршалирован, потому что длина экземпляра встроенного массива не соответствует объявленной длине в макете.»}

который вы можете увидеть на изображении здесь.

// Это та часть, где была бы фотография, но мне не хватает репутации.
Поэтому я должен записать это. 🙁 Я опубликую это как можно скорее, мой репу до 10.
введите описание изображения здесь

unsafe void CalculateChecksum()
{
int i = 0;
ushort checksum = 0;
i = Marshal.SizeOf(messageData);
i = sizeof(ushort);

byte[] byteArray = new byte[Marshal.SizeOf(messageData)];fixed (byte* pArray = byteArray)Marshal.StructureToPtr(messageData, new IntPtr (pArray), false);

// Calculate the checksum
messageData.header.checksum = 0;
for (byte u = 0; u < messageData.header.packetCount; u++)
checksum += byteArray[u];

messageData.header.checksum = checksum;
}

* messageData.parameter.data -> 0x00cc1bfc
а также
* messageData.parameter.strInternalProcess.data -> 0x00cc1bfc

оба массива данных указывают на одну и ту же позицию, что является неправильным, поскольку из-за команды ushort должно быть как минимум смещение в 2 байта.

Мой байт [] byteArray 4204

Поэтому, прочитав намного больше и попытавшись понять это самостоятельно, я нашел 2 возможных решения.
Но у каждого решения есть проблема, которую я не могу решить самостоятельно.

Прежде всего, я делаю что-то не так во всех вещах, которые я делал до сих пор, или есть простое решение для кода, который я разместил.

Так что теперь я доберусь до возможных решений, о которых я думал, но я опубликую их отдельно ниже этого поста.

Спасибо за вашу помощь. Я оценил каждый ответ, потому что я застрял в этой точке больше недели и не знаю ничего другого, чтобы попробовать.

-2

Решение

Возможное решение проблемы с новой проблемой, которую я не могу решить самостоятельно.

Я изменил определение:

    public byte[] data;
to look as followed
public fixed byte data[PACKET_DATA_SIZE];

Здесь вы можете увидеть все изменения

public unsafe struct SInternalProcessData
{
public ushort command;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = PACKET_DATA_SIZE - 2)]
public fixed byte data[PACKET_DATA_SIZE - 2];
};

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public unsafe struct SMessageParameter
{
[FieldOffset(0)]
public SInternalProcessData strInternalProcess;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = PACKET_DATA_SIZE)]
public fixed byte data[PACKET_DATA_SIZE];
};public const int PACKET_HEADER_SIZE = 17;
public const int PACKET_BODY_SIZE = 12;
public const int PACKET_COMPLETE_SIZE = 4204;
public const int PACKET_DATA_SIZE = PACKET_COMPLETE_SIZE - PACKET_HEADER_SIZE - PACKET_BODY_SIZE;
//value PACKET_DATA_SIZE = 4175

Это устраняет проблему с указанием обоих массивов данных в одном месте.
Как вы можете видеть на картинке. Но это создает новую проблему.

ArgumentException

Type 'GettingStartedClient.MailslotData+SMessageData' cannot
be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

Поэтому я поиграл с настройками для [MarshalAs (UnmanagedType.), Но не смог найти конфигурацию, которая бы работала нормально.

Я проверил все настройки с подмножеством из моей структуры
Marshal.SizeOf (messageData.parameter.data)

Итак, вот моя проблема, с которой мне нужна помощь.

0

Другие решения

Тип «GettingStartedClient.MailslotData + SMessageData» не может быть
маршалинг как неуправляемая структура; нет значимого размера или смещения
быть вычисленным.

Так что я играл с настройками для [MarshalAs (UnmanagedType. Но я
не удалось найти конфигурацию, которая бы работала нормально.

Теперь я знаю почему.
Таким образом, чтобы понять фон, все понятно.
Я пытался помешать фиксированному массиву. Что делает машель, так это переставляет структуру так, как вы решили. что команда mashal не может сделать с фиксированным массивом.

Так что решение было довольно простым. Удалите mashaling и вуаля. Все отлично работает.

[StructLayout(LayoutKind.Explicit, Size = PACKET_DATA_SIZE, Pack = 1)]
public unsafe struct SInternalProcessData
{
[FieldOffset(0)]
public ushort command;
[FieldOffset(1)]
public fixed byte data[PACKET_DATA_SIZE - 2];
};

[StructLayout(LayoutKind.Explicit, Size = PACKET_DATA_SIZE, Pack = 1)]
public unsafe struct SMessageParameter
{
[FieldOffset(0)]
public SInternalProcessData strInternalProcess;
[FieldOffset(0)]
public fixed byte data[PACKET_DATA_SIZE];
};
0

По вопросам рекламы [email protected]