Как написать первый драйвер USB-клиента (UMDF)

В этой статье вы будете использовать шаблон Драйвер пользовательского режима, USB (UMDF V2), предоставляемый в Microsoft Visual Studio 2022, для написания клиентского драйвера на основе платформы UMDF. После сборки и установки драйвера клиента вы увидите драйвер клиента в диспетчер устройств и просмотрите выходные данные драйвера в отладчике.

UMDF (называемая платформой в этой статье) основана на компонентной объектной модели (COM). Каждый объект платформы по умолчанию должен реализовывать IUnknown и его методы QueryInterface, AddRef и Release. Методы AddRef и Release управляют временем существования объекта, поэтому драйверу клиента не нужно поддерживать количество ссылок. Метод QueryInterface позволяет драйверу клиента получать указатели интерфейса на другие объекты платформы в объектной модели Windows Driver Framework (WDF). Объекты платформы выполняют сложные задачи драйвера и взаимодействуют с Windows. Некоторые объекты платформы предоставляют интерфейсы, позволяющие драйверу клиента взаимодействовать с платформой.

Драйвер клиента на основе UMDF реализуется как внутрипроцессный COM-сервер (DLL), а C++ является предпочтительным языком для написания драйвера клиента для USB-устройства. Как правило, драйвер клиента реализует несколько интерфейсов, предоставляемых платформой. В этой статье описывается класс, определенный драйвером клиента, который реализует интерфейсы платформы в качестве класса обратного вызова. После создания экземпляров этих классов результирующие объекты обратного вызова будут связаны с определенными объектами платформы. Это партнерство дает драйверу клиента возможность реагировать на события, связанные с устройством или системой, о чем сообщает платформа. Всякий раз, когда Windows уведомляет платформу об определенных событиях, платформа вызывает обратный вызов драйвера клиента, если он доступен. В противном случае платформа продолжает обработку события по умолчанию. Код шаблона определяет классы обратного вызова драйвера, устройства и очереди.

Описание исходного кода, созданного шаблоном, см. в статье Основные сведения о коде шаблона UMDF для драйвера USB-клиента.

Перед началом работы

Для разработки, отладки и установки драйвера пользовательского режима требуется два компьютера:

  • Главный компьютер под управлением Windows 10 или более поздней версии операционной системы Windows. Главный компьютер — это среда разработки, где вы пишете и отлаживать драйвер.
  • Целевой компьютер под управлением версии операционной системы, на которой требуется протестировать драйвер, например Windows 11 версии 22H2. На целевом компьютере есть драйвер пользовательского режима, который требуется отладить, и один из отладчиков.

В некоторых случаях, когда главный и целевой компьютеры работают под управлением одной и той же версии Windows, может быть только один компьютер под управлением Windows 10 или более поздней версии Windows. В этой статье предполагается, что вы используете два компьютера для разработки, отладки и установки драйвера пользовательского режима.

Прежде чем начать, убедитесь, что вы соответствуете следующим требованиям:

Требования к программному обеспечению

  • Главный компьютер имеет Visual Studio 2022.

  • На хост-компьютере установлена последняя версия пакета драйверов Windows (WDK) для Windows 11 версии 22H2.

    Комплект включает заголовки, библиотеки, средства, документацию и средства отладки, необходимые для разработки, сборки и отладки драйвера USB-клиента. Последнюю версию WDK можно получить в разделе Как получить WDK.

  • На хост-компьютере установлена последняя версия средств отладки для Windows. Вы можете получить последнюю версию из WDK или скачать и установить средства отладки для Windows.

  • Если вы используете два компьютера, необходимо настроить главный и целевой компьютеры для отладки в пользовательском режиме. Дополнительные сведения см. в статье Настройка отладки User-Mode в Visual Studio.

Требования к оборудованию

Получите USB-устройство, для которого будет записываться драйвер клиента. В большинстве случаев вы предоставляете USB-устройство и его спецификацию оборудования. Спецификация описывает возможности устройства и поддерживаемые команды поставщика. Используйте спецификацию, чтобы определить функциональные возможности USB-драйвера и связанные с ним решения по проектированию.

Если вы не знакомы с разработкой USB-драйверов, используйте комплект обучения OSR USB FX2 для изучения примеров USB, входящих в состав WDK. Он содержит устройство USB FX2 и все необходимые спецификации оборудования для реализации драйвера клиента.

Шаг 1. Создание кода драйвера

Дополнительные сведения о написании кода драйвера UMDF см. в статье Создание драйвера UMDF на основе шаблона.

