Освобождение отключенного виртуального последовательного порта

У меня небольшая проблема со сканером штрих-кода 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;

Если я отключаю 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();
    }

Я переопределил Событие Dispose класса "SerialPort", чтобы он прерывал поток:

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

        }

        base.Dispose(isDisposing);
    }

2 ответа

Решение

Последовательные порты датируются каменным веком вычислений. Вот где вы подключили свой телетайп ASR-33, чтобы начать печатать в своей программе на Фортране. Электрический интерфейс очень прост. Так же и Windows API для использования последовательного порта из вашего собственного кода. Практически любая среда выполнения поддерживает их.

USB полностью заменил оборудование последовательного порта. У него гораздо более продвинутый логический интерфейс к машине, поддерживающий различные типы устройств. Кроме того, он поддерживает функцию Plug and Play, позволяющую операционной системе определять, когда устройство подключено или удаляется, а также автоматически устанавливать драйвер устройства и так далее.

Эта гибкость имеет свою цену, однако для использования USB-устройства всегда требуется драйвер устройства. Драйверы устройств не созданы равными. Разные драйверы требуют разных способов общения с устройством. Обычно делается через DeviceIoControl() или Read/WriteFile(), но это очень непрозрачные функции API. В первые дни USB производители устройств поставляли DLL, которая предоставляла богатый API, чтобы скрыть детали реализации.

Это не сработало, производители не очень хорошо пишут хорошие API и уверены, что не любят их поддерживать. Таким образом, хорошим решением будет поддержка стандартного API, который доступен на любом компьютере, поддерживается любой средой выполнения, документируется и поддерживается кем-то другим. Как и последовательный порт API.

Это не сработало, производители не очень хорошо пишут драйверы устройств, эмулирующие последовательные порты. Самым большим недостатком API является то, что он не поддерживает Plug and Play. Основная поддержка для него отсутствует, ведь у оборудования последовательного порта нет логического интерфейса для его поддержки. Существует некоторая поддержка для обнаружения того, что устройство подключено через аппаратную линию рукопожатия DTR, но нет никакой поддержки для обнаружения того, что порта больше нет.

Проблема в отключении USB-устройства. В идеальном мире эмулятор, встроенный в драйвер устройства, будет просто делать вид, что последовательный порт все еще там, пока не будет закрыт последний дескриптор на устройстве. Это было бы логичной реализацией, учитывая, что нет способа вызвать событие Plug and Play. По какой-то странной причине это кажется трудным для реализации. Большинство драйверов USB используют непристойные ярлыки, они просто заставляют устройство исчезать, даже когда оно используется.

Это проигрывает любой код режима пользователя, который использует устройство. Как правило, написано, чтобы предположить, что это настоящий последовательный порт, и реальные последовательные порты не исчезают внезапно. По крайней мере, без рисования ярко-синей искрой. То, что идет не так, довольно непредсказуемо, потому что это зависит от того, как драйвер отвечает на запросы на устройстве, которого больше нет. Неполучаемое исключение в рабочем потоке, запущенном SerialPort, было обычной ошибкой. Похоже, ваш драйвер действительно ошибается, он генерирует код возврата ошибки по запросу драйвера MJ_CLOSE. Что логично для водителя, ведь устройства там больше нет, но он неразрешим с вашей стороны. У вас есть ручка, и вы не можете ее закрыть. Это ручей без весла.

Каждый основной выпуск.NET имел небольшой патч к классам SerialPort, чтобы попытаться немного минимизировать страдания. Но есть ограниченное количество возможностей, которые Microsoft может сделать, улавливая все ошибки и делая вид, что их не было, в конечном итоге приводит к классу, который больше не предоставляет хорошей диагностики, даже с хорошим драйвером.

Итак, практические подходы:

  • всегда используйте значок "Безопасное извлечение устройства" в Windows
  • использовать последнюю версию.NET
  • обратитесь к поставщику и попросите обновить драйвер
  • поставщики канав, которые поставляют паршивых водителей
  • Скажите своим пользователям, что только потому, что это единственное, что вы можете сделать с USB-устройством, его отключение не решает никаких проблем.
  • сделать закрытие порта простым и доступным в вашем интерфейсе
  • приклейте USB-разъем к порту, чтобы он не мог быть удален

Пятая пуля - это то, что доставляет программистам неприятности. Написание кода последовательного порта не просто, оно сильно асинхронно, и с потоком пула потоков, который запускает событие DataReceived, трудно иметь дело. Когда вы не можете диагностировать проблему программного обеспечения, вы склонны винить аппаратное обеспечение. С аппаратным обеспечением вы мало что можете сделать, но отключите его. Плохая идея. Теперь у вас есть две проблемы.

Эта проблема существует в.Net 2, 3, 3.5, вы можете использовать framework 4 (проблема не существует в.net 4)

Другие вопросы по тегам