[英]How to union struct of struct with marshal.sizeof c#/c++
The Problem is that I'm trying to use c++ structure in my c# programm.问题是我试图在我的 c# 程序中使用 c++ 结构。
We are using Mail slots to communicate with a user interface and there is no other way to do this because of the complexity and age and it is running on over 1000 machines all around the world.我们正在使用邮件插槽与用户界面进行通信,由于其复杂性和年龄,没有其他方法可以做到这一点,并且它在世界各地的 1000 多台机器上运行。
Our structure looks like this我们的结构看起来像这样
// 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;
In c# all the sizes are fixed by these values.在 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;
Now the problem is not with the header or the body, that was pretty simple to manage.现在问题不在于标题或正文,这很容易管理。 The problem is with the union.
问题出在工会上。
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
};
Now here comes the problem.现在问题来了。 The Union.
工会。 With the Fieldoffset I can stick both the byte array and the struckt that have the same size into the same location.
使用 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;
};
While defining it this way I get an ArgumentException at CalculateChecksum().在以这种方式定义它时,我在CalculateChecksum() 处得到了一个ArgumentException。 I declare my struct with new and i only use SInternalProcess like seen here.
我用 new 声明我的结构,我只使用 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();
}
In CalculateChecksum() i'll get ArgumentException{"Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout."}在CalculateChecksum() 中,我会得到ArgumentException{“无法封送类型,因为嵌入的数组实例的长度与布局中声明的长度不匹配。”}
which you can see at the image here.您可以在此处的图像中看到。
//This is the part where there would have been a picture but i don't have enough reputation.
//这是有图片但我没有足够声誉的部分。 So I have to write it down.
所以我必须把它写下来。 :-( i'll post it asap my repu is up to 10.
:-(我会尽快发布我的repu高达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 and *messageData.parameter.strInternalProcess.data -> 0x00cc1bfc
*messageData.parameter.data -> 0x00cc1bfc 和 *messageData.parameter.strInternalProcess.data -> 0x00cc1bfc
both data array's are pointing to the same position, which is wrong there should be at least a 2byte offset because of the ushort command.两个数据数组都指向相同的位置,这是错误的,因为 ushort 命令,应该至少有 2 字节的偏移量。
My byte[] byteArray is 4204我的 byte[] byteArray 是 4204
So after reading a lot more and trying to figure it out myself I found 2 possible solutions.因此,在阅读了更多内容并试图自己弄清楚之后,我找到了 2 个可能的解决方案。 But each solution has a problem i can't solve by my self.
但是每个解决方案都有一个我自己无法解决的问题。
First of all am i doing something wrong in all the things i have done up to now, or is there a simple solution to the code i have posted.首先,我是否在到目前为止所做的所有事情中都做错了什么,或者我发布的代码是否有一个简单的解决方案。
So now i'll get to the possible solutions that i have thought of but i will post them separately below this post.所以现在我将讨论我想到的可能的解决方案,但我会在这篇文章下面单独发布它们。
Thanks for all your help.感谢你的帮助。 I appreciated every answer because i am stuck at this point for over a week now and don't know anything else to try.
我很感激每一个答案,因为我在这一点上被困了一个多星期,不知道还有什么可以尝试的。
Possible solution for the Problem mith a new problem that i can't fix myself.问题的可能解决方案是一个我无法解决的新问题。
I changed the definition of:我改变了以下定义:
public byte[] data;
to look as followed
public fixed byte data[PACKET_DATA_SIZE];
Here you can see the whole changes在这里你可以看到整个变化
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
This fixes the problem that i have with both data array's pointing at the same location.这解决了我的两个数据数组都指向同一位置的问题。 As you can see in the Picture.
正如你在图片中看到的。 But it creates an new problem.
但它产生了一个新问题。
Type 'GettingStartedClient.MailslotData+SMessageData' cannot
be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
So I played with the settings for the [MarshalAs(UnmanagedType. but i could not find a configuration that would work fine.所以我使用了 [MarshalAs(UnmanagedType.) 的设置。但我找不到可以正常工作的配置。
I tested all settings with a subset from my structure Marshal.SizeOf(messageData.parameter.data)我使用结构 Marshal.SizeOf(messageData.parameter.data) 中的一个子集测试了所有设置
So here is my problem that i would need some help with.所以这是我的问题,我需要一些帮助。
Type 'GettingStartedClient.MailslotData+SMessageData' cannot be marshaled as an unmanaged structure;
类型“GettingStartedClient.MailslotData+SMessageData”不能作为非托管结构进行封送; no meaningful size or offset can be computed.
无法计算出有意义的大小或偏移量。
So I played with the settings for the [MarshalAs(UnmanagedType. but i could not find a configuration that would work fine.
所以我使用了 [MarshalAs(UnmanagedType.) 的设置。但我找不到可以正常工作的配置。
Now i know why.现在我知道为什么了。 So to understand the background makes it all clear.
因此,了解背景使一切变得清晰。 I was trying to mashal a fixed array.
我试图混搭一个固定数组。 What mashel does is to rearrange the structure to look like you have decided it to look.
mashel 所做的是重新排列结构,使其看起来像您决定的样子。 which the mashal command can't do with a fixed array.
mashal 命令无法使用固定数组执行此操作。
So the solution was pretty easy.所以解决方案非常简单。 Remove the mashaling and voilà.
去除糖化和voilà。 It all works fine.
一切正常。
[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];
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.