结构体定义如下    //报文头
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TMsgHeadInfo
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public char[] MsgCode;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public char[] MsgType;
        public byte SenderType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public char[] Sender;
        public byte ReceiverType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public char[] Receiver;
        public int TotalLength;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] VerifyCode;
    }
//03 报文
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TLabelContent
    {
        public int PosX;
        public int PosY;
        public int Flag;
        public int Flv;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
        public char[] FileName;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
        public char[] strContent;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public char[] strColor;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public char[] strBkColor;
        public int Space;
        public int Font;
        public int FontHeight;
        public int FontWidth;
    }    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TPlayList
    {
        public int ActTime;
        public int Action;
        public int Speed;
        public int ListNum;
        public TLabelContent[] Content;
    }
    //下发节目单
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TPlayListInfo
    {
        public byte DevType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public char[] DevCode;
        public int Page;
        public TPlayList[] PlayList;
    }
    //下发报文
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TPlayListMsg
    {
        public TMsgHeadInfo MsgHead;
        public TPlayListInfo PlayListInfo;
    }调用代码如下private void button3_Click(object sender, EventArgs e)
        {
            //初始化方法是否正确,如果不正确请告知其他方法
            TPlayListMsg playlistmsg;
            playlistmsg.PlayListInfo.PlayList = new TPlayList[10];            for (int i = 0; i < 10; i++)
                playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5];            playlistmsg.PlayListInfo.DevCode = new char[10];
            playlistmsg.PlayListInfo.DevCode = "2803000001".ToCharArray();
            playlistmsg.PlayListInfo.DevType = 1;
            playlistmsg.PlayListInfo.Page = 10;            playlistmsg.MsgHead.MsgCode = new char[2];
            playlistmsg.MsgHead.MsgCode = "03".ToCharArray();            playlistmsg.MsgHead.MsgType = new char[2];
            playlistmsg.MsgHead.MsgType = "01".ToCharArray();
            playlistmsg.MsgHead.SenderType = 1;            playlistmsg.MsgHead.Sender = new char[6];
            playlistmsg.MsgHead.Sender = "280100".ToCharArray();            playlistmsg.MsgHead.Receiver = new char[6];
            playlistmsg.MsgHead.Receiver = "280300".ToCharArray();
            playlistmsg.MsgHead.ReceiverType = 4;
            //注意此处
            playlistmsg.MsgHead.TotalLength = 2600;            playlistmsg.MsgHead.VerifyCode = new char[32];
            //注意此处
            playlistmsg.MsgHead.VerifyCode = "235A3ECDB49A612AFDE4F4C3D6735D5D".ToCharArray();
            
            for (int i = 0; i < 10; i++)
            {
                playlistmsg.PlayListInfo.PlayList[i].ListNum = 5;
                playlistmsg.PlayListInfo.PlayList[i].Action = 1;
                playlistmsg.PlayListInfo.PlayList[i].ActTime = 5;
                playlistmsg.PlayListInfo.PlayList[i].Speed = 10;
                for (int j = 0; j < 5; j++)
                {
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].PosX = 0;
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].PosY = 0;                    playlistmsg.PlayListInfo.PlayList[i].Content[j].FileName = new char[255];
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].FileName = "".ToCharArray();
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].Flag = 0;
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].Flv = 0;
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].Font = 0;
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].FontHeight = 32;
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].FontWidth = 32;
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].Space = 0;                    playlistmsg.PlayListInfo.PlayList[i].Content[j].strBkColor = new char[12];
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].strBkColor = "255000000000".ToCharArray();                    playlistmsg.PlayListInfo.PlayList[i].Content[j].strColor = new char[12];
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].strColor = "000000000000".ToCharArray();                    playlistmsg.PlayListInfo.PlayList[i].Content[j].strContent = new char[255];
                    playlistmsg.PlayListInfo.PlayList[i].Content[j].strContent = "祝您一路平安".ToCharArray();
                }
            }
            
            Tools tool = new Tools();
            byte[] by = tool.StructToBytes(playlistmsg.PlayListInfo);
            playlistmsg.MsgHead.VerifyCode = tool.MD5Byte(by);            byte[] bytes = tool.StructToBytes(playlistmsg.MsgHead);            playlistmsg.MsgHead.TotalLength = Marshal.SizeOf(playlistmsg);            TCPClient tcp = new TCPClient();
            int ret;
            ret = tcp.ConnectServer("192.168.26.118", 13334);
            if (ret == 0)
            {
                MessageBox.Show("连接服务器失败");
            }
            else
            {
                MessageBox.Show("连接服务器成功");                if (tcp.SendMsg(bytes) > 0)
                {
                    MessageBox.Show("发送成功");
                }
                else
                {
                    MessageBox.Show("发送失败");
                }
            }
        }
