![]() |
![]() |
||||||||||||
Управление USB-устройствами под Windows
Автор: Serg1987, axentfly@yandex.ru Написать данный мануал меня сподвигло желание помочь окружающим в вопросе написания программ под Windows для управления USB устройствами, т.к. в сети на этот счет очень мало сколь более менее толковой информации. "Мало??" - удивятся некоторые. Да, мало.. Нет, есть конечно инструкции по написанию софта с использованием всяких внешних библиотек, типа libusb и т.д. Когда передо мной стала задача написания софта под Windows, я тоже смотрел в сторону данных библиотек. Но меня жутко не устраивал тот факт, что при переносе программы на другой компьютер также необходимо было и перекачивать прилагающуюся usb-либу. Многие согласятся, что это весьма неудобно, особенно, если свой продукт вы собираетесь куда-то продвигать. Поэтому было принято решение - сделать всё средствами Windows. Тем более поставляющиеся драйвера и ресурсы от Майкрософта позволяют программистам делать ПО для USB устройств без всяких там libusb или ещё черт знает каких рудиментов. И такие программы без проблем запустятся на других машинах. Кроме установщика ничего копировать не придется. Что ж.. Для начала.. Статья ориентирована на более продвинутых пользователей, нежели чем на начинающих. В статье отсылок к коду будет мало. Для этого смотрите сам проект. Софт писался для устройства USB класса Custom-HID. Оговорюсь об используемом средстве разработки. У меня это C++ Builder Embarcaderro XE7. В Visual Studio настройка проекта и т.п. может быть немножко по другому. Но общий принцип не меняется - и там и там код по сути одинаков. ОС - Windows 7. Проект я прикрепил в архиве. Напоминаю, данный проект работает только в C++ Builder XE7 и выше. Для того, чтобы открыть в более старых версиях, нужно будет выкинуть из кода инициализации некоторые инклуды и описатели (реализация C++ Builder старых и новых версий отличается). В старых версиях проще создать свой проект и скопировать туда приложенный в моем проекте код. Это было предисловие. Поехали.. Для начала, для того чтобы программировать под Windows для USB вам нужно скачать пакет для разработчиков от Майрософта Windows WDK по ссылке https://www.microsoft.com/en-us/download/details.aspx?id=11800 Качаем и устанавливаем. Пути оставляем по умолчанию. После этого открываем наш Builder. Заходим в свойства Tools->Options и далее в Environment Options->C++ Options->Paths And Directories.. ищем строку System Include Path.. и добавляем следующие пути для хидер-файлов из WDK. У меня пути для h-файлов такие: C:WinDDK7600.16385.1incddk Потом добавляем путь для библиотек lib. Всё тоже самое, но на этот раз ищем строку System Library Path.. В данном блоке должны быть прописаны пути: C:WindowsSystem32 Готово. Переходим непосредственно к программе. В софте имеются 3 кнопки (Connect, Disconnect и Check). Нас интересует прежде всего волшебная кнопка Connect, а именно тот код, который она выполняет. Итак.. Открываем файл Unit2.cpp и смотрим Инициализация USB и поиск устройства осуществляется с помощью функций Windows, подробное описание которых приведено на сайте MS. Все базовые функции для работы с HID на уровне Windows и указатели на них объявляются в начале программы. Код инициализации (и поиска нашего устройства) - это функция enumd() Сразу вызываем: hDev = SetupDiGetClassDevs(&hguid,NULL,0,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); Данная функция инициализирует требуемый класс устройств. Более подробно о ней я писать не буду. Если знаете английский, то исчерпывающую информацию можете узнать с сайта мелкомягких. Далее получаем размеры структур инфы об устройствах и интерфейсе: dInf.cbSize = sizeof(SP_DEVINFO_DATA); А дальше в хитроумной цикле while поочередно получаем инфу о каждом USB-устройстве, пока те не закончатся)) Из этого перебора читаем данные (VID и PID или ещё чего), с и ищем нужное нам устройство (сравниваем полученные данные с теми, что нам нужны . -> функция connecthid()). В функции connecthid мы поочередно пытаемся открыть каждое обнаруженное системой устройство. Многие знающие заметят, что тут используются функции, знакомые некоторым по работе с COM-портом. Те же CreateFile и CloseFile. Да, USB устройство открывается как объект файла. А также как и для COM-порта для USB-девайса создаются потоки записи и чтения. Функция getinfo сравнивает значение VID и PID текущего устройства с искомым. Если такового нет, то ненужное устройство отключается функцией disconhid(), если мы вдруг с ним соединились (не всякое HID устройство можно открыть методом CreateFile). Если устройство успешно найдено, то индикатор на форме меняет цвет с красного на зеленый, а надпись Off внутри него на On. Искомые VID и PID (а также я добавил строку продукта) определены в переменной: AnsiString productdata[3] = {"1155","22350","I2Cdial"}; VID и PID тут представлены в десятичном, а не hex-виде. Это краткий мануал для тех, кто хочет писать ПО для своих девайсов на более низком и качественном уровне, без всяких рудиментарных дополнительных библиотек. Как я и говорил, статья рассчитана на более продвинутых пользователей, но если что - вопросы можете задавать. Ссылка для скачки самого проекта - внизу. Исправлено и дополнено (06.07.2017): Друзья, нюанс в данном коде был найден давно. Но я решил дополнить статью сейчас, чтобы некоторые не наступили на те грабли, что и я. Вопрос касается самого порядка инициализации девайса. В проекте инициализация происходит так: -получаем путь каждого устройства, после чего пытаемся открыть (CreateFile) данное устройство. -После этого считываем методом GetAttribute его VID и PID. -И если устройство не то, то закрываем его (CloseFile). Друзья, как оказалось, так делать не рекомендуется. Во превых, постоянным вызовом Create/CloseFile расходуются ресурсы памяти, во вторых - при отключении нашего девайса по нажатию на кнопку Disconnect, программа может закрыть потоки другого какого-либо устройства. С целью исправления данной ошибки порядок инициализации должен быть следующим: 1) Находим устройство, получаем его путь в строке. Данная строка в проекте передается как аргумент в функцию connecthid 2) Найдя путь, вычленяем из строки пути искомые VID и PID. Работаем чисто со строкой, девайс не открываем! Для того чтобы понять, какое положение значения VID и PID занимают в строке, советую вывести её куда-либо (какой-нибудь MEMO или StringList). Копируем полученные значения VID и PID в переменные и сравниваем с исходными. Здесь вся работа целиком со строками. 3) Если по пункту 2. VID и PID совпали с искомыми то только сейчас! мы вызываем функцию CreateFile и открываем наше устройство! Наслаждаемся))
Файлы: Все вопросы в Форум.
|
|
||||||||||||
![]() |
![]() |


![]() |
![]() |
|||
|
||||
![]() |
![]() |