c#/c++ 如何将结构的结构与 marshal.sizeof 联合
Posted
技术标签:
【中文标题】c#/c++ 如何将结构的结构与 marshal.sizeof 联合【英文标题】:How to union struct of struct with marshal.sizeof c#/c++ 【发布时间】:2012-11-29 09:19:38 【问题描述】:问题是我试图在我的 c# 程序中使用 c++ 结构。
我们正在使用 Mail slot 与用户界面进行通信,但由于复杂性和年代久远,没有其他方法可以做到这一点,并且它在全球 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;
;
以这种方式定义它时,我在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 -> 0x00cc1bfc 和 *messageData.parameter.strInternalProcess.data -> 0x00cc1bfc
两个数据数组都指向同一个位置,这是错误的,因为 ushort 命令应该至少有 2 个字节的偏移量。
我的 byte[] byteArray 是 4204
因此,在阅读了更多内容并尝试自己弄清楚之后,我找到了 2 个可能的解决方案。 但是每个解决方案都有一个我自己无法解决的问题。
首先,我到目前为止所做的所有事情都做错了什么,或者我发布的代码是否有一个简单的解决方案。
所以现在我将讨论我想到的可能的解决方案,但我将在这篇文章下方单独发布它们。
感谢您的所有帮助。我感谢每一个答案,因为我在这一点上停留了一个多星期,不知道还有什么可以尝试的。
【问题讨论】:
【参考方案1】:问题的可能解决方案是一个我自己无法解决的新问题。
我改变了以下的定义:
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)
所以这是我的问题,我需要一些帮助。
【讨论】:
找到了我的解决方案。一旦我知道如何用语言表达就会分享它。【参考方案2】:Type 'GettingStartedClient.MailslotData+SMessageData' 不能 编组为非托管结构;没有有意义的大小或偏移量可以 被计算出来。
所以我使用了 [MarshalAs(UnmanagedType. 但我 找不到可以正常工作的配置。
现在我知道为什么了。 因此,了解背景可以使一切变得清晰。 我试图混搭一个固定的数组。 mashel 所做的是重新排列结构,使其看起来像您已经决定的样子。这是 mashal 命令无法对固定数组执行的操作。
所以解决方案非常简单。删除捣碎和瞧。一切正常。
[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];
;
【讨论】:
以上是关于c#/c++ 如何将结构的结构与 marshal.sizeof 联合的主要内容,如果未能解决你的问题,请参考以下文章
如何正确地将这些转换为 c#,marshall,以便我可以将这些结构传递给 DLL (c++)?
COM接口 c# marshalling array of arrays
Marshall结构通过sendmessage将其传递给delphi记录