里面用到的结构体转byte数组的代码如下
        public byte[] StructToBytes(object obj)
        {
            int size = Marshal.SizeOf(obj);
            byte[] bytes = new byte[size];
            IntPtr structPtr = Marshal.AllocHGlobal(size); //分配结构体大小的内存空间
            Marshal.StructureToPtr(obj, structPtr, false); //将结构体拷到分配好的内存空间
            Marshal.Copy(structPtr, bytes, 0, size);       //从内存空间拷到byte数组
            Marshal.FreeHGlobal(structPtr);                //释放内存空间
            return bytes;
        }
我上面的初始化方法是否正确,另外上面标处两个注意的地方,一个是要得到这处结构体的MD5(只要报文体的,即TPlaylistInfo的),一个是要得到这个结构体的长度,但是因为如果结构体中有未赋值 参数,所以就先随便赋了个值,然后再修改的这两个值,挺别扭,请问有其他方法吗
近来问的问题回答的人不多,而且大多没回答到点子上,望大家认真对待,解决问题后,尽快结帖,如果分不够,可以再开帖散分,谢谢StructurestructC#数组结构体数组

解决方案 »

  1.   

    这句提示错误,
    byte[] by = tool.StructToBytes(playlistmsg.PlayListInfo);
                playlistmsg.MsgHead.VerifyCode = tool.MD5Byte(by);未处理的“System.ArgumentException”类型的异常出现在 MTWS.Net.exe 中。其他信息: 参数错误。 (异常来自 HRESULT:0x80070057 (E_INVALIDARG))另外TCPCLIENT类的定义如下
     class TCPClient
        {
            //客户端socket
            Socket ClientSocket;
            IPEndPoint sSvrIP;
            public TCPClient()
            {        }        ~TCPClient()
            {        }        public int ConnectServer(string IP, int Port)
            {
                int ret = 0;
                sSvrIP = new IPEndPoint(IPAddress.Parse(IP), Port);
                ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                try
                {
                    ClientSocket.Connect(sSvrIP);
                    ret = 1;
                }
                catch (SocketException ex)
                {
                    ret = 0;
                    //throw new Exception(ex.Message);
                }
                return ret;
            }        public bool IsConnected()
            {
                return ClientSocket.Connected;
            }        public int SendMsg(byte[] Msg)
            {
                if (IsConnected())
                    return ClientSocket.Send(Msg, Msg.Length, SocketFlags.None);
                else
                    return -1;
            }        public int RecvMsg(byte[] Msg)
            {
                int bufLen = 0;
                bufLen = Msg.Length;
                if (IsConnected())
                    return ClientSocket.Receive(Msg, bufLen, SocketFlags.None);
                else
                    return -1;
            }
        }
      

  2.   

    public TLabelContent[] Content;
    你确定这个地方不用再加修饰或者指明空间大小码?
      

  3.   

    这个地方已经指出了
    for (int i = 0; i < 10; i++)                 playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5]; 
      

  4.   

    这个地方已经指出了
    for (int i = 0; i < 10; i++)                 playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5]; c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
      

  5.   

    这个地方已经指出了
    for (int i = 0; i < 10; i++)                 playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5]; c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
    应该如何写呢?
      

  6.   

    TPlayList是不能封送(Marshal)的,原因是,缺少了SizeConst定义,CLR不知道TLabelContent[]到底要封送出几个,或封收几个。一种比较简单直接做法是,自己做系列化,而不依赖于系统封送:
    interface IPersistable
    {
        void WriteTo(Stream stream);
        void ReadFrom(Stream stream);
    }class TLabelContent : IPersistable
    {
       //...
    }class TPlayList : IPersistable
    {
        public int ActTime;
        public int Action;
        public int Speed;
        public int ListNum;
        public TLabelContent[] Content;    public void WriteToStream(Stream s)
        {
            if (Content == null || Content.Length != ListNum) throw new Exception("");        foreach (int i in new int[] { ActTime, Action, Speed, ListNum })
            {
                byte[] bytes = BitConverter.GetBytes(i);
                s.Write(bytes, 0, bytes.Length);
            }
            foreach (IPersistable c in Content)
            {
                c.WriteTo(s);
            }
        }
        public void ReadFromStream(Stream s)
        {
            //...
            Content = new TLabelContent[ListNum];
            for (int i = 0; i < ListNum; i++)
            {
                Content[i] = new TLabelContent();
                Content[i].ReadFrom(s);
            }
        }
    }
      

  7.   

    这个地方已经指出了
    for (int i = 0; i < 10; i++)                 playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5]; c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
    应该如何写呢?
    类型定义你这么写也可以,但是封送和解析的地方,你还是按照报文的定义(类型、顺序、长度、字节序)来处理吧
      

  8.   

    如果加上[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]这样能行吗?
      

  9.   

    楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
      

  10.   

    是啊,这C#我是半瓶子醋的水平,只好这样了记得你有发过类拟的贴子。不是有跟你提过么。
    你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
    然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
      

  11.   

    是啊,这C#我是半瓶子醋的水平,只好这样了记得你有发过类拟的贴子。不是有跟你提过么。
    你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
    然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。

    那个问题已解决了,这是新问题,结构体套结构体数组的问题
      

  12.   

    这个地方已经指出了
    for (int i = 0; i < 10; i++)                 playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5]; c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
    应该如何写呢?
    类型定义你这么写也可以,但是封送和解析的地方,你还是按照报文的定义(类型、顺序、长度、字节序)来处理吧
    但是提示错误啊
    未处理的“System.ArgumentException”类型的异常出现在 MTWS.Net.exe 中。其他信息: 未能封送类型,因为嵌入数组实例的长度与布局中声明的长度不匹配。
      

  13.   

    另外可否这样,声明lablecontent数组,赋值 ,然后把他们移动到一个连续内在里再发送
      

  14.   

    是啊,这C#我是半瓶子醋的水平,只好这样了记得你有发过类拟的贴子。不是有跟你提过么。
    你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
    然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。

    那个问题已解决了,这是新问题,结构体套结构体数组的问题我的建议还是一样的,要不然你会发现C#强行实现C++的结构,到了后边会是个坑,而这个坑会越挖越深。。C++多以指针操作,他可以容易实现结构的大小对应内存里的数据,C#这方面不怎么行。
    就像内存共享一样。当然你要非得这样实现,只能慢慢去挖觉。我也会关注一下。可能以后会用到。
      

  15.   

    记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
      

  16.   


    你可以打印出C++的结构体
    我打个比方
    C++结构体 public int X
     public long Y
     public String xxx
     public bool aa这样的结构 在内存中
    他是 
    int 对应的是4个byte
    long 对应的是8个byte
    string 两种可能(字符长度+ string->Byte,另一种是 string->byte + \0 这是常见的一种)
    bool 1个byte所以结构变Byte[]就是 4+8+((string->Byte).Length +1) + 1
    然后就把这个Byte直接发给C++服务端,就会认的出来了所以我之前跟你提的先看看C++的结构体转成Byte是什么样的打印出来。,int long bool 都是一样的。
    然后由C#自己用Byte组合,结构套结构 在C++里他们内存里的数据都是连继的会放在一起,C#是引用类型,
    所以你得出的数据就不是你要的结果了。
      

  17.   


    你可以打印出C++的结构体
    我打个比方
    C++结构体 public int X
     public long Y
     public String xxx
     public bool aa这样的结构 在内存中
    他是 
    int 对应的是4个byte
    long 对应的是8个byte
    string 两种可能(字符长度+ string->Byte,另一种是 string->byte + \0 这是常见的一种)
    bool 1个byte所以结构变Byte[]就是 4+8+((string->Byte).Length +1) + 1
    然后就把这个Byte直接发给C++服务端,就会认的出来了所以我之前跟你提的先看看C++的结构体转成Byte是什么样的打印出来。,int long bool 都是一样的。
    然后由C#自己用Byte组合,结构套结构 在C++里他们内存里的数据都是连继的会放在一起,C#是引用类型,
    所以你得出的数据就不是你要的结果了。

    感谢,问题已解决,还是用原来的方法,提示那个错误是因为位数不够,又没有自动补齐,您所说的那种访求,我也想尝试一下,可以加我QQ 78647557,晚上聊聊,C#方面还要多向你学习,
      

  18.   


    你可以打印出C++的结构体
    我打个比方
    C++结构体 public int X
     public long Y
     public String xxx
     public bool aa这样的结构 在内存中
    他是 
    int 对应的是4个byte
    long 对应的是8个byte
    string 两种可能(字符长度+ string->Byte,另一种是 string->byte + \0 这是常见的一种)
    bool 1个byte所以结构变Byte[]就是 4+8+((string->Byte).Length +1) + 1
    然后就把这个Byte直接发给C++服务端,就会认的出来了所以我之前跟你提的先看看C++的结构体转成Byte是什么样的打印出来。,int long bool 都是一样的。
    然后由C#自己用Byte组合,结构套结构 在C++里他们内存里的数据都是连继的会放在一起,C#是引用类型,
    所以你得出的数据就不是你要的结果了。

    感谢,问题已解决,还是用原来的方法,提示那个错误是因为位数不够,又没有自动补齐,您所说的那种访求,我也想尝试一下,可以加我QQ 78647557,晚上聊聊,C#方面还要多向你学习,贴出结果呀。。哪里补齐