一尘不染

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

c#

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

阅读 224

收藏
2020-05-19

共1个答案

一尘不染

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

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

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

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

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

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

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

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

所以实际的方法是:

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

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

2020-05-19