C# · 12月 26, 2021

c# – 释放未插拔的虚拟串行端口

我有一个USB条形码扫描器有点问题.
我正在使用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); }解决方法 串行端口从计算的石器时代开始.这就是您插入ASR-33电传的地方,开始输入您的Fortran程序.电接口非常简单. Windows API从您自己的代码中使用串行端口也是如此.实际上任何运行时环境都支持它们.

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事件的线程池线程很难处理.当您无法诊断软件问题时,您往往会责怪硬件.硬件很简单,但拔掉它.馊主意.现在你有两个问题.