释放未插入的虚拟串行端口
我有一个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设备,则无法正常closures软件,并且虚拟端口保持打开状态,直到重新启动整个计算机。
所以我的问题是,有没有办法通过C#代码拔掉设备后closures虚拟端口?
问候
编辑#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; }
这就是串口的callback事件:
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电传打字机的地方,开始inputFortran程序。 电气接口非常简单。 所以是Windows API使用您自己的代码中的串行端口。 实际上任何运行时环境都支持它们。
USB已经完全取代了串口硬件。 它具有更先进的机器逻辑接口,支持许多不同types的设备。 它支持即插即用,使操作系统能够检测到设备连接或拆卸的时间,以及自动安装设备驱动程序等。
这种灵活性是有代价的,但是USB设备总是需要一个设备驱动才能使用。 设备驱动程序不是相同的。 不同的驱动程序需要不同的方式与设备交谈。 通常通过DeviceIoControl()或Read / WriteFile()完成,但是这些API函数是非常不透明的。 在USB的早期,设备制造商将提供一个提供丰富的API来隐藏实现细节的DLL。
那不太好,制造商不擅长编写好的API,他们肯定不喜欢支持它们。 所以一个好的解决scheme是支持一个标准的API,一个可以在任何机器上使用的标准API,由任何运行时支持,由其他人logging和维护。 就像串口API一样。
这并没有那么好,制造商也不太擅长编写模拟串行端口的设备驱动程序。 API最大的困扰就是它不支持即插即用。 它的核心支持是缺less的,毕竟串口硬件没有逻辑接口来支持它。 有一些支持通过DTR硬件握手线来检测设备是否连接,但是不支持检测端口不在那里。
分离USB设备是个问题。 在理想情况下,设备驱动程序中内置的仿真器只会假装串行端口仍然存在,直到设备的最后一个句柄closures。 这将是合乎逻辑的实现,因为无法触发即插即用事件。 由于一些奇怪的原因,似乎难以实施。 大多数USB驱动程序采取糟糕的捷径,他们只是使设备消失, 即使它正在使用 。
这会对使用设备的任何用户模式代码造成严重破坏。 这是通常写入假设它是一个真正的串行端口和真正的串行端口不会突然消失。 至less不是没有绘制一个明亮的蓝色火花。 出了什么问题是非常不可预知的,因为它取决于驱动程序如何响应不再存在的设备上的请求。 由SerialPort启动的工作线程中的不可捕捉的exception是一个常见的不幸事件。 听起来就像你的驱动程序真的错了,它会在MJ_CLOSE驱动程序请求上产生错误返回码。 对于一个司机来说,这是一个合乎逻辑的事情,毕竟这个设备已经不存在了,但是从你的结局来看却是无法解决的。 你有一个句柄,你不能closures它。 这是一个没有桨的小溪。
.NET的每个主要版本都有一个小的补丁,以便尽量减less苦难。 但是,微软能够做到的数量是有限的,抓住所有的错误,假装他们没有发生,最终导致没有提供好的诊断的课程,即使是一个好的驱动程序。
所以实际的方法是:
- 请始终使用Windows中的“移除硬件安全”托盘图标
- 使用最新版本的.NET
- 联系供应商并要求更新驱动程序
- 沟渠供应商提供糟糕的司机
- 告诉你的用户,仅仅因为这是你用USB设备做的唯一的事情,拔掉它并不能解决任何问题
- 使closures端口很容易,并在您的用户界面中访问
- 将USB连接器粘贴到端口,以免被移除
第五个子弹也是让程序员陷入困境的原因。 编写串口代码并不容易,它是非常asynchronous的,运行DataReceived事件的线程池线程很难处理。 当你无法诊断软件问题时,你往往会责怪硬件。 你可以用硬件做很less的事情 ,但拔掉它。 馊主意。 现在你有两个问题。
这个问题存在于.NET 2,3,3.5中你可以使用框架4(问题不存在于.net 4中)