Freigeben eines nicht verbundenen virtuellen seriellen Ports

Ich habe ein kleines Problem mit einem USB Barcode Scanner. Ich verwende den Scanner mit der class “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; 

Wenn ich das USB-Gerät abziehe, während es über die “SerialPort” -class geöffnet wird, kann ich die Software nicht richtig schließen und der virtuelle Port bleibt für alle Ewigkeit offen oder bis ich den gesamten Computer neu starte.

Meine Frage ist also, gibt es eine Möglichkeit, den virtuellen Port zu schließen, nachdem ich das Gerät über C # -Code ausgesteckt habe?

Schöne Grüße

[Bearbeiten # 1]

Alles klar, etwas mehr Code:

Auf diese Weise überprüfe ich alle 10 Sekunden, ob das Gerät angeschlossen ist:

  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; } 

Das ist das Callback-Event des seriellen Ports:

 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; } 

wenn es nicht mehr antwortet, wird “DeviceNotAvailableEvent ()” ausgetriggers:

  void BarcodeScannerDeviceNotAvailableEvent() { this._barcodeScanner.Close(); this._barcodeScanner.Dispose(); } 

Ich habe das Dispose Event der “SerialPort” class überschrieben, so dass es den Thread abbrechen wird:

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

    Serielle Ports stammen aus der Steinzeit der Informatik. Dort haben Sie Ihren ASR-33-Fernschreiber angeschlossen, um mit der Eingabe Ihres Fortran-Programms zu beginnen. Die elektrische Schnittstelle ist sehr einfach. So verwendet die Windows-API einen seriellen Port aus Ihrem eigenen Code. Praktisch jede Laufzeitumgebung unterstützt sie.

    USB hat die Hardware der seriellen Schnittstelle komplett ersetzt. Es verfügt über eine wesentlich erweiterte logische Schnittstelle zur Maschine, die viele verschiedene Arten von Geräten unterstützt. Und es unterstützt Plug-and-Play, so dass das Betriebssystem erkennt, wenn ein Gerät angeschlossen oder entfernt wird, sowie den Gerätetreiber automatisch installiert und so weiter.

    Diese Flexibilität hat jedoch ihren Preis. Ein USB-Gerät benötigt immer einen Gerätetreiber, um nutzbar zu werden. Gerätetreiber werden nicht gleich erstellt. Unterschiedliche Treiber erfordern unterschiedliche Möglichkeiten, mit dem Gerät zu kommunizieren. Normalerweise erfolgt dies über DeviceIoControl () oder Read / WriteFile (), aber das sind sehr undurchsichtige API-functionen. In den frühen Tagen von USB würden Gerätehersteller eine DLL zur Verfügung stellen, die eine reichhaltige API zur Verfügung stellte, um die Implementierungsdetails zu verbergen.

    Das hat nicht so gut funktioniert, Hersteller sind nicht sehr gut darin, gute APIs zu schreiben, und sie unterstützen sie sicher nicht gerne. Eine gute Lösung wäre also die Unterstützung einer Standard-API, die auf jeder Maschine verfügbar ist und von jeder Laufzeit unterstützt wird, die von einer anderen Person dokumentiert und verwaltet wird. Wie die serielle Schnittstelle API.

    Das hat nicht so gut geklappt, die Hersteller sind nicht sehr gut darin, Gerätetreiber zu schreiben, die serielle Ports emulieren. Das größte Problem mit der API ist, dass sie Plug & Play nicht unterstützt. Die coreunterstützung dafür fehlt, schließlich hat die Hardware der seriellen Schnittstelle keine logische Schnittstelle, um sie zu unterstützen. Es gibt einige Unterstützung für das Erkennen, dass ein Gerät über die DTR-Hardware-Handshake-Leitung angeschlossen ist, aber keinerlei Unterstützung für das Erkennen, dass der Port nicht mehr vorhanden ist.

    Trennen des USB-Geräts ist das Problem. In einer idealen Welt würde der Emulator, der in den Gerätetreiber eingebaut ist, einfach so tun, als wäre der serielle Port noch vorhanden, bis der letzte Griff auf dem Gerät geschlossen ist. Das wäre die logische Implementierung, da es kein Plug-and-Play-Ereignis gibt. Aus irgendeinem seltsamen Grund scheint das schwierig zu implementieren zu sein. Die meisten USB-Treiber nehmen die miese Abkürzung, sie lassen das Gerät einfach verschwinden, auch wenn es gerade benutzt wird .

    Dies wirkt sich auf jeden Benutzermodus-Code aus, der das Gerät verwendet. In der Regel wird davon ausgegangen, dass es sich um einen echten seriellen Port handelt und echte serielle Ports nicht plötzlich verschwinden. Zumindest nicht ohne einen leuchtend blauen Funken zu zeichnen. Was schief läuft, ist ziemlich unberechenbar, weil es davon abhängt, wie der Fahrer auf Anfragen auf einem Gerät reactjs, das nicht mehr da ist. Eine nicht behebbare Ausnahme in einem Worker-Thread, die von SerialPort gestartet wurde, war ein häufiges Missgeschick. Klingt wie Ihr Treiber wirklich falsch, es generiert einen Fehler Return Code auf der MJ_CLOSE Treiberanforderung. Für einen Fahrer ist das eine logische Sache, schließlich ist das Gerät nicht mehr da, aber von deinem Ende her ziemlich unlösbar. Sie haben ein Handle und Sie können es nicht schließen. Das ist ein Bach ohne Paddel.

    Jede Hauptversion von .NET hatte einen kleinen Patch für die SerialPort-classn, um das Elend etwas zu minimieren. Aber es gibt eine begrenzte Menge, die Microsoft tun kann, alle Fehler zu erfassen und vorzutäuschen, dass sie letztlich nicht zu einer class geführt haben, die selbst mit einem guten Treiber keine gute Diagnose mehr bietet.

    So praktische Ansätze sind:

    • Verwenden Sie immer das Taskleisten-Symbol Hardware sicher entfernen in Windows
    • Verwenden Sie die neueste Version von .NET
    • Kontaktieren Sie den Anbieter und fragen Sie nach einem Treiberupdate
    • Graben Anbieter, die lausige Treiber liefern
    • Sagen Sie Ihren Benutzern, dass das Trennen des USB-Geräts nicht das Problem triggers, nur weil es das einzige ist, was Sie mit einem USB-Gerät tun können
    • Schließen Sie den Port einfach und zugänglich in Ihrer Benutzeroberfläche
    • Kleben Sie den USB-Stecker an den Anschluss, damit er nicht entfernt werden kann

    Die fünfte Kugel ist auch, was Programmierer in Schwierigkeiten bringt. Es ist nicht einfach, seriellen Portcode zu schreiben, er ist stark asynchron und der Threadpool-Thread, der das DataReceived-Ereignis ausführt, ist schwer zu handhaben. Wenn Sie das Softwareproblem nicht diagnostizieren können, neigen Sie dazu, die Hardware zu beschuldigen. Es gibt sehr wenig, was Sie mit der Hardware tun können, aber entfernen Sie es. Schlechte Idee. Jetzt hast du zwei Probleme.

    Dieses Problem existiert in .Net 2, 3, 3.5 Sie können Framework 4 verwenden (Problem existiert nicht in .net 4)