简体   繁体   English

如何将结构体与 marshal.sizeof c#/c++ 联合

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM