SerialPort问题

时间:2010-07-12 16:36:30

标签: c# usb serial-port

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

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

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

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

我有什么想法可以正确操作这种情况吗?或者至少要抓住例外?

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

6 个答案:

答案 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()方法显示为可用端口的问题,直到虚拟串口被软件实例化为止。