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

Rob*_*gel 9 c# usb serial-port barcode

我的USB条形码扫描仪有点问题.我正在使用带有"SerialPort"类的Scanner:

        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;
Run Code Online (Sandbox Code Playgroud)

如果我通过"SerialPort"类打开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;
    }
Run Code Online (Sandbox Code Playgroud)

那是串口的Callback-Event:

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;
    }
Run Code Online (Sandbox Code Playgroud)

如果它不再回答它将触发"DeviceNotAvailableEvent()":

    void BarcodeScannerDeviceNotAvailableEvent()
    {
        this._barcodeScanner.Close();
        this._barcodeScanner.Dispose();
    }
Run Code Online (Sandbox Code Playgroud)

我已经覆盖了"SerialPort"类的Dispose事件,以便它将中止Thread:

protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            this._deviceAvailableThread.Abort();

        }

        base.Dispose(isDisposing);
    }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 23

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

USB完全取代了串口硬件.它具有更高级的机器逻辑接口,支持许多不同类型的设备.它支持即插即用,允许操作系统检测设备何时连接或移除,以及自动安装设备驱动程序等.

然而,这种灵活性是有代价的,USB设备总是需要设备驱动程序才能使用.设备驱动程序不是平等的.不同的驱动程序需要不同的方式来与设备通信.通常通过DeviceIoControl()或Read/WriteFile()完成,但这些是非常不透明的API函数.在USB的早期,设备制造商将提供一个DLL,它提供了丰富的API来隐藏实现细节.

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

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

拆卸USB设备是个问题.在理想情况下,设备驱动程序中内置的仿真器只会假装串口仍在那里,直到设备上的最后一个句柄关闭.这将是逻辑实现,因为没有办法触发即插即用事件.由于某些奇怪的原因,似乎很难实现.大多数USB驱动程序采用简洁的快捷方式,它们只是使设备即使在使用时也会消失.

这会对使用该设备的任何用户模式代码造成严重破坏.这通常被写为假设它是一个真正的串行端口,真正的串行端口不会突然消失.至少没有画出明亮的蓝色火花.出了什么问题是非常不可预测的,因为它取决于驱动程序如何响应不再存在的设备上的请求.SerialPort启动的工作线程中的一个无法捕获的异常是一个常见的事故.听起来你的驱动程序确实错了,它会在MJ_CLOSE驱动程序请求上生成错误返回代码.对于一个驱动程序来说,这是一个合乎逻辑的事情,在所有设备不再存在之后,但是从你的目的来看是无法解决的.你有一个手柄,你不能关闭它.这是一条没有划桨的小溪.

.NET的每个主要版本都有一个针对SerialPort类的小补丁,试图尽量减少痛苦.但微软可以做的数量有限,捕捉所有错误并假装它们没有发生,最终导致不再提供良好诊断的类,即使有一个好的驱动程序.

所以实用的方法是:

  • 始终使用Windows中的"安全删除硬盘"托盘图标
  • 使用最新版本的.NET
  • 联系供应商并要求更新驱动程序
  • 供应糟糕司机的沟渠供应商
  • 告诉你的用户,只是因为这是你唯一能用USB设备做的事情,拔掉它就不能解决任何问题
  • 在UI中轻松关闭端口并进行访问
  • 将USB连接器粘到端口上,使其无法移除

第5个子弹也是程序员遇到麻烦的原因.编写串口代码并不容易,它是非常异步的,并且运行DataReceived事件的线程池线程很难处理.当您无法诊断软件问题时,您往往会责怪硬件.您可以使用硬件很少的事情但拔下电源插头.馊主意.现在你有两个问题.

  • 这是一个非常彻底的答案.这应该是这类问题的规范答案. (2认同)
  • -1 表示“USB 已完全取代了串行端口硬件。” 作为总括声明。 (2认同)
  • 在过去的15年里,我马上回过头来看电脑的背面. (2认同)