//报文头
[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的),一个是要得到这个结构体的长度,但是因为如果结构体中有未赋值 参数,所以就先随便赋了个值,然后再修改的这两个值,挺别扭,请问有其他方法吗
近来问的问题回答的人不多,而且大多没回答到点子上,望大家认真对待,解决问题后,尽快结帖,如果分不够,可以再开帖散分,谢谢
21 个解决方案
#1
这句提示错误,
未处理的“System.ArgumentException”类型的异常出现在 MTWS.Net.exe 中。
其他信息: 参数错误。 (异常来自 HRESULT:0x80070057 (E_INVALIDARG))
另外TCPCLIENT类的定义如下
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
c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
#5
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了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
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了for (int i = 0; i < 10; i++) playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5];
c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
应该如何写呢?
类型定义你这么写也可以,但是封送和解析的地方,你还是按照报文的定义(类型、顺序、长度、字节序)来处理吧
#8
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);
}
}
}
如果加上[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]这样能行吗?
#9
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
#10
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
#11
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
记得你有发过类拟的贴子。不是有跟你提过么。
你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
#12
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
记得你有发过类拟的贴子。不是有跟你提过么。
你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
那个问题已解决了,这是新问题,结构体套结构体数组的问题
#13
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了for (int i = 0; i < 10; i++) playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5];
c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
应该如何写呢?
类型定义你这么写也可以,但是封送和解析的地方,你还是按照报文的定义(类型、顺序、长度、字节序)来处理吧
但是提示错误啊
未处理的“System.ArgumentException”类型的异常出现在 MTWS.Net.exe 中。
其他信息: 未能封送类型,因为嵌入数组实例的长度与布局中声明的长度不匹配。
#14
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);
}
}
}
另外可否这样,声明lablecontent数组,赋值 ,然后把他们移动到一个连续内在里再发送
#15
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
记得你有发过类拟的贴子。不是有跟你提过么。
你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
那个问题已解决了,这是新问题,结构体套结构体数组的问题
我的建议还是一样的,要不然你会发现C#强行实现C++的结构,到了后边会是个坑,而这个坑会越挖越深。。
C++多以指针操作,他可以容易实现结构的大小对应内存里的数据,C#这方面不怎么行。
就像内存共享一样。当然你要非得这样实现,只能慢慢去挖觉。我也会关注一下。可能以后会用到。
#16
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
#17
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
你可以打印出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#是引用类型,
所以你得出的数据就不是你要的结果了。
#18
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
你可以打印出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#方面还要多向你学习,
#19
C#想管理内存数据确实要命...
#20
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
你可以打印出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#方面还要多向你学习,
贴出结果呀。。哪里补齐
#21
所有的char数组都要补齐
#1
这句提示错误,
未处理的“System.ArgumentException”类型的异常出现在 MTWS.Net.exe 中。
其他信息: 参数错误。 (异常来自 HRESULT:0x80070057 (E_INVALIDARG))
另外TCPCLIENT类的定义如下
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
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了
for (int i = 0; i < 10; i++) playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5];
#4
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了for (int i = 0; i < 10; i++) playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5];
c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
#5
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了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
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了for (int i = 0; i < 10; i++) playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5];
c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
应该如何写呢?
类型定义你这么写也可以,但是封送和解析的地方,你还是按照报文的定义(类型、顺序、长度、字节序)来处理吧
#8
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);
}
}
}
如果加上[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]这样能行吗?
#9
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
#10
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
#11
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
记得你有发过类拟的贴子。不是有跟你提过么。
你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
#12
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
记得你有发过类拟的贴子。不是有跟你提过么。
你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
那个问题已解决了,这是新问题,结构体套结构体数组的问题
#13
public TLabelContent[] Content;
你确定这个地方不用再加修饰或者指明空间大小码?
这个地方已经指出了for (int i = 0; i < 10; i++) playlistmsg.PlayListInfo.PlayList[i].Content = new TLabelContent[5];
c#结构里的数组仍然是引用类型,在内存里仍然是一个4字节的引用,而不是所有元素的所有空间
应该如何写呢?
类型定义你这么写也可以,但是封送和解析的地方,你还是按照报文的定义(类型、顺序、长度、字节序)来处理吧
但是提示错误啊
未处理的“System.ArgumentException”类型的异常出现在 MTWS.Net.exe 中。
其他信息: 未能封送类型,因为嵌入数组实例的长度与布局中声明的长度不匹配。
#14
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);
}
}
}
另外可否这样,声明lablecontent数组,赋值 ,然后把他们移动到一个连续内在里再发送
#15
楼主过于依赖C++的结构体了。C#要实现C++的模式还真有点难度。
是啊,这C#我是半瓶子醋的水平,只好这样了
记得你有发过类拟的贴子。不是有跟你提过么。
你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。
然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
那个问题已解决了,这是新问题,结构体套结构体数组的问题
我的建议还是一样的,要不然你会发现C#强行实现C++的结构,到了后边会是个坑,而这个坑会越挖越深。。
C++多以指针操作,他可以容易实现结构的大小对应内存里的数据,C#这方面不怎么行。
就像内存共享一样。当然你要非得这样实现,只能慢慢去挖觉。我也会关注一下。可能以后会用到。
#16
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
#17
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
你可以打印出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#是引用类型,
所以你得出的数据就不是你要的结果了。
#18
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
你可以打印出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#方面还要多向你学习,
#19
C#想管理内存数据确实要命...
#20
记得你有发过类拟的贴子。不是有跟你提过么。 你把C++封装后的结构体转成byte[] 后打印出来, 看里面的字节是怎么组成的。 然后用C#的BinaryWrite 去组成C++转成byte[]后的字节就是了。这种方法是最可行的。
这种方式我考虑过,但是如果把他们连续的放在一起里,前面有人说过用范型,也是类似,可惜水平不行,不知道如何使用
你可以打印出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#方面还要多向你学习,
贴出结果呀。。哪里补齐
#21
所有的char数组都要补齐