串口问题

发布于 2024-09-09 06:33:45 字数 483 浏览 5 评论 0原文

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

我已经安装了驱动程序来与读卡器一起操作,就像它是通过 Com 端口连接一样,尽管它是一个 USB 设备。插入设备后,列表中会出现另一个 Com 端口。

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

当程序关闭时,结果是 WinIOException。我不仅在使用 SerialPort 的代码中无法捕获它,而且在 program.cs 级别也无法捕获它。根据堆栈,在尝试完成和处置 SerialPort 对象后会引发 WinIOException。

我有什么想法可以如何正确处理这种情况?或者至少捕获异常?

我可以肯定的是,问题不在于这个特定的驱动程序;而是在于这个特定的驱动程序。我又从另一家制造商那里得到了一个条形码阅读器(具有相同用途的驱动程序) - 情况是一样的。

I'm working with SerialPort to communicate (read only) with barcode reader.

I've installed driver to operate with the reader as if it was connected via Com-port, though it is a usb device. When the device is plugged, one more Com-port appears in the list.

The problem is the following. I initialize the SerialPort object to read from barcode reader, but if the reader is unplugged, I have no way to finalize or dispose the SerialPort object correctly, because the port it is "attached" to no longer exists.

The result is WinIOException when the program is closed. I cannot catch it not only in the code working with the SerialPort but at the program.cs level as well. According to the stack WinIOException is thrown after the attempts of finalizing and disposing the SerialPort object.

Are there any ideas how I can operate with this situation properly? Or at least to catch the exception?

The thing I know for sure is that the problem is not in this particular driver; I had one more barcode reader from another manufacturer (with the same purpose driver) - the situation is the same.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

小鸟爱天空丶 2024-09-16 06:33:45

唉,这是 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>

不要使用它。

Sigh, this an age old problem with USB serial port emulators. Serial ports are devices that date from the stone age. They used to be screwed into the bus, no way to remove them while a program is using it without drawing sparks and billowing smoke. Stone age also includes the lack for any kind of plug-and-play support so that a program could detect that the device is suddenly gonzo.

Unfortunately, the majority of the crummy device drivers that emulate them just make them disappear, even though a program has the port opened. This works just about as well as jerking a flash drive out of the socket when Windows is writing files to it. There's a background worker thread that waits for notifications from the device driver so that it can generate the DataReceived, ErrorReceived and PinChanged events. That thread suffers a heart attack when the device suddenly disappears. You can't catch that, it is a thread that was started by the SerialPort class, you can't wrap it with try/catch.

By popular demand, Microsoft did something about it in .NET 4.0. Not actually sure what happens in that release. If you're stuck on an earlier release, the only reasonable thing you can do is tape a sign next to the USB slot: "Don't remove while in use!" Which inevitably makes somebody unplug the device at least twice to see what happens. After which they get bored with that and leave you in peace.

The very unreasonable workaround is an app.exe.config file with this content:

<?xml version ="1.0"?>
<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
  </runtime>
</configuration>

Don't use it.

萤火眠眠 2024-09-16 06:33:45

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

因此,如果继承.NET SerialPort类并重写Open / Close,则可以执行以下操作:

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

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

如果 USB 已拔出,这将抛出异常,抱怨对 BaseStream 的访问。在调用 GC 之前检查 .IsOpen 属性,或者将其包装在 Try Catch 中(如果不这样做)不要相信 .IsOpen 每次都会返回 False...

这样就可以解决问题,您的应用程序将处理它已被拉出的事实,并且当您关闭时它不会崩溃。

我目前无法在重新插入端口后重新打开端口,但至少除了标签上写着“请勿触摸”之外,还有一些进展......

In my code, this happens as part of the Finalize() method on the BaseStream, which is called by the garbage collector.

As such, if one inherits the .NET SerialPort class and overrides the Open / Close, you can do the following:

During the Open, just call GC.SuppressFinalize(Me.BaseStream)

During the close, try to call GC.ReRegisterForFinalize(Me.BaseStream)

If the USB has been pulled out, this will throw an exception, moaning about access to the BaseStream. Either check the .IsOpen property before calling the GC, or wrap it in a Try Catch if you don't trust .IsOpen to return False every time...

That'll sort it out, your application will handle the fact that it's been pulled out, and it won't crash when you close.

I'm currently unable to make it then re-open the port if it's plugged back in, but at least there's some progress beyond a label saying don't touch...

抱猫软卧 2024-09-16 06:33:45

您可以继承 SerialPort 并重写 Dispose() 方法来处理此类异常。你可以直接吞噬异常(Dispose 无论如何都不应该抛出)。

如果您想记录异常或以其他方式处理它,则必须首先检查处理标志。如果为 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
                }
            }

        }
    }

You can inherit from SerialPort and override the Dispose() method to handle such exceptions. You can just gobble the exception (Dispose shouldn't be throwing anyway).

If you want to log the exception or handle it in some other way, you will have to check the disposing flag first. If it is false it means that Dispose was called by SerialPort's destructor and the object is already orphaned.

E.g.

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

        }
    }
一萌ing 2024-09-16 06:33:45

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

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);
        }
    }
}

I solved this problem by creating a separate process which handles the serial port. When the serial port is unplugged I restart the process. Now I can reconnect to a unplugged serial port device without restarting the main application.

TLDR; Create a separate process.

Example code

Serial port process code

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);
        }
    }
}

Main application

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);
        }
    }
}
染年凉城似染瑾 2024-09-16 06:33:45

嗯,坏消息。

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

.Net 4.0 也没有帮助。我已经安装了 VS2010 - 没有任何改变。仍会引发未处理的异常。不幸的是,“在 USB 插槽旁边贴上一个标志:“使用时请勿移除!”似乎是唯一的决定......

Well, bad news.

Solution by Panagiotis Kanavos does not help. The problem is still here.

.Net 4.0 doesn't help either. I've installed VS2010 - nothing changed. The unhadled exception is still thrown. Unfortunately, "tape a sign next to the USB slot: "Don't remove while in use!" seems to be the only decision...

十雾 2024-09-16 06:33:45

我也有过同样的经历。尽管不建议这样做,但您可以将串行设备拔出并插入到实际的串行端口,通信将重新开始。 USB 串行端口不能以这种方式工作。我还遇到过这样的问题:在软件实例化虚拟串行端口之前,USB 串行端口不会通过 SerialPort.GetPortNames() 方法显示为可用端口。

I've had the same experience. Although it is not advised, you can unplug and plugin a serial device to an actual serial port and the communication will begin again. A USB serial port doesn't work this way. I've also had the problem of the USB serial port not appearing as an available port by the SerialPort.GetPortNames() method until after the virtual serial port is instantiated by the software.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文