我正在使用SerialPort与条形码阅读器进行通信(只读)。
我已经安装了驱动程序来操作阅读器,就好像它是通过Com-port连接的,虽然它是一个usb设备。插入设备后,列表中会再出现一个Com-port。
问题如下。我初始化SerialPort对象以从条形码阅读器读取,但如果读取器被拔掉,我无法正确完成或处置SerialPort对象,因为它“附加”的端口不再存在。
程序关闭时,结果是WinIOException。我不仅在使用SerialPort的代码中捕获它,而且在program.cs级别也是如此。根据堆栈,在尝试完成并处理SerialPort对象后抛出WinIOException。
我有什么想法可以正确操作这种情况吗?或者至少要抓住例外?
我确切知道的是问题不在这个特定的驱动程序中;我还有一个来自其他制造商的条形码阅读器(具有相同目的的驱动程序) - 情况是一样的。
答案 0 :(得分:12)
叹息,这是USB串口仿真器的老问题。串行端口是可以追溯到石器时代的设备。它们曾经被拧入公共汽车,当程序使用它时没有办法将它们移除而不会产生火花和滚滚浓烟。石器时代还包括缺少任何类型的即插即用支持,以便程序可以检测到该设备突然是奇闻趣事。
不幸的是,即使程序打开了端口,大多数模仿它们的软件设备驱动程序也会使它们消失。当Windows向其中写入文件时,这与将插槽中的闪存驱动器冲出一样有效。有一个后台工作线程等待来自设备驱动程序的通知,以便它可以生成DataReceived,ErrorReceived和PinChanged事件。当设备突然消失时,该线程会遭受心脏病发作。你无法理解,它是一个由SerialPort类启动的线程,你不能用try / catch包装它。
根据大众的需求,微软在.NET 4.0中做了一些事情。实际上并不确定该版本中会发生什么。如果您坚持使用早期版本,那么您可以做的唯一合理的事情是在USB插槽旁边粘贴一个标记:“请勿在使用时移除!”这不可避免地会让某人至少两次拔掉设备,看看会发生什么。之后他们对此感到厌倦,让你平静下来。
非常不合理的解决方法是包含以下内容的app.exe.config文件:
<?xml version ="1.0"?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
</configuration>
不要使用它。
答案 1 :(得分:5)
在我的代码中,这是作为BaseStream上Finalize()
方法的一部分发生的,该方法由垃圾收集器调用。
因此,如果继承.NET SerialPort类并覆盖Open / Close,则可以执行以下操作:
在公开期间,只需致电GC.SuppressFinalize(Me.BaseStream)
在结束时,请尝试拨打GC.ReRegisterForFinalize(Me.BaseStream)
如果已经拔出USB,这将引发异常,抱怨访问BaseStream。如果您不信任.IsOpen
每次都返回False,请在调用GC
之前检查Try
属性,或将其包装在Catch
.IsOpen
中。 ..
这将解决它,你的应用程序将处理它已被拔出的事实,并且当你关闭时它不会崩溃。
我目前无法制作它然后重新打开端口,如果它重新插入,但至少有一些进展超出标签说不要触摸......
答案 2 :(得分:2)
您可以从SerialPort继承并重写Dispose()方法来处理此类异常。你可以只吞噬异常(Dispose不应该抛出)。
如果要记录异常或以其他方式处理异常,则必须先检查 disposing 标志。如果为false,则意味着Dispose由SerialPort的析构函数调用,并且该对象已经是孤立的。
E.g。
public class MySerialPort:SerialPort
{
protected override void Dispose(bool disposing)
{
try
{
base.Dispose(disposing);
}
catch (Exception exc )
{
if (disposing)
{
//Log the error
}
}
}
}
答案 3 :(得分:1)
我通过创建一个处理串口的独立进程解决了这个问题。拔下串口后,重新启动该过程。现在,我可以重新连接到未插入的串行端口设备,而无需重新启动主应用程序。
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);
}
}
}
答案 4 :(得分:0)
Panagiotis Kanavos的解决方案没有帮助。问题仍然存在。
.Net 4.0也没有帮助。我安装了VS2010 - 没有任何改变。仍然抛出未加扰的异常。不幸的是,“在USB插槽旁边贴一个标志:”在使用时不要移除!“似乎是唯一的决定......
答案 5 :(得分:0)
我有同样的经历。虽然不建议,但您可以将串行设备拔出并插入实际的串行端口,然后再次开始通信。 USB串口不能以这种方式工作。我还遇到了串行端口没有被SerialPort.GetPortNames()方法显示为可用端口的问题,直到虚拟串口被软件实例化为止。