В Visual Studio 2022 для конкретного кода, предназначенного для USB, выберите следующие параметры.

  1. В диалоговом окне Новый проект в поле поиска вверху введите USB.
  2. В средней области выберите Драйвер пользовательского режима, USB (UMDF V2).
  3. Выберите Далее.
  4. Введите имя проекта, выберите расположение для сохранения и нажмите кнопку Создать.

На следующих снимках экрана показано диалоговое окно Новый проект для шаблона ДРАЙВЕРА USB User-Mode .

Снимок экрана: параметры создания проекта Visual Studio.

Снимок экрана: экран конфигурации создания проекта в Visual Studio.

В этой статье предполагается, что имя проекта — MyUSBDriver_UMDF_. Она содержит следующие файлы:

Файлы Описание
Driver.h; Driver.c Содержит реализацию точки входа модуля драйвера. Функции и обратные вызовы, связанные с DriverEntry и WDFDRIVER.
Device.h; Device.c Функции и обратные вызовы, связанные с WDFDEVICE и WDFUSBDEVICE.
Queue.h; Queue.c Функции и обратные вызовы, связанные с WDFQUEUE.
Trace.h Определяет GUID интерфейса устройства. Он также объявляет функции трассировки и макросы.
<Имя> проекта.inf INF-файл, необходимый для установки драйвера клиента на целевом компьютере.

Шаг 2. Добавление сведений об устройстве

Перед сборкой драйвера необходимо добавить сведения об устройстве, в частности идентификатор оборудования. Чтобы указать идентификатор оборудования, выполните следующие действия.

  1. В окне Обозреватель решений щелкните правой кнопкой мыши MyUSBDriver_UMDF_ и выберите Пункт Свойства.
  2. В окне Страницы свойств MyUSBDriver_UMDF_ перейдите к разделу Свойства > конфигурации Драйвер Установка > развертывания, как показано ниже. Снимок экрана: окно страниц свойств Visual Studio 2022.
  3. Установите флажок Удалить предыдущие версии драйверов перед развертыванием.
  4. В поле Имя целевого устройства выберите имя компьютера, настроенного для тестирования и отладки.
  5. Выберите Hardware ID Driver Update (Обновление драйвера) и введите идентификатор оборудования для драйвера. В этом упражнении идентификатор оборудования — Root\MyUSBDriver_UMDF_. Щелкните ОК.

Примечание

В этом упражнении идентификатор оборудования не идентифицирует реальную часть оборудования. Он определяет мнимое устройство, которому будет предоставлено место в дереве устройств в качестве дочернего по отношению к корневому узлу. Для реального оборудования не выбирайте Обновление драйвера идентификатора оборудования. Вместо этого выберите Установить и проверить. Идентификатор оборудования можно увидеть в файле сведений о драйвере (INF). В окне Обозреватель решений перейдите к MyUSBDriver_UMDF_ > Файлы драйверов и дважды щелкните MyUSBDriver_UMDF_.inf. Идентификатор оборудования находится в [Standard.NT$ARCH$].

Для всех драйверов USB-клиента на основе UMDF требуются два драйвера, предоставляемые Корпорацией Майкрософт: отражатель и WinUSB.

  • Отражатель. Если драйвер загружается успешно, отражатель загружается как самый верхний драйвер в стеке режима ядра. Отражатель должен быть верхним драйвером в стеке режима ядра. В соответствии с этим требованием в INF-файле шаблона указывается отражатель как услуга и WinUSB в качестве драйвера нижнего фильтра в INF:

    [MyDevice_Install.NT.Services]
    AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall  ; flag 0x2 sets this as the service for the device
    AddService=WinUsb,0x000001f8,WinUsb_ServiceInstall  ; this service is installed because its a filter.
    
  • WinUSB: пакет установки должен содержать монеты для Winusb.sys так как для клиентского драйвера WinUSB является шлюзом к стеку драйверов USB в режиме ядра. Другим компонентом, который загружается, является библиотека DLL в пользовательском режиме с именем WinUsb.dll в хост-процессе драйвера клиента (Wudfhost.exe). Winusb.dll предоставляет функции WinUSB , которые упрощают процесс взаимодействия между драйвером клиента и WinUSB.

Шаг 3. Создание кода драйвера USB-клиента

