#c# #visual-studio-2008 #serial-port
#c# #visual-studio-2008 #последовательный порт
Вопрос:
В моем приложении на C # 2008 я использую функцию SerialPort.GetPortNames() для получения списка доступных в данный момент портов. Что я заметил, так это то, что когда я подключаю USB-устройство, в списке моего приложения отображается номер порта, а когда я отключаю его и обновляю список, номера порта там больше нет.
Одна фаза приложения включает в себя непрерывное чтение / запись данных с / на устройство. Теперь я ожидаю, что если я отключу устройство во время операции и получу текущий список портов с помощью SerialPort.GetPortNames(), имени порта там не будет, и я могу использовать это, чтобы принять решение о том, что устройство было отключено.
К моему удивлению, имя порта все еще найдено, несмотря на то, что оно было удалено
Почему программа ведет себя подобным образом? Имя порта не отображается в режиме отсутствия связи. Имеет ли это какое-то отношение к удаляемому устройству при обмене данными?
Ответ №1:
Вы должны говорить о SerialPort.GetPortNames(), «GetPortList» не имеет смысла. Функция выполняет итерацию значений в реестре, записанных туда драйвером вашего устройства-эмулятора USB. Вы можете ознакомиться с Regedit.exe перейдите в HKLMHardwareDeviceMapSerialComm. Отключите его, нажмите F5, если COM-порт все еще там, то SerialPort не знает ничего лучше, чем порт, который все еще присутствует.
Не существует предписанного поведения относительно того, как драйвер устройства последовательного порта должен вести себя, когда порт внезапно исчезает. Последовательные порты очень примитивны, они восходят к эпохе, когда «ошибка» означала моль, склеивающую телетайп. Аппаратная поддержка Plug and Play вообще отсутствует, удаление порта при включенном питании эквивалентно отключению дисковода, пока Windows переключается на файл подкачки.
Большинство драйверов устройств возвращают код ошибки, он генерирует необнаруживаемое исключение, которое приводит к сбою вашей программы. Тема этой статьи об отзывах. Очевидно, что ваш драйвер устройства этого не делает, что должно быть предпочтительнее, чем бомбардировка вашей программы. Кстати, большинство драйверов устройств USB-эмулятора являются полным мусором.
Окончательное решение простое: прикрепите к разъему небольшую пометку «не отключать во время использования!». Это своего рода проблема с USB, большинство людей смотрят на это и говорят «хм, что я могу с этим сделать?». И получите единственный ответ и отключите его. После пары неудач они научатся больше так не делать.
Ответ №2:
Я предполагаю, что вы имеете в виду System.IO.Ports.SerialPort.GetPortNames(), потому что я нигде не смог найти функцию GetPortList(). MSDN сообщает: «Если реестр содержит устаревшие или иным образом неверные данные, то метод GetPortNames вернет неверные данные», так что, вероятно, в этом и заключается проблема. Я предполагаю, что Windows не обновляет реестр, если порт все еще «используется», точно так же, как вы не можете удалить файл, когда у программы есть дескриптор для него.
Если вы хотите проверить, удалено ли устройство, вы можете сделать это с помощью вызова Window API (http://www.pinvoke.net/default.aspx/user32/RegisterDeviceNotification.html ). Надеюсь, это поможет!
Комментарии:
1. Спасибо за предложения. Похоже, Windows API — это лучший способ обойти это. Я совершенно неопытен в использовании Windows API. Вы предполагаете, что у меня есть опыт работы с C #, не могли бы вы предложить ссылку, по которой я мог бы получить хорошее представление об использовании Windows API с приложениями C # 2008.
2. msdn.microsoft.com/en-us/magazine/cc164123.aspx вероятно, это поможет. Впрочем, у меня тоже нет никакого опыта в этой области.
Ответ №3:
Правильно, что GetPortNames()
считывает порты из раздела реестра
HKLMHardwareDeviceMapSerialComm
Это автоматически обновляется Windows при каждом открытии или закрытии порта.
Но, тем не менее, со мной случилось так, что в реестре указан несуществующий порт, а также возвращенный из GetPortNames()
. Когда я пытаюсь открыть этот порт, я получаю «Порт XYZ не существует«.
Что это???
Теперь я выяснил причину: это происходит всегда после использования PortMon из www.sysinternals.com . Этот инструмент содержит ошибки и позволяет неработоспособному порту зависать в реестре, если порт закрыт во время его мониторинга.
В этом случае единственное средство — перезагрузить компьютер.
Ответ №4:
Как упоминали другие, это очень специфично для драйвера. Похоже, что не существует способа проверить с помощью .Net API, действительно ли порт, возвращаемый GetPortNames(), существует и является действительным.
Что касается того, почему порты ведут себя подобным образом, я обнаружил, что некоторые драйверы USB-to-serial вызывают сбой приложения при внезапном отключении порта.
Другие драйверы, часто те, которые не аварийно завершают работу, будут сохранять порт в списке до тех пор, пока ваше приложение не закроет его, после чего он исчезнет. Попытка чтения из устаревшего порта или записи на него (обычно) приводит к тайм-аутам или ошибкам. Предположительно, чтобы не привести к аварийному завершению работы приложения, драйверу необходимо поддерживать устаревший порт, пока он все еще открыт в приложении.
Если вы снова подключите порт, некоторые драйверы даже смогут повторно подключить его к вашему приложению, другие не распознают порт, пока ваше приложение не закроет устаревший порт. Такое поведение при повторном подключении может быть несколько опасным, если порт исчез из-за перезагрузки устройства, потому что тогда оно внезапно окажется в состоянии, отличном от ожидаемого вашим приложением, без явного указания на то, что оно сбросилось. По крайней мере, если вы получаете ошибки от порта, вы знаете, что что-то произошло.
Я также обнаружил, что если я забуду закрыть порт, он не исчезнет из списка до тех пор, пока сборщик мусора не приступит к удалению объекта SerialPort.
Комментарии:
1. > «некоторые драйверы даже смогут повторно подключить его к вашему приложению». Я никогда такого не видел. С каким устройством вы наблюдали это?