我正在使用Scanner与“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;
如果USB设备在通过“SerialPort”类打开时拔下电源插头,则无法正常关闭软件,虚拟端口将永久保持打开状态,直到重启整个计算机.
所以我的问题是,在我通过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); }
解决方法
USB已经完全取代了串口硬件.它具有更高级的机器逻辑接口,支持许多不同类型的设备.它支持即插即用,允许操作系统检测何时连接或删除设备,以及自动安装设备驱动程序等.
然而,这种灵活性是有代价的,因为USB设备总是需要一个设备驱动程序才能使用.设备驱动程序不是相等的.不同的驱动程序需要不同的方式与设备通信.通常通过DeviceIoControl()或Read / WriteFile()完成,但这些是非常不透明的API函数.在USB的早期,设备制造商将提供一个提供丰富的API来隐藏实现细节的DLL.
那样做并不好,制造商们不太善于编写好的API,他们肯定不喜欢支持它们.所以一个很好的解决方案是支持一个标准的API,一个在任何机器上可用的API,由任何运行时支持,由其他人记录和维护.像串口API一样.
这并没有那么好,制造商们不太会在编写串行端口的设备驱动程序.与API最大的挂起是它不支持即插即用.所有的串口硬件没有逻辑接口来支持它的核心支持是缺少的.有一些支持通过DTR硬件握手线检测设备是否连接,但是没有任何支持来检测端口不再存在.
拆卸USB设备是问题.在理想的世界中,设备驱动程序内置的仿真器将简单地假装串行端口仍然存在,直到设备上的最后一个句柄关闭.这将是逻辑实现,因为没有办法触发即插即用事件.有些奇怪的原因似乎很难实现.大多数USB驱动程序都采用了令人沮丧的快捷方式,即使在使用该设备时也会使设备消失.
这会对使用该设备的任何用户模式代码造成严重破坏.这通常被写为假设它是一个真正的串行端口,而真正的串行端口不会突然消失.至少不是没有画出明亮的蓝色火花.出了什么问题是不可预测的,因为这取决于司机如何响应不再存在的设备上的请求.由SerialPort启动的工作线程中的一个不可批处理的异常是一个常见的不幸.听起来像您的驱动程序真的错了,它会在MJ_CLOSE驱动程序请求上生成错误返回码.对于一个司机而言,这是一件合乎逻辑的事情,所有的设备都不再存在,但是从你的目的来看却是无法解决的.你有一个句柄,你无法关闭它.这是一条没有桨的小河.
每个主要版本的.NET都有一个小的补丁到SerialPort类,以尽量减少一些苦难.但微软可以做的有限的数量,抓住所有的错误,假装没有发生,最终导致不再提供良好诊断的课程,即使是一个好的驱动程序.
所以实际的做法是:
>始终使用Windows中的“删除硬件安全”托盘图标
>使用最新版本的.NET
>联系供应商并要求更新驱动程序
>供应糟糕的司机的沟渠供应商
>告诉你的用户,只是因为它是唯一可以使用USB设备,拔掉它不能解决任何问题
使用户可轻松关闭端口
将USB连接器粘贴到端口,以便不能将其移除
第五个子弹也是程序员遇到的麻烦.编写串行端口代码并不容易,它是非常异步的,运行DataReceived事件的线程池线程很难处理.当您无法诊断软件问题时,您往往会责怪硬件.硬件很简单,但拔掉它.馊主意.现在你有两个问题.