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

时间:2012-03-23 08:13:23

标签: 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设备,我就无法正常关闭软件,虚拟端口永远保持打开状态,或直到我重新启动整台计算机。

所以我的问题是,在我通过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);
    }

2 个答案:

答案 0 :(得分:23)

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

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

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

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

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

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

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

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

如此实用的方法是:

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

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

答案 1 :(得分:0)

这个问题存在于.Net 2,3,3.5中你可以使用框架4(.net 4中不存在问题)