c# - 释放未插入的虚拟串行端口

标签 c# serial-port usb barcode

USB条码扫描器出现了一些问题。
我在“SerialPort”类中使用扫描仪:

        this._barcodeScanner = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One) { Handshake = Handshake.None, ReadTimeout = 500, WriteTimeout = 500 };
        this._barcodeScanner.Open();
        this._barcodeScanner.DataReceived += BarcodeScannerCallback;

如果在通过“SerialPort”类打开USB设备时拔出USB设备,我将无法正确关闭软件,并且虚拟端口将一直保持打开状态,直到我重新启动整个计算机为止。

所以我的问题是,通过C#代码拔出设备后,是否可以关闭虚拟端口?

问候

[编辑#1]

好的,更多代码:

这样,我每隔10秒检查一次设备是否插入:
    private bool CheckUsbDeviceAvailability()
    {
        ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI",
        "SELECT * FROM MSSerial_PortName WHERE PortName = '" + this.PortName + "'");

        if (searcher.Get().Count > 0)
            return true;
        return false;
    }

多数民众赞成在串行端口的回调事件:
void BarcodeScannerCallback(object sender, SerialDataReceivedEventArgs e)
    {
        Thread.Sleep(500);
        string data = this._barcodeScanner.ReadExisting().Replace(Convert.ToChar(2), Convert.ToChar(32)).Trim();
        if (data.StartsWith("AX"))
        {
            string[] arrData = data.Split('\n');
            this._barcodeScanner.StopAvailabilityThread();
            Barcode code = new Barcode(arrData[0].Replace("\r", ""));

            if (CheckIfBarcodeExists(code))
                this.UpdateBarcodeNode(code);
            else
                this.CreateBarcodeNode(code);

            BarcodeScannerCallbackEvent(sender, e, code);
            this._barcodeScanner.StartAvailabilityThread();
        }

        this._barcodeScanner.ComDevicePluggedIn = ScannerDevice.ComAvailabilityState.Available;
    }

如果不再回答,则将触发“DeviceNotAvailableEvent()”:
    void BarcodeScannerDeviceNotAvailableEvent()
    {
        this._barcodeScanner.Close();
        this._barcodeScanner.Dispose();
    }

我已经覆盖了“SerialPort”类的Dispose事件,以便它将中止线程:
protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            this._deviceAvailableThread.Abort();

        }

        base.Dispose(isDisposing);
    }

最佳答案

串行端口可追溯到计算的石器时代。那就是您插入ASR-33电传打字机以开始输入Fortran程序的地方。电气接口(interface)非常简单。 Windows API也可以使用您自己的代码中的串行端口。实际上,任何运行时环境都支持它们。

USB已完全取代了串行端口硬件。它具有到计算机的更高级的逻辑接口(interface),支持许多不同类型的设备。并且它支持即插即用,允许操作系统检测何时连接或卸下设备以及自动安装设备驱动程序等。

这种灵活性是有代价的,但是,USB设备始终需要设备驱动程序才能使用。设备驱动程序创建不相等。不同的驱动程序要求使用不同的方式与设备对话。通常通过DeviceIoControl()或Read/WriteFile()完成,但是这些都是非常不透明的API函数。在USB的早期,设备制造商将提供一个DLL,该DLL提供了丰富的API以隐藏实现细节。

效果不是很好,制造商不太擅长编写好的API,他们肯定不喜欢支持它们。因此,一个好的解决方案是支持一种标准API,该标准可在任何计算机上使用,由任何运行时支持,由其他人记录和维护。就像串口API一样。

效果不是很好,制造商并不擅长编写模拟串行端口的设备驱动程序。 API的最大缺点是它不支持即插即用。在所有串行端口硬件都没有逻辑接口(interface)来支持它之后,缺少对它的核心支持。支持检测通过DTR硬件握手线路连接的设备,但不支持检测端口不再存在的任何支持。

拆卸USB设备是问题所在。在理想情况下,设备驱动程序中内置的仿真器会简单地假装串行端口仍然存在,直到关闭设备上的最后一个句柄为止。考虑到无法触发即插即用事件,这将是逻辑上的实现。由于某些奇怪的原因,似乎难以实现。大多数USB驱动程序都采用了愚蠢的快捷方式,即使使设备处于使用状态,它们也只会使设备消失。

这会对使用该设备的任何用户模式代码造成严重破坏。通常在编写时假定它是一个真实的串行端口,并且真实的串行端口不会突然消失。至少不是没有画出明亮的蓝色 Spark 。出问题的原因几乎是无法预测的,因为这取决于驱动程序如何响应不再存在的设备上的请求。由SerialPort启动的工作线程中发生无法捕获的异常是常见的事故。听起来您的驱动程序确实出错了,它会在MJ_CLOSE驱动程序请求中生成错误返回码。对于驱动程序来说,这样做是合乎逻辑的事情,毕竟设备已经不存在了,但是从您的角度来看这是完全无法解决的。您有一个 handle ,无法将其关闭。那是一条没有桨的小河。

.NET的每个主要发行版都为SerialPort类提供了一个小补丁,以尝试最大程度地减少痛苦。但是,Microsoft只能做的事情有限,发现所有错误并假装它们没有发生,最终导致该类不再提供良好的诊断,即使使用了良好的驱动程序也是如此。

所以实际的方法是:

  • 始终使用Windows中的“安全删除硬件”托盘图标
  • 使用最新版本的.NET
  • 与供应商联系,并请求驱动程序更新
  • 提供糟糕驱动程序的沟渠供应商
  • 告诉您的用户,仅因为这是您可以使用USB设备执行的唯一操作,所以拔出它并不能解决任何问题
  • 使关闭端口变得容易并且可以在用户界面中访问
  • 将USB连接器粘在端口上,以便无法将其删除

  • 第五点也是给程序员带来麻烦的原因。编写串行端口代码并不容易,它是高度异步的,并且运行DataReceived事件的线程池线程很难处理。当您无法诊断软件问题时,您往往会把责任归咎于硬件。您只能使用很少的硬件才能将其拔出。馊主意。现在您有两个问题。

    关于c# - 释放未插入的虚拟串行端口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9835881/

    相关文章:

    linux - 串行读/写/dev/tty 检查

    c# - ScintillaNET 中的缩进和智能缩进

    c# - C# 中扩展方法和方法之间的区别

    c# - 最新版本的 Unity 和 Google 无法生成 APK 构建并显示 Android Manifestation 脚本错误

    c# - 是否可以使用带有内部连接的 ef core 5 运行原始 sql 并将数据具体化为一个类?

    linux - 用于 usb 设备/dev/sdb 的 opendir

    c# - 如何将这些 DCB 结构设置从 C 映射到 C# SerialPort 类

    c# - 如何使用 .NET/C# 进行可靠的 SerialPort 编程?

    c++ - MFC C++ 通过 WM_DEVICECHANGE 通知区分两个设备

    linux - 在 Linux 上通过 USB 发送原始数据