问题是我正在尝试在我的c#programm中使用c ++结构。
我们正在使用Mail插槽与用户界面进行通信,由于其复杂性和使用年限,没有其他方法可以执行此操作,并且它已在全球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,我可以将字节数组和具有相同大小的struckt同时放在同一位置。
[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;
};
在以这种方式定义它时,我在CalculateChecksum()处获得了ArgumentException。 我用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();
}
在CalculateChecksum()中,我将得到ArgumentException {“无法封送类型,因为嵌入数组实例的长度与布局中声明的长度不匹配。”}
你可以在这里看到图片。
//这是有照片但我没有足够声望的部分。 所以我得把它写下来。 :-(我会发布它尽快我的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 - &gt; 0x00cc1bfc 和 * messageData.parameter.strInternalProcess.data - &gt; 0x00cc1bfc
两个数据数组都指向相同的位置,这是错误的,因为ushort命令应该至少有2个字节的偏移量。
我的byte [] byteArray是4204
因此,在阅读了更多内容并尝试自己解决之后,我发现了两种可能的解决方案。 但是每个解决方案都有一个我无法解决的问题。
首先,我在所做的所有事情中做错了什么,或者对我发布的代码有一个简单的解决方案。
所以现在我会找到我想到的可能的解决方案,但我会在这篇帖子下单独发布。
感谢您的帮助。我很感激每一个答案,因为我现在已经停留了一个多星期,并且不知道还有什么可以尝试。
答案 0 :(得分:0)
问题的可能解决方案有一个我无法解决的新问题。
我改变了:
的定义 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
这解决了我在两个数据阵列指向同一位置时遇到的问题。 正如您在图片中看到的那样。但它会产生一个新问题。
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)
所以这是我的问题,我需要一些帮助。
答案 1 :(得分:0)
输入'GettingStartedClient.MailslotData + SMessageData'不能 作为一个不受管理的结构编组;没有意义的大小或偏移可以 计算。
所以我玩了[MarshalAs(UnmanagedType。)但我的设置 找不到可以正常工作的配置。
现在我知道为什么了。 因此,了解背景使一切都清楚。 我试图掩饰一个固定的数组。 mashel所做的是重新排列结构,使其看起来像你决定要看一样。 mashal命令无法使用固定数组。
所以解决方案非常简单。删除mashaling和voilà。一切正常。
[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];
};