SerialPort问题

我正在使用SerialPort与条形码阅读器进行通信(只读)。

我已经安装了驱动程序来操作阅读器,就好像它是通过Com-port连接的,虽然它是一个usb设备。 插入设备后,列表中会再出现一个Com-port。

问题如下。 我初始化SerialPort对象以从条形码阅读器读取,但如果读取器被拔掉,我无法正确完成或处置SerialPort对象,因为它“附加”的端口不再存在。

程序关闭时,结果是WinIOException。 我不仅在使用SerialPort的代码中捕获它,而且在program.cs级别也是如此。 根据堆栈,在尝试完成和处理SerialPort对象后抛出WinIOException。

有没有想法如何正确操作这种情况? 或者至少要抓住例外?

我确切知道的是问题不在于这个特定的驱动程序; 我还有一个来自另一个制造商的条形码阅读器(具有相同的目的驱动程序) – 情况是相同的。

叹了口气,这是USB串口仿真器的老问题。 串行端口是可以追溯到石器时代的设备。 它们曾经被拧入公共汽车,当程序使用它时没有办法将它们移除而不会产生火花和滚滚浓烟。 石器时代还包括缺乏任何类型的即插即用支持,以便程序可以检测到该设备突然是奇闻趣事。

不幸的是,即使程序打开了端口,大多数模仿它们的软件设备驱动程序也会使它们消失。 当Windows向其中写入文件时,这与将插槽中的闪存驱动器冲出来的效果差不多。 有一个后台工作线程等待来自设备驱动程序的通知,以便它可以生成DataReceived,ErrorReceived和PinChanged事件。 当设备突然消失时,该线程遭受心脏病发作。 你无法理解,它是一个由SerialPort类启动的线程,你不能用try / catch包装它。

根据大众的需求,微软在.NET 4.0中做了一些事情。 实际上并不确定该版本中会发生什么。 如果您坚持使用早期版本,那么您可以做的唯一合理的事情是在USB插槽旁边粘贴一个标记:“请勿在使用时移除!” 这不可避免地使某人至少两次拔掉设备,看看会发生什么。 之后他们对此感到厌倦,让你平静下来。

非常不合理的解决方法是带有以下内容的app.exe.config文件:

      

不要使用它。

在我的代码中,这发生在BaseStream上的Finalize()方法的一部分,该方法由垃圾收集器调用。

因此,如果inheritance.NET SerialPort类并覆盖打开/关闭,则可以执行以下操作:

在打开期间,只需调用GC.SuppressFinalize(Me.BaseStream)

在关闭期间,尝试调用GC.ReRegisterForFinalize(Me.BaseStream)

如果已经拔出USB,这将引发exception,抱怨访问BaseStream。 在调用GC之前检查.IsOpen属性,或者如果不信任.IsOpen其包装在Try Catch .IsOpen每次都返回False …

这将解决它,你的应用程序将处理它被拉出的事实,并且当你关闭时它不会崩溃。

我目前无法制作它然后重新打开端口,如果它重新插入,但至少有一些进展超出标签说不要触摸…

您可以从SerialPortinheritance并重写Dispose()方法来处理此类exception。 你可以只是吞噬exception(无论如何不应该抛弃Dispose)。

如果要记录exception或以其他方式处理exception,则必须首先检查处置标志。 如果为false,则意味着Dispose由SerialPort的析构函数调用,并且该对象已经是孤立的。

例如

  public class MySerialPort:SerialPort { protected override void Dispose(bool disposing) { try { base.Dispose(disposing); } catch (Exception exc ) { if (disposing) { //Log the error } } } } 

嗯,坏消息。

Panagiotis Kanavos的解决方案没有帮助。 问题仍然存在。

.Net 4.0也没有帮助。 我已经安装了VS2010 – 没有任何改变。 仍然抛出了未加扰的exception。 不幸的是,“在USB插槽旁边贴一个标志:”在使用时不要移除!“似乎是唯一的决定……

我有同样的经历。 虽然不建议,但您可以将串行设备拔出并插入实际的串行端口,然后再次开始通信。 USB串口不能以这种方式工作。 我还遇到了串行端口没有被SerialPort.GetPortNames()方法显示为可用端口的问题,直到虚拟串口被软件实例化为止。

我通过创建一个处理串口的独立进程解决了这个问题。 拔下串口后,重新启动该过程。 现在我可以重新连接到未插入的串行端口设备,而无需重新启动主应用程序。

TLDR; 创建一个单独的流程。

示例代码

串口进程代码

 static void Main(string[] args) { using (var output = Console.OpenStandardOutput()) using (var serialPort = new SerialPort(args[0], int.Parse(args[1]))) { serialPort.Open(); while (serialPort.IsOpen) { serialPort.BaseStream.CopyTo(output); } } } 

主要应用

 var options = new ProcessStartInfo() { FileName = "Serial Port Process name here", UseShellExecute = false, RedirectStandardOutput = true, }; using(var process = Process.Start(options)) { using (StreamReader reader = process.StandardOutput) { while (!process.HasExited) { string result = reader.ReadLine(); Console.WriteLine(result); } } }