Чтобы создать драйвер, выполните приведенные далее действия.

  1. Откройте проект драйвера или решение в Visual Studio 2022.
  2. Щелкните правой кнопкой мыши решение в Обозреватель решений и выберите Configuration Manager.
  3. В Configuration Manager выберите активную конфигурацию решения (например, Отладка или Выпуск) и активную платформу решения (например, x64), которые соответствуют интересующему вас типу сборки.
  4. Убедитесь, что GUID интерфейса устройства является точным на протяжении всего проекта.
    • GUID интерфейса устройства определяется в Trace.h и ссылается MyUSBDriverUMDFCreateDevice из в Device.c. При создании проекта с именем MyUSBDriver_UMDF_ Visual Studio 2022 определяет GUID интерфейса устройства с именем GUID_DEVINTERFACE_MyUSBDriver_UMDF_ , но вызывает WdfDeviceCreateDeviceInterface с неправильным параметром &GUID_DEVINTERFACE_MyUSBDriverUMDF. Замените неправильный параметр именем, определенным в Trace.h, чтобы обеспечить правильную сборку драйвера.
  5. В меню Построение выберите пункт Построить решение.

Дополнительные сведения см. в разделе Создание драйвера.

Шаг 4. Настройка компьютера для тестирования и отладки

Чтобы протестировать и отладить драйвер, запустите отладчик на хост-компьютере и драйвер на целевом компьютере. До сих пор вы использовали Visual Studio на хост-компьютере для создания драйвера. Затем необходимо настроить целевой компьютер. Чтобы настроить целевой компьютер, следуйте инструкциям в статье Подготовка компьютера для развертывания и тестирования драйверов.

Шаг 5. Включение трассировки для отладки ядра

Код шаблона содержит несколько сообщений трассировки (TraceEvents), которые могут помочь в отслеживании вызовов функций. Все функции в исходном коде содержат сообщения трассировки, которые помечают вход и выход подпрограммы. Для ошибок сообщение трассировки содержит код ошибки и осмысленную строку. Так как трассировка WPP включена для проекта драйвера, файл символов PDB, созданный в процессе сборки, содержит инструкции по форматированию сообщений трассировки. При настройке главного и целевого компьютеров для трассировки WPP драйвер может отправлять сообщения трассировки в файл или отладчик.

Настройка главного компьютера для трассировки WPP

  1. Создайте файлы формата сообщений трассировки (TMF), извлекая инструкции по форматированию сообщений трассировки из файла символов PDB.

    Для создания файлов TMF можно использовать Tracepdb.exe. Средство находится в папке<> установкиWindows Kits\10\bin\<architecture> в WDK. Следующая команда создает TMF-файлы для проекта драйвера.

    tracepdb -f <PDBFiles> -p <TMFDirectory>
    

    Параметр -f указывает расположение и имя файла символов PDB. Параметр -p указывает расположение файлов TMF, созданных Tracepdb. Дополнительные сведения см. в разделе Команды Tracepdb.

    В указанном расположении есть три файла, по одному для каждого файла кода C в проекте. Им присваиваются имена файлов GUID.

  2. В отладчике введите следующие команды:

    .load Wmitrace
    .chain
    !wmitrace.searchpath + <TMF file location>
    

Выполните следующие команды.

  • Загрузите расширение Wmitrace.dll.
  • Проверяет, загружено ли расширение отладчика.
  • Добавляет расположение файлов TMF в путь поиска расширения отладчика.

Результат будет примерно таким:

Trace Format search path is: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE;c:\drivers\tmf

Настройка целевого компьютера для трассировки WPP

  1. Убедитесь, что на целевом компьютере есть средство Tracelog. Средство находится в папке< install_folder>Windows Kits\10\Tools\<arch> в WDK. Дополнительные сведения см. в разделе Синтаксис команды Tracelog.

  2. Откройте командное окно и запустите от имени администратора.

  3. Введите следующую команду:

    tracelog -start MyTrace -guid \#c918ee71-68c7-4140-8f7d-c907abbcb05d -flag 0xFFFF -level 7-rt -kd
    

Команда запускает сеанс трассировки с именем MyTrace.

Аргумент GUID указывает GUID поставщика трассировки, который является драйвером клиента. Guid можно получить из Trace.h в проекте Visual Studio 2022. В качестве другого варианта можно ввести следующую команду и указать GUID в файле GUID. Файл содержит GUID в формате дефиса:

tracelog -start MyTrace -guid c:\\drivers\\Provider.guid -flag 0xFFFF -level 7-rt -kd

Вы можете остановить сеанс трассировки, введя следующую команду:

tracelog -stop MyTrace

