diff --git a/XCoder/Protocols/ModbusMessage.cs b/XCoder/Protocols/ModbusMessage.cs
index 38bf932..69d2928 100644
--- a/XCoder/Protocols/ModbusMessage.cs
+++ b/XCoder/Protocols/ModbusMessage.cs
@@ -4,166 +4,165 @@ using System.Runtime.Serialization;
using NewLife.Data;
using NewLife.Serialization;
-namespace NewLife.IoT.Protocols
+namespace NewLife.IoT.Protocols;
+
+public class ModbusMessage : IAccessor
{
- public class ModbusMessage : IAccessor
- {
- #region 属性
- /// <summary>是否响应</summary>
- [IgnoreDataMember]
- public Boolean Reply { get; set; }
+ #region 属性
+ /// <summary>是否响应</summary>
+ [IgnoreDataMember]
+ public Boolean Reply { get; set; }
- /// <summary>事务编号</summary>
- public UInt16 TransactionId { get; set; }
+ /// <summary>事务编号</summary>
+ public UInt16 TransactionId { get; set; }
- /// <summary>协议</summary>
- public UInt16 ProtocolId { get; set; }
+ /// <summary>协议</summary>
+ public UInt16 ProtocolId { get; set; }
- /// <summary>站号</summary>
- public Byte Host { get; set; }
+ /// <summary>站号</summary>
+ public Byte Host { get; set; }
- /// <summary>操作码</summary>
- public FunctionCodes Code { get; set; }
+ /// <summary>操作码</summary>
+ public FunctionCodes Code { get; set; }
- /// <summary>地址。请求中使用</summary>
- public UInt16 Address { get; set; }
+ /// <summary>地址。请求中使用</summary>
+ public UInt16 Address { get; set; }
- /// <summary>个数</summary>
- public UInt16 Count { get; set; }
+ /// <summary>个数</summary>
+ public UInt16 Count { get; set; }
- /// <summary>负载数据。响应中使用</summary>
- [IgnoreDataMember]
- public Packet Payload { get; set; }
- #endregion
+ /// <summary>负载数据。响应中使用</summary>
+ [IgnoreDataMember]
+ public Packet Payload { get; set; }
+ #endregion
- #region 构造
- public override String ToString()
+ #region 构造
+ public override String ToString()
+ {
+ if (!Reply)
{
- if (!Reply)
- {
- if (Payload == null)
- return $"{Code} ({Address}, {Count})";
- else
- return $"{Code} ({Address}={Payload.ToHex()})";
- }
+ if (Payload == null)
+ return $"{Code} ({Address}, {Count})";
else
- return $"{Code} {Payload.ToHex()}";
+ return $"{Code} ({Address}={Payload.ToHex()})";
}
- #endregion
-
- #region 方法
- /// <summary>读取</summary>
- /// <param name="stream"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public Boolean Read(Stream stream, Object context)
+ else
+ return $"{Code} {Payload.ToHex()}";
+ }
+ #endregion
+
+ #region 方法
+ /// <summary>读取</summary>
+ /// <param name="stream"></param>
+ /// <param name="context"></param>
+ /// <returns></returns>
+ public Boolean Read(Stream stream, Object context)
+ {
+ var binary = context as Binary ?? new Binary { Stream = stream, IsLittleEndian = false };
+
+ TransactionId = binary.Read<UInt16>();
+ ProtocolId = binary.Read<UInt16>();
+ var len = binary.Read<UInt16>();
+ if (len < 1 + 1 + 1) return false;
+
+ Host = binary.ReadByte();
+ Code = (FunctionCodes)binary.ReadByte();
+
+ len -= 2;
+ if (!Reply)
{
- var binary = context as Binary ?? new Binary { Stream = stream, IsLittleEndian = false };
-
- TransactionId = binary.Read<UInt16>();
- ProtocolId = binary.Read<UInt16>();
- var len = binary.Read<UInt16>();
- if (len < 1 + 1 + 1) return false;
-
- Host = binary.ReadByte();
- Code = (FunctionCodes)binary.ReadByte();
-
- len -= 2;
- if (!Reply)
- {
- Address = binary.Read<UInt16>();
- if (len == 4)
- Count = binary.Read<UInt16>();
- else
- Payload = binary.ReadBytes(len - 2);
- }
- else if (len >= 1)
- {
- var len2 = binary.ReadByte();
- if (len2 <= len - 1) Payload = binary.ReadBytes(len2);
- }
-
- return true;
+ Address = binary.Read<UInt16>();
+ if (len == 4)
+ Count = binary.Read<UInt16>();
+ else
+ Payload = binary.ReadBytes(len - 2);
}
-
- /// <summary>解析消息</summary>
- /// <param name="pk"></param>
- /// <returns></returns>
- public static ModbusMessage Read(Packet pk, Boolean reply = false)
+ else if (len >= 1)
{
- var msg = new ModbusMessage { Reply = reply };
- if (msg.Read(pk.GetStream(), null)) return msg;
-
- return null;
+ var len2 = binary.ReadByte();
+ if (len2 <= len - 1) Payload = binary.ReadBytes(len2);
}
- /// <summary>写入消息到数据流</summary>
- /// <param name="stream"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public Boolean Write(Stream stream, Object context)
- {
- var binary = context as Binary ?? new Binary { Stream = stream, IsLittleEndian = false };
+ return true;
+ }
- binary.Write(TransactionId);
- binary.Write(ProtocolId);
+ /// <summary>解析消息</summary>
+ /// <param name="pk"></param>
+ /// <returns></returns>
+ public static ModbusMessage Read(IPacket pk, Boolean reply = false)
+ {
+ var msg = new ModbusMessage { Reply = reply };
+ if (msg.Read(pk.GetStream(), null)) return msg;
- var pk = Payload;
- var len = 1 + 1;
- if (!Reply)
- len += 2 + (pk?.Total ?? 2);
- else
- len += 1 + (pk?.Total ?? 0);
- binary.Write((UInt16)len);
-
- binary.Write(Host);
- binary.Write((Byte)Code);
-
- if (!Reply)
- {
- binary.Write(Address);
- if (pk != null)
- binary.Write(pk.Data, pk.Offset, pk.Count);
- else
- binary.Write(Count);
- }
+ return null;
+ }
+
+ /// <summary>写入消息到数据流</summary>
+ /// <param name="stream"></param>
+ /// <param name="context"></param>
+ /// <returns></returns>
+ public Boolean Write(Stream stream, Object context)
+ {
+ var binary = context as Binary ?? new Binary { Stream = stream, IsLittleEndian = false };
+
+ binary.Write(TransactionId);
+ binary.Write(ProtocolId);
+
+ var pk = Payload;
+ var len = 1 + 1;
+ if (!Reply)
+ len += 2 + (pk?.Total ?? 2);
+ else
+ len += 1 + (pk?.Total ?? 0);
+ binary.Write((UInt16)len);
+
+ binary.Write(Host);
+ binary.Write((Byte)Code);
+
+ if (!Reply)
+ {
+ binary.Write(Address);
+ if (pk != null)
+ binary.Write(pk.Data, pk.Offset, pk.Count);
else
- {
- var len2 = (pk?.Total ?? 0);
- binary.Write((Byte)len2);
- if (pk != null)
- binary.Write(pk.Data, pk.Offset, pk.Count);
- }
-
- return true;
+ binary.Write(Count);
}
-
- /// <summary>消息转数据包</summary>
- /// <returns></returns>
- public Packet ToPacket()
+ else
{
- var ms = new MemoryStream();
- Write(ms, null);
-
- ms.Position = 0;
- return new Packet(ms);
+ var len2 = (pk?.Total ?? 0);
+ binary.Write((Byte)len2);
+ if (pk != null)
+ binary.Write(pk.Data, pk.Offset, pk.Count);
}
- public ModbusMessage CreateReply()
+ return true;
+ }
+
+ /// <summary>消息转数据包</summary>
+ /// <returns></returns>
+ public Packet ToPacket()
+ {
+ var ms = new MemoryStream();
+ Write(ms, null);
+
+ ms.Position = 0;
+ return new Packet(ms);
+ }
+
+ public ModbusMessage CreateReply()
+ {
+ if (Reply) throw new InvalidOperationException();
+
+ var msg = new ModbusMessage
{
- if (Reply) throw new InvalidOperationException();
-
- var msg = new ModbusMessage
- {
- Reply = true,
- TransactionId = TransactionId,
- ProtocolId = ProtocolId,
- Host = Host,
- Code = Code,
- };
-
- return msg;
- }
- #endregion
+ Reply = true,
+ TransactionId = TransactionId,
+ ProtocolId = ProtocolId,
+ Host = Host,
+ Code = Code,
+ };
+
+ return msg;
}
+ #endregion
}
\ No newline at end of file
diff --git a/XCoder/Protocols/ModbusTcp.cs b/XCoder/Protocols/ModbusTcp.cs
index 9953451..2455d59 100644
--- a/XCoder/Protocols/ModbusTcp.cs
+++ b/XCoder/Protocols/ModbusTcp.cs
@@ -108,7 +108,7 @@ namespace NewLife.IoT.Protocols
if (span2 != null) span2.Tag = buf.ToHex();
- var rs = ModbusMessage.Read(buf, true);
+ var rs = ModbusMessage.Read((ArrayPacket)buf, true);
if (rs == null) return null;
WriteLog("<= {0}", rs);
diff --git a/XCoder/XCoder.csproj b/XCoder/XCoder.csproj
index 285e330..193b798 100644
--- a/XCoder/XCoder.csproj
+++ b/XCoder/XCoder.csproj
@@ -13,6 +13,8 @@
<ApplicationIcon>leaf.ico</ApplicationIcon>
<LangVersion>latest</LangVersion>
<TargetFrameworkProfile />
+ <ImplicitUsings>enable</ImplicitUsings>
+ <LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
@@ -384,25 +386,25 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NewLife.Core">
- <Version>10.10.2024.803</Version>
+ <Version>11.5.2025.501</Version>
</PackageReference>
<PackageReference Include="NewLife.Map">
- <Version>2.6.2024.801</Version>
+ <Version>2.6.2025.305</Version>
</PackageReference>
<PackageReference Include="NewLife.MQTT">
- <Version>2.0.2024.822-beta1012</Version>
+ <Version>2.0.2025.415</Version>
</PackageReference>
<PackageReference Include="NewLife.Net">
- <Version>4.3.2024.822-beta1011</Version>
+ <Version>4.4.2025.305</Version>
</PackageReference>
<PackageReference Include="NewLife.Redis">
- <Version>5.7.2024.801</Version>
+ <Version>6.2.2025.503</Version>
</PackageReference>
<PackageReference Include="NewLife.Stardust">
- <Version>3.0.2024.806</Version>
+ <Version>3.3.2025.506</Version>
</PackageReference>
<PackageReference Include="NewLife.XCode">
- <Version>11.15.2024.806</Version>
+ <Version>11.19.2025.501</Version>
</PackageReference>
<PackageReference Include="SSH.NET">
<Version>2020.0.2</Version>
diff --git a/XCoder/XCom/SerialPortList.cs b/XCoder/XCom/SerialPortList.cs
index 7a4e5ff..5007c27 100644
--- a/XCoder/XCom/SerialPortList.cs
+++ b/XCoder/XCom/SerialPortList.cs
@@ -6,6 +6,7 @@ using System.IO;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;
+using NewLife.Data;
using NewLife.Log;
using NewLife.Net;
using NewLife.Threading;
@@ -87,7 +88,7 @@ namespace NewLife.Windows
//cbEncoding.DataSource = new String[] { Encoding.UTF8.WebName, Encoding.ASCII.WebName, Encoding.UTF8.WebName };
// 添加编码子菜单
- var encs = new Encoding[] { Encoding.UTF8, Encoding.ASCII, Encoding.UTF7, Encoding.Unicode, Encoding.BigEndianUnicode, Encoding.UTF32,Encoding.GetEncoding("GB2312") };
+ var encs = new Encoding[] { Encoding.UTF8, Encoding.ASCII, Encoding.UTF7, Encoding.Unicode, Encoding.BigEndianUnicode, Encoding.UTF32, Encoding.GetEncoding("GB2312") };
var list = new List<Encoding>(encs);
// 暂时不用这么多编码
//list.AddRange(Encoding.GetEncodings().Select(e => e.GetEncoding()).Where(e => !encs.Contains(e)));
@@ -449,7 +450,7 @@ namespace NewLife.Windows
StreamReader _reader;
void OnReceived(Object sender, ReceivedEventArgs e)
{
- var data = e.Packet.ReadBytes();
+ var data = e.Packet.ReadBytes(0, -1);
if (data == null || data.Length < 1) return;
BytesOfReceived += data.Length;
diff --git a/XCoder/XCom/SerialTransport.cs b/XCoder/XCom/SerialTransport.cs
index c3d432a..206b5d3 100644
--- a/XCoder/XCom/SerialTransport.cs
+++ b/XCoder/XCom/SerialTransport.cs
@@ -9,522 +9,532 @@ using NewLife.Data;
using NewLife.Log;
using NewLife.Threading;
-namespace NewLife.Net
+namespace NewLife.Net;
+
+/// <summary>串口传输</summary>
+/// <example>
+/// 标准例程:
+/// <code>
+/// var st = new SerialTransport();
+/// st.PortName = "COM65"; // 通讯口
+/// st.FrameSize = 16; // 数据帧大小
+///
+/// st.Received += (s, e) =>
+/// {
+/// Console.WriteLine("收到 {0}", e.ToHex());
+/// };
+/// // 开始异步操作
+/// st.Open();
+///
+/// //var buf = "01080000801A".ToHex();
+/// var buf = "0111C02C".ToHex();
+/// for (int i = 0; i < 100; i++)
+/// {
+/// Console.WriteLine("发送 {0}", buf.ToHex());
+/// st.Send(buf);
+///
+/// Thread.Sleep(1000);
+/// }
+/// </code>
+/// </example>
+public class SerialTransport : DisposeBase, ITransport
{
- /// <summary>串口传输</summary>
- /// <example>
- /// 标准例程:
- /// <code>
- /// var st = new SerialTransport();
- /// st.PortName = "COM65"; // 通讯口
- /// st.FrameSize = 16; // 数据帧大小
- ///
- /// st.Received += (s, e) =>
- /// {
- /// Console.WriteLine("收到 {0}", e.ToHex());
- /// };
- /// // 开始异步操作
- /// st.Open();
- ///
- /// //var buf = "01080000801A".ToHex();
- /// var buf = "0111C02C".ToHex();
- /// for (int i = 0; i < 100; i++)
- /// {
- /// Console.WriteLine("发送 {0}", buf.ToHex());
- /// st.Send(buf);
- ///
- /// Thread.Sleep(1000);
- /// }
- /// </code>
- /// </example>
- public class SerialTransport : DisposeBase, ITransport
+ #region 属性
+ private SerialPort _Serial;
+ /// <summary>串口对象</summary>
+ public SerialPort Serial
{
- #region 属性
- private SerialPort _Serial;
- /// <summary>串口对象</summary>
- public SerialPort Serial
+ get { return _Serial; }
+ set
{
- get { return _Serial; }
- set
+ _Serial = value;
+ if (_Serial != null)
{
- _Serial = value;
- if (_Serial != null)
- {
- PortName = _Serial.PortName;
- BaudRate = _Serial.BaudRate;
- Parity = _Serial.Parity;
- DataBits = _Serial.DataBits;
- StopBits = _Serial.StopBits;
- }
+ PortName = _Serial.PortName;
+ BaudRate = _Serial.BaudRate;
+ Parity = _Serial.Parity;
+ DataBits = _Serial.DataBits;
+ StopBits = _Serial.StopBits;
}
}
+ }
- /// <summary>端口名称。默认COM1</summary>
- public String PortName { get; set; } = "COM1";
+ /// <summary>端口名称。默认COM1</summary>
+ public String PortName { get; set; } = "COM1";
- /// <summary>波特率。默认115200</summary>
- public Int32 BaudRate { get; set; } = 115200;
+ /// <summary>波特率。默认115200</summary>
+ public Int32 BaudRate { get; set; } = 115200;
- /// <summary>奇偶校验位。默认None</summary>
- public Parity Parity { get; set; } = Parity.None;
+ /// <summary>奇偶校验位。默认None</summary>
+ public Parity Parity { get; set; } = Parity.None;
- /// <summary>数据位。默认8</summary>
- public Int32 DataBits { get; set; } = 8;
+ /// <summary>数据位。默认8</summary>
+ public Int32 DataBits { get; set; } = 8;
- /// <summary>停止位。默认One</summary>
- public StopBits StopBits { get; set; } = StopBits.One;
+ /// <summary>停止位。默认One</summary>
+ public StopBits StopBits { get; set; } = StopBits.One;
- /// <summary>超时时间。超过该大小未收到数据,说明是另一帧。默认10ms</summary>
- public Int32 Timeout { get; set; } = 10;
+ /// <summary>超时时间。超过该大小未收到数据,说明是另一帧。默认10ms</summary>
+ public Int32 Timeout { get; set; } = 10;
- private String _Description;
- /// <summary>描述信息</summary>
- public String Description
+ private String _Description;
+ /// <summary>描述信息</summary>
+ public String Description
+ {
+ get
{
- get
+ if (_Description == null)
{
- if (_Description == null)
- {
- var dic = GetNames();
- if (!dic.TryGetValue(PortName, out _Description))
- _Description = "";
- }
- return _Description;
+ var dic = GetNames();
+ if (!dic.TryGetValue(PortName, out _Description))
+ _Description = "";
}
+ return _Description;
}
+ }
- ///// <summary>粘包处理接口</summary>
- //public IPacket Packet { get; set; }
+ ///// <summary>粘包处理接口</summary>
+ //public IPacket Packet { get; set; }
- /// <summary>字节超时。数据包间隔,默认20ms</summary>
- public Int32 ByteTimeout { get; set; } = 20;
- #endregion
+ /// <summary>字节超时。数据包间隔,默认20ms</summary>
+ public Int32 ByteTimeout { get; set; } = 20;
+ #endregion
- #region 构造
- /// <summary>串口传输</summary>
- public SerialTransport()
- {
- // 每隔一段时间检查一次串口是否已经关闭,如果串口已经不存在,则关闭该传输口
- timer = new TimerX(CheckDisconnect, null, 3000, 3000) { Async = true };
- }
+ #region 构造
+ /// <summary>串口传输</summary>
+ public SerialTransport()
+ {
+ // 每隔一段时间检查一次串口是否已经关闭,如果串口已经不存在,则关闭该传输口
+ timer = new TimerX(CheckDisconnect, null, 3000, 3000) { Async = true };
+ }
- /// <summary>销毁</summary>
- /// <param name="disposing"></param>
- //protected override void Dispose(Boolean disposing)
- //{
- // base.Dispose(disposing);
-
- // try
- // {
- // if (Serial != null) Close();
- // if (timer != null) timer.Dispose();
- // }
- // catch { }
- //}
- #endregion
-
- #region 方法
- /// <summary>确保创建</summary>
- public virtual void EnsureCreate()
+ /// <summary>销毁</summary>
+ /// <param name="disposing"></param>
+ //protected override void Dispose(Boolean disposing)
+ //{
+ // base.Dispose(disposing);
+
+ // try
+ // {
+ // if (Serial != null) Close();
+ // if (timer != null) timer.Dispose();
+ // }
+ // catch { }
+ //}
+ #endregion
+
+ #region 方法
+ /// <summary>确保创建</summary>
+ public virtual void EnsureCreate()
+ {
+ if (Serial == null)
{
- if (Serial == null)
- {
- Serial = new SerialPort(PortName, BaudRate, Parity, DataBits, StopBits);
+ Serial = new SerialPort(PortName, BaudRate, Parity, DataBits, StopBits);
- _Description = null;
- }
+ _Description = null;
}
+ }
+
+ /// <summary>打开</summary>
+ public virtual Boolean Open()
+ {
+ EnsureCreate();
- /// <summary>打开</summary>
- public virtual Boolean Open()
+ if (!Serial.IsOpen)
{
- EnsureCreate();
+ Serial.Open();
+ if (Received != null) Serial.DataReceived += DataReceived;
+ }
- if (!Serial.IsOpen)
- {
- Serial.Open();
- if (Received != null) Serial.DataReceived += DataReceived;
- }
+ return true;
+ }
+
+ /// <summary>关闭</summary>
+ public virtual Boolean Close()
+ {
+ // 关闭时必须清空,否则更换属性后再次打开也无法改变属性
+ var sp = Serial;
+ if (sp != null)
+ {
+ Serial = null;
+ if (Received != null) sp.DataReceived -= DataReceived;
+ if (sp.IsOpen) sp.Close();
- return true;
+ OnDisconnect();
}
- /// <summary>关闭</summary>
- public virtual Boolean Close()
- {
- // 关闭时必须清空,否则更换属性后再次打开也无法改变属性
- var sp = Serial;
- if (sp != null)
- {
- Serial = null;
- if (Received != null) sp.DataReceived -= DataReceived;
- if (sp.IsOpen) sp.Close();
+ return true;
+ }
+ #endregion
- OnDisconnect();
- }
+ #region 发送
+ /// <summary>写入数据</summary>
+ /// <param name="pk">数据包</param>
+ public virtual Int32 Send(IPacket pk)
+ {
+ if (!Open()) return -1;
- return true;
- }
- #endregion
+ WriteLog("Send:{0}", pk.ToHex());
- #region 发送
- /// <summary>写入数据</summary>
- /// <param name="pk">数据包</param>
- public virtual Int32 Send(Packet pk)
+ var sp = Serial;
+ lock (sp)
{
- if (!Open()) return -1;
+ if (pk.TryGetArray(out var arr))
+ sp.Write(arr.Array, arr.Offset, arr.Count);
+ else
+ sp.Write(pk.ToArray(), 0, pk.Total);
+ }
- WriteLog("Send:{0}", pk.ToHex());
+ return pk.Total;
+ }
- var sp = Serial;
- lock (sp)
- {
- sp.Write(pk.Data, pk.Offset, pk.Count);
- }
+ public Int32 Send(Byte[] buffer) => Send(new ArrayPacket(buffer));
- return pk.Total;
- }
+ /// <summary>异步发送数据并等待响应</summary>
+ /// <param name="pk"></param>
+ /// <returns></returns>
+ public virtual async Task<IOwnerPacket> SendAsync(IPacket pk)
+ {
+ if (!Open()) return null;
- /// <summary>异步发送数据并等待响应</summary>
- /// <param name="pk"></param>
- /// <returns></returns>
- public virtual async Task<Packet> SendAsync(Packet pk)
- {
- if (!Open()) return null;
+ //if (Packet == null) Packet = new PacketProvider();
- //if (Packet == null) Packet = new PacketProvider();
+ //var task = Packet.Add(pk, null, Timeout);
- //var task = Packet.Add(pk, null, Timeout);
+ _Source = new TaskCompletionSource<IOwnerPacket>();
- _Source = new TaskCompletionSource<Packet>();
+ if (pk != null)
+ {
+ WriteLog("SendAsync:{0}", pk.ToHex());
- if (pk != null)
+ // 发送数据
+ var sp = Serial;
+ lock (sp)
{
- WriteLog("SendAsync:{0}", pk.ToHex());
-
- // 发送数据
- Serial.Write(pk.Data, pk.Offset, pk.Count);
+ if (pk.TryGetArray(out var arr))
+ sp.Write(arr.Array, arr.Offset, arr.Count);
+ else
+ sp.Write(pk.ToArray(), 0, pk.Total);
}
-
- return await _Source.Task;
}
- /// <summary>接收数据</summary>
- /// <returns></returns>
- public virtual Packet Receive()
- {
- if (!Open()) return null;
+ return await _Source.Task;
+ }
- var task = SendAsync(null);
- if (Timeout > 0 && !task.Wait(Timeout)) return null;
+ /// <summary>接收数据</summary>
+ /// <returns></returns>
+ public virtual IOwnerPacket Receive()
+ {
+ if (!Open()) return null;
- return task.Result;
- }
- #endregion
+ var task = SendAsync(null);
+ if (Timeout > 0 && !task.Wait(Timeout)) return null;
- #region 异步接收
- void DataReceived(Object sender, SerialDataReceivedEventArgs e)
+ return task.Result;
+ }
+ #endregion
+
+ #region 异步接收
+ void DataReceived(Object sender, SerialDataReceivedEventArgs e)
+ {
+ // 发送者必须保持一定间隔,每个报文不能太大,否则会因为粘包拆包而出错
+ try
{
- // 发送者必须保持一定间隔,每个报文不能太大,否则会因为粘包拆包而出错
- try
+ var sp = sender as SerialPort;
+ WaitMore();
+ if (sp.BytesToRead > 0)
{
- var sp = sender as SerialPort;
- WaitMore();
- if (sp.BytesToRead > 0)
- {
- var buf = new Byte[sp.BytesToRead];
+ //var buf = new Byte[sp.BytesToRead];
- var count = sp.Read(buf, 0, buf.Length);
- //if (count != buf.Length) buf = buf.ReadBytes(0, count);
- //var ms = new MemoryStream(buf, 0, count, false);
- var pk = new Packet(buf, 0, count);
+ var pk = new OwnerPacket(sp.BytesToRead);
+ var count = sp.Read(pk.Buffer, pk.Offset, pk.Length);
+ pk.Resize(count);
- ProcessReceive(pk);
- }
- }
- catch (Exception ex)
- {
- //WriteLog("Error " + ex.Message);
- if (Log != null) Log.Error("DataReceived Error {0}", ex.Message);
+ ProcessReceive(pk);
}
}
-
- void WaitMore()
+ catch (Exception ex)
{
- var sp = Serial;
-
- var ms = ByteTimeout;
- var end = DateTime.Now.AddMilliseconds(ms);
- var count = sp.BytesToRead;
- while (sp.IsOpen && end > DateTime.Now)
- {
- //Thread.SpinWait(1);
- Thread.Sleep(ms);
- if (count != sp.BytesToRead)
- {
- end = DateTime.Now.AddMilliseconds(ms);
- count = sp.BytesToRead;
- }
- }
+ //WriteLog("Error " + ex.Message);
+ if (Log != null) Log.Error("DataReceived Error {0}", ex.Message);
}
+ }
+
+ void WaitMore()
+ {
+ var sp = Serial;
- void ProcessReceive(Packet pk)
+ var ms = ByteTimeout;
+ var end = DateTime.Now.AddMilliseconds(ms);
+ var count = sp.BytesToRead;
+ while (sp.IsOpen && end > DateTime.Now)
{
- try
- {
- //if (Packet == null)
- OnReceive(pk);
- //else
- //{
- // // 拆包,多个包多次调用处理程序
- // foreach (var msg in Packet.Parse(pk))
- // {
- // OnReceive(msg);
- // }
- //}
- }
- catch (Exception ex)
+ //Thread.SpinWait(1);
+ Thread.Sleep(ms);
+ if (count != sp.BytesToRead)
{
- if (!ex.IsDisposed()) Log.Error("{0}.OnReceive {1}", PortName, ex.Message);
+ end = DateTime.Now.AddMilliseconds(ms);
+ count = sp.BytesToRead;
}
}
+ }
- private TaskCompletionSource<Packet> _Source;
- /// <summary>处理收到的数据。默认匹配同步接收委托</summary>
- /// <param name="pk"></param>
- internal virtual void OnReceive(Packet pk)
+ void ProcessReceive(IOwnerPacket pk)
+ {
+ try
+ {
+ //if (Packet == null)
+ OnReceive(pk);
+ //else
+ //{
+ // // 拆包,多个包多次调用处理程序
+ // foreach (var msg in Packet.Parse(pk))
+ // {
+ // OnReceive(msg);
+ // }
+ //}
+ }
+ catch (Exception ex)
{
- //// 同步匹配
- //if (Packet != null && Packet.Match(pk, null)) return;
+ if (!ex.IsDisposed()) Log.Error("{0}.OnReceive {1}", PortName, ex.Message);
+ }
+ }
- if (_Source != null)
- {
- _Source.SetResult(pk);
- _Source = null;
- return;
- }
+ private TaskCompletionSource<IOwnerPacket> _Source;
+ /// <summary>处理收到的数据。默认匹配同步接收委托</summary>
+ /// <param name="pk"></param>
+ internal virtual void OnReceive(IOwnerPacket pk)
+ {
+ //// 同步匹配
+ //if (Packet != null && Packet.Match(pk, null)) return;
- // 触发事件
- Received?.Invoke(this, new ReceivedEventArgs { Packet = pk });
+ if (_Source != null)
+ {
+ _Source.SetResult(pk);
+ _Source = null;
+ return;
}
- /// <summary>数据到达事件</summary>
- public event EventHandler<ReceivedEventArgs> Received;
- #endregion
+ // 触发事件
+ Received?.Invoke(this, new ReceivedEventArgs { Packet = pk });
+ }
+
+ /// <summary>数据到达事件</summary>
+ public event EventHandler<ReceivedEventArgs> Received;
+ #endregion
- #region 自动检测串口断开
- /// <summary>断开时触发,可能是人为断开,也可能是串口链路断开</summary>
- public event EventHandler Disconnected;
+ #region 自动检测串口断开
+ /// <summary>断开时触发,可能是人为断开,也可能是串口链路断开</summary>
+ public event EventHandler Disconnected;
- Boolean isInEvent;
- void OnDisconnect()
+ Boolean isInEvent;
+ void OnDisconnect()
+ {
+ if (Disconnected != null)
{
- if (Disconnected != null)
+ // 判断是否在事件中,避免外部在断开时间中调用Close造成死循环
+ if (!isInEvent)
{
- // 判断是否在事件中,避免外部在断开时间中调用Close造成死循环
- if (!isInEvent)
- {
- isInEvent = true;
+ isInEvent = true;
- Disconnected(this, EventArgs.Empty);
+ Disconnected(this, EventArgs.Empty);
- isInEvent = false;
- }
+ isInEvent = false;
}
}
+ }
- TimerX timer;
- /// <summary>检查串口是否已经断开</summary>
- /// <remarks>
- /// FX串口异步操作有严重的泄漏缺陷,如果外部硬件长时间断开,
- /// SerialPort.IsOpen检测不到,并且会无限大占用内存。
- /// </remarks>
- /// <param name="state"></param>
- void CheckDisconnect(Object state)
- {
- if (String.IsNullOrEmpty(PortName) || Serial == null || !Serial.IsOpen) return;
+ TimerX timer;
+ /// <summary>检查串口是否已经断开</summary>
+ /// <remarks>
+ /// FX串口异步操作有严重的泄漏缺陷,如果外部硬件长时间断开,
+ /// SerialPort.IsOpen检测不到,并且会无限大占用内存。
+ /// </remarks>
+ /// <param name="state"></param>
+ void CheckDisconnect(Object state)
+ {
+ if (String.IsNullOrEmpty(PortName) || Serial == null || !Serial.IsOpen) return;
- // 如果端口已经不存在,则断开吧
- if (!SerialPort.GetPortNames().Contains(PortName))
- {
- WriteLog("串口{0}已经不存在,准备关闭!", PortName);
+ // 如果端口已经不存在,则断开吧
+ if (!SerialPort.GetPortNames().Contains(PortName))
+ {
+ WriteLog("串口{0}已经不存在,准备关闭!", PortName);
- //OnDisconnect();
- Close();
- }
+ //OnDisconnect();
+ Close();
}
- #endregion
+ }
+ #endregion
- #region 辅助
- /// <summary>获取带有描述的串口名,没有时返回空数组</summary>
- /// <returns></returns>
- public static String[] GetPortNames()
+ #region 辅助
+ /// <summary>获取带有描述的串口名,没有时返回空数组</summary>
+ /// <returns></returns>
+ public static String[] GetPortNames()
+ {
+ var list = new List<String>();
+ foreach (var item in GetNames())
{
- var list = new List<String>();
- foreach (var item in GetNames())
- {
- list.Add(String.Format("{0}({1})", item.Key, item.Value));
- }
- return list.ToArray();
+ list.Add(String.Format("{0}({1})", item.Key, item.Value));
}
+ return list.ToArray();
+ }
- /// <summary>获取串口列表,名称和描述</summary>
- /// <returns></returns>
- public static Dictionary<String, String> GetNames()
- {
- var dic = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
+ /// <summary>获取串口列表,名称和描述</summary>
+ /// <returns></returns>
+ public static Dictionary<String, String> GetNames()
+ {
+ var dic = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
#if NC30
- foreach (var item in SerialPort.GetPortNames())
- {
- dic.Add(item, "");
- }
+ foreach (var item in SerialPort.GetPortNames())
+ {
+ dic.Add(item, "");
+ }
#else
- using (var key = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DEVICEMAP\SERIALCOMM", false))
- using (var usb = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\USB", false))
+ using (var key = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DEVICEMAP\SERIALCOMM", false))
+ using (var usb = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\USB", false))
+ {
+ if (key != null)
{
- if (key != null)
+ foreach (var item in key.GetValueNames())
{
- foreach (var item in key.GetValueNames())
- {
- var name = key.GetValue(item) + "";
- var des = "";
+ var name = key.GetValue(item) + "";
+ var des = "";
- // 尝试枚举USB串口
- foreach (var vid in usb.GetSubKeyNames())
+ // 尝试枚举USB串口
+ foreach (var vid in usb.GetSubKeyNames())
+ {
+ var usbvid = usb.OpenSubKey(vid);
+ foreach (var elm in usbvid.GetSubKeyNames())
{
- var usbvid = usb.OpenSubKey(vid);
- foreach (var elm in usbvid.GetSubKeyNames())
+ var sub = usbvid.OpenSubKey(elm);
+ //if (sub.GetValue("Class") + "" == "Ports")
{
- var sub = usbvid.OpenSubKey(elm);
- //if (sub.GetValue("Class") + "" == "Ports")
+ var FriendlyName = sub.GetValue("FriendlyName") + "";
+ if (FriendlyName.Contains("({0})".F(name)))
{
- var FriendlyName = sub.GetValue("FriendlyName") + "";
- if (FriendlyName.Contains("({0})".F(name)))
- {
- des = FriendlyName.TrimEnd("({0})".F(name)).Trim();
- break;
- }
+ des = FriendlyName.TrimEnd("({0})".F(name)).Trim();
+ break;
}
}
- if (!des.IsNullOrEmpty()) break;
- }
-
- // 最后选择设备映射的串口名
- if (des.IsNullOrEmpty())
- {
- des = item;
- var p = item.LastIndexOf('\\');
- if (p >= 0) des = des.Substring(p + 1);
}
+ if (!des.IsNullOrEmpty()) break;
+ }
- //dic.Add(name, des);
- // 某台机器上发现,串口有重复
- dic[name] = des;
+ // 最后选择设备映射的串口名
+ if (des.IsNullOrEmpty())
+ {
+ des = item;
+ var p = item.LastIndexOf('\\');
+ if (p >= 0) des = des.Substring(p + 1);
}
+
+ //dic.Add(name, des);
+ // 某台机器上发现,串口有重复
+ dic[name] = des;
}
}
+ }
#endif
- return dic;
- }
+ return dic;
+ }
- /// <summary>从串口列表选择串口,支持自动选择关键字</summary>
- /// <param name="keyWord">串口名称或者描述符的关键字</param>
- /// <returns></returns>
- public static SerialTransport Choose(String keyWord = null)
+ /// <summary>从串口列表选择串口,支持自动选择关键字</summary>
+ /// <param name="keyWord">串口名称或者描述符的关键字</param>
+ /// <returns></returns>
+ public static SerialTransport Choose(String keyWord = null)
+ {
+ var ns = GetNames();
+ if (ns.Count == 0)
{
- var ns = GetNames();
- if (ns.Count == 0)
- {
- Console.WriteLine("没有可用串口!");
- return null;
- }
-
- var name = "";
- var des = "";
+ Console.WriteLine("没有可用串口!");
+ return null;
+ }
- Console.WriteLine("可用串口:");
- Console.ForegroundColor = ConsoleColor.Green;
- foreach (var item in ns)
- {
- if (item.Value == "Serial0") continue;
+ var name = "";
+ var des = "";
- if (keyWord != null && (item.Key.EqualIgnoreCase(keyWord) || item.Value.Contains(keyWord)))
- {
- name = item.Key;
- des = item.Value;
- }
+ Console.WriteLine("可用串口:");
+ Console.ForegroundColor = ConsoleColor.Green;
+ foreach (var item in ns)
+ {
+ if (item.Value == "Serial0") continue;
- //Console.WriteLine(item);
- Console.WriteLine("{0,5}({1})", item.Key, item.Value);
- }
- // 没有自动选择,则默认最后一个
- if (name.IsNullOrEmpty())
+ if (keyWord != null && (item.Key.EqualIgnoreCase(keyWord) || item.Value.Contains(keyWord)))
{
- var item = ns.Last();
name = item.Key;
des = item.Value;
}
- while (true)
- {
- Console.ResetColor();
- Console.Write("请输入串口名称(默认 ");
- Console.ForegroundColor = ConsoleColor.Red;
- Console.Write("{0}", name);
- Console.ResetColor();
- Console.Write("):");
-
- var str = Console.ReadLine();
- if (str.IsNullOrEmpty()) break;
-
- // 只有输入有效串口名称才行
- if (ns.ContainsKey(str))
- {
- name = str;
- des = ns[str];
- break;
- }
- }
-
- Console.WriteLine();
- Console.Write("正在打开串口 ");
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine("{0}({1})", name, des);
+ //Console.WriteLine(item);
+ Console.WriteLine("{0,5}({1})", item.Key, item.Value);
+ }
+ // 没有自动选择,则默认最后一个
+ if (name.IsNullOrEmpty())
+ {
+ var item = ns.Last();
+ name = item.Key;
+ des = item.Value;
+ }
+ while (true)
+ {
+ Console.ResetColor();
+ Console.Write("请输入串口名称(默认 ");
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.Write("{0}", name);
Console.ResetColor();
+ Console.Write("):");
- var sp = new SerialTransport
- {
- PortName = name
- };
+ var str = Console.ReadLine();
+ if (str.IsNullOrEmpty()) break;
- return sp;
+ // 只有输入有效串口名称才行
+ if (ns.ContainsKey(str))
+ {
+ name = str;
+ des = ns[str];
+ break;
+ }
}
- #endregion
- #region 日志
- /// <summary>日志对象</summary>
- public ILog Log { get; set; } = Logger.Null;
+ Console.WriteLine();
+ Console.Write("正在打开串口 ");
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine("{0}({1})", name, des);
- /// <summary>输出日志</summary>
- /// <param name="format"></param>
- /// <param name="args"></param>
- public void WriteLog(String format, params Object[] args)
- {
- if (Log != null && Log.Enable) Log.Info(format, args);
- }
+ Console.ResetColor();
- /// <summary>已重载</summary>
- /// <returns></returns>
- public override String ToString()
+ var sp = new SerialTransport
{
- if (!String.IsNullOrEmpty(PortName))
- return PortName;
- else
- return "(SerialPort)";
- }
+ PortName = name
+ };
+
+ return sp;
+ }
+ #endregion
+ #region 日志
+ /// <summary>日志对象</summary>
+ public ILog Log { get; set; } = Logger.Null;
- #endregion
+ /// <summary>输出日志</summary>
+ /// <param name="format"></param>
+ /// <param name="args"></param>
+ public void WriteLog(String format, params Object[] args)
+ {
+ if (Log != null && Log.Enable) Log.Info(format, args);
}
+
+ /// <summary>已重载</summary>
+ /// <returns></returns>
+ public override String ToString()
+ {
+ if (!String.IsNullOrEmpty(PortName))
+ return PortName;
+ else
+ return "(SerialPort)";
+ }
+
+
+ #endregion
}
\ No newline at end of file
diff --git a/XCoder/XNet/BenchHelper.cs b/XCoder/XNet/BenchHelper.cs
index 51bbda4..0ede2cb 100644
--- a/XCoder/XNet/BenchHelper.cs
+++ b/XCoder/XNet/BenchHelper.cs
@@ -10,29 +10,28 @@ using NewLife.Threading;
using TaskEx = System.Threading.Tasks.Task;
#endif
-namespace XCoder.XNet
+namespace XCoder.XNet;
+
+static class BenchHelper
{
- static class BenchHelper
+ /// <summary>异步多次发送数据</summary>
+ /// <param name="session">会话</param>
+ /// <param name="pk">数据包</param>
+ /// <param name="times">次数</param>
+ /// <param name="msInterval">间隔</param>
+ /// <returns></returns>
+ public static Task SendConcurrency(this ISocketRemote session, IPacket pk, Int32 times, Int32 msInterval)
{
- /// <summary>异步多次发送数据</summary>
- /// <param name="session">会话</param>
- /// <param name="pk">数据包</param>
- /// <param name="times">次数</param>
- /// <param name="msInterval">间隔</param>
- /// <returns></returns>
- public static Task SendConcurrency(this ISocketRemote session, Packet pk, Int32 times, Int32 msInterval)
+ var task = TaskEx.Run(async () =>
{
- var task = TaskEx.Run(async () =>
+ for (var i = 0; i < times; i++)
{
- for (var i = 0; i < times; i++)
- {
- session.Send(pk);
+ session.Send(pk);
- await TaskEx.Delay(msInterval);
- }
- });
+ await TaskEx.Delay(msInterval);
+ }
+ });
- return task;
- }
+ return task;
}
}
\ No newline at end of file
diff --git a/XCoder/XNet/FrmMain.cs b/XCoder/XNet/FrmMain.cs
index 8987b24..28718bb 100644
--- a/XCoder/XNet/FrmMain.cs
+++ b/XCoder/XNet/FrmMain.cs
@@ -377,7 +377,7 @@ namespace XNet
// 处理换行
str = str.Replace("\n", "\r\n");
var buf = cfg.HexSend ? str.ToHex() : str.GetBytes();
- var pk = new Packet(buf);
+ var pk = new ArrayPacket(buf);
if (_Client != null)
{
@@ -418,7 +418,7 @@ namespace XNet
for (var i = 0; i < count && _Server != null; i++)
{
var sw = Stopwatch.StartNew();
- var cs = await _Server.SendAllAsync(buf);
+ var cs = await _Server.SendAllAsync(pk);
sw.Stop();
BizLog.Info("{3}/{4} 已向[{0}]个客户端发送[{1}]数据 {2:n0}ms", cs, buf.Length, sw.ElapsedMilliseconds, i + 1, count);
if (sleep > 0) await TaskEx.Delay(sleep);
diff --git a/XCoder/XNet/FrmMqtt.cs b/XCoder/XNet/FrmMqtt.cs
index bdf2038..7cbc9c1 100644
--- a/XCoder/XNet/FrmMqtt.cs
+++ b/XCoder/XNet/FrmMqtt.cs
@@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Forms;
using NewLife;
+using NewLife.Data;
using NewLife.Log;
using NewLife.MQTT;
using NewLife.MQTT.Messaging;
diff --git a/XCoderLinux/SharpApp.cs b/XCoderLinux/SharpApp.cs
index 27c240b..bbddba5 100644
--- a/XCoderLinux/SharpApp.cs
+++ b/XCoderLinux/SharpApp.cs
@@ -63,7 +63,7 @@ namespace XCoder
var asm = AssemblyX.Create(Assembly.GetExecutingAssembly());
if (set.Title.IsNullOrEmpty()) set.Title = asm.Title;
- _title = Title = String.Format("{2} v{0} {1:HH:mm:ss}", asm.CompileVersion, asm.Compile, set.Title);
+ _title = Title = String.Format("{2} v{0} {1:HH:mm:ss}", asm.FileVersion, asm.Compile, set.Title);
_load.ContinueWith(t => LoadForms(t.Result));
diff --git a/XCoderLinux/Util/ControlHelper.cs b/XCoderLinux/Util/ControlHelper.cs
index 75668cd..508ae01 100644
--- a/XCoderLinux/Util/ControlHelper.cs
+++ b/XCoderLinux/Util/ControlHelper.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Gtk;
+using NewLife;
namespace XCoder.Util
{
diff --git a/XCoderLinux/XCoderLinux.csproj b/XCoderLinux/XCoderLinux.csproj
index 8893159..e3ebb46 100644
--- a/XCoderLinux/XCoderLinux.csproj
+++ b/XCoderLinux/XCoderLinux.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
- <TargetFrameworks>net5.0;netcoreapp3.1</TargetFrameworks>
+ <TargetFrameworks>net8.0</TargetFrameworks>
<AssemblyName>XCoder</AssemblyName>
<RootNamespace>XCoder</RootNamespace>
<AssemblyTitle>新生命码神工具</AssemblyTitle>
@@ -14,7 +14,9 @@
<AssemblyVersion>8.0.*</AssemblyVersion>
<Deterministic>false</Deterministic>
<ApplicationIcon>..\XCoder\leaf.ico</ApplicationIcon>
- <OutputPath>..\..\XCoderLinux\</OutputPath>
+ <OutputPath>..\Bin\XCoderLinux\</OutputPath>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <LangVersion>latest</LangVersion>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<DefineConstants>TRACE;NC30;__CORE__</DefineConstants>
@@ -48,8 +50,9 @@
<ItemGroup>
<PackageReference Include="GtkSharp" Version="3.24.24.34" />
- <PackageReference Include="NewLife.Core" Version="10.10.2024.803" />
- <PackageReference Include="NewLife.XCode" Version="11.15.2024.806" />
+ <PackageReference Include="NewLife.Core" Version="11.5.2025.501" />
+ <PackageReference Include="NewLife.Stardust" Version="3.3.2025.506" />
+ <PackageReference Include="NewLife.XCode" Version="11.19.2025.501" />
<PackageReference Include="System.IO.Ports" Version="6.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" />
</ItemGroup>
diff --git a/XCoderLinux/XCom/SerialPortList.cs b/XCoderLinux/XCom/SerialPortList.cs
index c24b074..e742e15 100644
--- a/XCoderLinux/XCom/SerialPortList.cs
+++ b/XCoderLinux/XCom/SerialPortList.cs
@@ -7,6 +7,7 @@ using System.IO.Ports;
using System.Linq;
using System.Text;
using Gtk;
+using NewLife.Data;
using NewLife.Log;
using NewLife.Net;
using NewLife.Threading;
@@ -451,7 +452,7 @@ namespace NewLife.Windows
StreamReader _reader;
void OnReceived(Object sender, ReceivedEventArgs e)
{
- var data = e.Packet.ReadBytes();
+ var data = e.Packet.ReadBytes(0, -1);
if (data == null || data.Length < 1) return;
BytesOfReceived += data.Length;
diff --git a/XCoderLinux/XNet/FrmMain.cs b/XCoderLinux/XNet/FrmMain.cs
index 77b69f3..9c879dc 100644
--- a/XCoderLinux/XNet/FrmMain.cs
+++ b/XCoderLinux/XNet/FrmMain.cs
@@ -426,7 +426,7 @@ namespace XNet
for (var i = 0; i < count && _Server != null; i++)
{
var sw = Stopwatch.StartNew();
- var cs = await _Server.SendAllAsync(buf);
+ var cs = await _Server.SendAllAsync(pk);
sw.Stop();
BizLog.Info("{3}/{4} 已向[{0}]个客户端发送[{1}]数据 {2:n0}ms", cs, buf.Length, sw.ElapsedMilliseconds, i + 1, count);
if (sleep > 0) await TaskEx.Delay(sleep);
diff --git a/XCoderWpf/XCoderWpf.csproj b/XCoderWpf/XCoderWpf.csproj
index bf963b4..be04b10 100644
--- a/XCoderWpf/XCoderWpf.csproj
+++ b/XCoderWpf/XCoderWpf.csproj
@@ -31,7 +31,7 @@
<ItemGroup>
<PackageReference Include="HandyControls" Version="3.3.9" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="4.0.0" />
- <PackageReference Include="NewLife.XCode" Version="11.15.2024.806" />
+ <PackageReference Include="NewLife.XCode" Version="11.19.2025.501" />
<PackageReference Include="Prism.DryIoc" Version="8.1.97" />
</ItemGroup>
diff --git "a/\347\240\201\347\245\236\345\267\245\345\205\267.sln" "b/\347\240\201\347\245\236\345\267\245\345\205\267.sln"
index 2ef2e56..b65083c 100644
--- "a/\347\240\201\347\245\236\345\267\245\345\205\267.sln"
+++ "b/\347\240\201\347\245\236\345\267\245\345\205\267.sln"
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29318.209
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36109.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Others", "Others", "{32891F65-FBA1-42B2-918E-61F3A9623F2A}"
ProjectSection(SolutionItems) = preProject
@@ -18,8 +18,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrazyCoder", "CrazyCoder\Cr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XCoderWpf", "XCoderWpf\XCoderWpf.csproj", "{405D4D22-FF61-4796-A3F2-222CFDA326D2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XCoder40", "XCoder40\XCoder40.csproj", "{A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -132,30 +130,6 @@ Global
{405D4D22-FF61-4796-A3F2-222CFDA326D2}.Release|x64.Build.0 = Release|Any CPU
{405D4D22-FF61-4796-A3F2-222CFDA326D2}.Release|x86.ActiveCfg = Release|Any CPU
{405D4D22-FF61-4796-A3F2-222CFDA326D2}.Release|x86.Build.0 = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|ARM.Build.0 = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|iPhone.Build.0 = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|x64.ActiveCfg = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|x64.Build.0 = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Debug|x86.Build.0 = Debug|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|Any CPU.Build.0 = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|ARM.ActiveCfg = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|ARM.Build.0 = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|iPhone.ActiveCfg = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|iPhone.Build.0 = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|x64.ActiveCfg = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|x64.Build.0 = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|x86.ActiveCfg = Release|Any CPU
- {A4A7E1BD-9E53-4D60-A0E0-122E5441DDBF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE