-2

问题是我试图在我的 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

因此,在阅读了更多内容并尝试自己弄清楚之后,我找到了两种可能的解决方案。但是每个解决方案都有一个我自己无法解决的问题。

首先,我在到目前为止所做的所有事情中都做错了什么,或者我发布的代码是否有一个简单的解决方案。

所以现在我将介绍我想到的可能的解决方案,但我将在这篇文章下面单独发布它们。

感谢你的帮助。我感谢每一个答案,因为我现在被困在这一点上一个多星期了,不知道还有什么可以尝试的。

4

2 回答 2

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) 的子集测试了所有设置

所以这是我的问题,我需要一些帮助。

于 2012-11-29T10:24:57.703 回答
0

类型“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];
};
于 2012-11-29T13:29:14.343 回答