Шаг 6. Развертывание драйвера на целевом компьютере

  1. В окне Обозреватель решений щелкните правой кнопкой мыши имя проекта (MyUSBDriver_UMDF_) и выберите пункт Свойства.
  2. В левой области перейдите к разделу Свойства > конфигурации Установка > развертывания драйвера.
  3. В поле Имя целевого устройства укажите имя целевого компьютера.
  4. Выберите Установить или переустановить и проверить.
  5. Щелкните ОК.
  6. В меню Отладка выберите Начать отладку или нажмите клавишу F5 на клавиатуре.

Примечание

Не указывайте идентификатор оборудования устройства в разделе Обновление драйвера идентификатора оборудования. Идентификатор оборудования должен быть указан только в файле сведений о драйвере (INF).

Шаг 7. Просмотр драйвера в диспетчер устройств

  1. Введите следующую команду, чтобы открыть диспетчер устройств.

    devmgmt
    
  2. Убедитесь, что диспетчер устройств отображает следующий узел.

    USB-устройство

    MyUSBDriver_UMDF_Device

Шаг 8. Просмотр выходных данных в отладчике

Убедитесь, что сообщения трассировки отображаются в окне интерпретации отладчика на хост-компьютере.

Результат выполнения должен быть аналогичен следующему:

[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Entry
[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Exit

Комментарии

Давайте рассмотрим, как платформа и драйвер клиента взаимодействуют с Windows и обрабатывают запросы, отправляемые на USB-устройство. На этом рисунке показаны модули, загруженные в систему для драйвера USB-клиента на основе UMDF.

Схема архитектуры драйвера клиента пользовательского режима.

Назначение каждого модуля описано здесь:

  • Приложение — процесс пользовательского режима, который отправляет запросы ввода-вывода для взаимодействия с USB-устройством.
  • Диспетчер ввода-вывода — компонент Windows, который создает пакеты запросов ввода-вывода (IRP) для представления полученных запросов приложений и пересылает их в верхнюю часть стека устройств в режиме ядра для целевого устройства.
  • Reflector — предоставленный Корпорацией Майкрософт драйвер режима ядра, установленный в верхней части стека устройств в режиме ядра (WUDFRd.sys). Отражатель перенаправляет irP, полученные от диспетчера ввода-вывода, в процесс узла драйвера клиента. После получения запроса платформа и драйвер клиента обрабатывают запрос.
  • Хост-процесс — процесс, в котором выполняется драйвер пользовательского режима (Wudfhost.exe). В нем также размещается платформа и диспетчер ввода-вывода.
  • Драйвер клиента — драйвер функции пользовательского режима для USB-устройства.
  • UMDF — модуль платформы, который обрабатывает большинство взаимодействий с Windows от имени клиентского драйвера. Он предоставляет интерфейсы драйвера устройства в пользовательском режиме (DIS), которые клиентский драйвер может использовать для выполнения распространенных задач драйвера.
  • Dispatcher — механизм, запускающийся в хост-процессе; определяет, как пересылать запрос в режим ядра после его обработки драйверами пользовательского режима и достижения нижней части стека пользовательского режима. На рисунке диспетчер перенаправит запрос в библиотеку DLL пользовательского режима, Winusb.dll.
  • Winusb.dll — библиотека DLL,предоставляемая корпорацией Майкрософт в пользовательском режиме, которая предоставляет функции WinUSB , упрощающие обмен данными между драйвером клиента и WinUSB (Winusb.sys, загруженные в режиме ядра).
  • Winusb.sys — предоставленный корпорацией Майкрософт драйвер, который требуется для всех клиентских драйверов UMDF для USB-устройств. Драйвер должен быть установлен под отражателем и выступает в качестве шлюза к стеку USB-драйверов в режиме ядра. Дополнительные сведения см. в разделе WinUSB.
  • Стек драйверов USB — набор драйверов, предоставляемых корпорацией Майкрософт, которые обрабатывают обмен данными на уровне протокола с USB-устройством. Дополнительные сведения см. в статье Драйверы USB на стороне узла в Windows.

Всякий раз, когда приложение отправляет запрос на стек usb-драйвера, диспетчер ввода-вывода Windows отправляет запрос в отражатель, который направляет его в клиентский драйвер в пользовательском режиме. Драйвер клиента обрабатывает запрос, вызывая определенные методы UMDF, которые вызывают функции WinUSB для отправки запроса в WinUSB. После получения запроса WinUSB обрабатывает запрос или пересылает его в стек usb-драйверов.