От примера кода к рабочему драйверу — что изменить в примерах

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

Помимо описанных здесь изменений, все драйверы должны использовать рекомендации, описанные в разделах Создание надежных драйверов Kernel-Mode и Рекомендации по разработке драйверов для группы разработчиков Surface. Все драйверы также должны соответствовать рекомендациям, приведенным в руководстве по безопасности драйверов.

Примеры драйверов WDK — уникальные идентификаторы

Пакет драйверов Windows (WDK) содержит широкий спектр примеров драйверов, демонстрирующих полезные методы разработки драйверов. Эти примеры можно использовать в качестве основы для собственных драйверов, но перед выпуском драйвера необходимо изменить некоторые аспекты примера , помимо очевидного рабочего кода, чтобы они однозначно применялись к вашему устройству и драйверу. Записи драйверов иногда упускают из виду эти детали.

Конкретные элементы, которые необходимо изменить, зависят от примера к другому, но в целом они определяют конкретное устройство, интерфейс или драйвер. Например, если пример драйвера содержит любой из следующих элементов, необходимо изменить их для применения к драйверу и устройству:

  • Глобальные уникальные идентификаторы (GUID)

  • Имена символьных ссылок

  • Имя объекта устройства

  • Теги пула

  • Определения кода элемента управления ввода-вывода (IOCTL)

  • Имена всех файлов, копируемых в системную папку

  • Plug and Play идентификатор устройства, идентификатор оборудования и совместимые идентификаторы

  • Имя службы драйверов

  • Описание устройства

  • Файл ресурсов

Если вы забудете внести эти изменения, это может привести к сбою установки, конфликтам с другими устройствами и драйверами в системе, а также к трудностям при отладке, а также к другим ошибкам.

Например, если появляется сообщение об ошибке, указывающее ...\toastDrv\kmdf\toastmon\wdftoastmon.inx(18-18): error 1284: Class "Sample" is reserved for use by Microsoft. , что имя "Sample" должно быть изменено на уникальное имя для примера драйвера.

Идентификаторы GUID

Драйверы используют идентификаторы GUID для идентификации классов настройки устройств, классов интерфейса устройства, пользовательских событий PnP, пользовательских событий инструментария управления Windows (WMI) и поставщиков трассировки Windows PreProcessor (WPP). Некоторые идентификаторы GUID определяются корпорацией Майкрософт, а другие — поставщиками устройств и драйверов.

Идентификаторы GUID класса настройки устройства, GUID класса интерфейса устройства и идентификаторы GUID WMI для общих устройств и данных WMI определяются в WDK или в общедоступных файлах заголовков для использования любым драйвером. Эти идентификаторы GUID изменять не следует.

Например, если вы реализуете мышь, вы по-прежнему будете использовать GUID_DEVINTERFACE_MOUSE, которая определена в файле заголовка WDK Ntddmou.h, в качестве класса интерфейса устройства. Однако при определении нового класса настройки устройства необходимо создать новый GUID класса настройки устройства и имя класса установки, а также новый GUID класса интерфейса устройства. GUID класса установки и GUID класса интерфейса устройства должны быть уникальными значениями; они не могут совместно использовать GUID.

Для большинства драйверов на основе примеров следует изменить только идентификаторы GUID, которые определены в локальном заголовке или исходном файле примера и, таким образом, относятся к образцу. Такие идентификаторы GUID могут включать следующее:

  • Пользовательские события PnP

  • Пользовательские события WMI

  • Классы интерфейса устройства для новых или пользовательских устройств

  • Поставщики трассировки WPP

Использование GUID, определенного для другого драйвера, может вызвать конфликты, если оба драйвера загружены в одной системе. Например, если два разных драйвера используют один и тот же GUID для регистрации интерфейса устройства, клиенты, которые пытаются открыть интерфейс устройства, могут случайно открыть неправильное устройство.

Ниже приведен фрагмент из файла Driver.h, включенного во все примеры драйверов Тостера. Он определяет GUID интерфейса устройства для устройств Тостера:

DEFINE_GUID(GUID_TOASTER_INTERFACE_STANDARD, \
            0xe0b27630, 0x5434, 0x11d3, 0xb8, 0x90, 0x0, 0xc0, \
            0x4f, 0xad, 0x51, 0x71);
// {E0B27630-5434-11d3-B890-00C04FAD5171}

Если вы используете этот файл в собственном драйвере, обязательно замените образец GUID (показанный выше полужирным шрифтом) на GUID интерфейса для собственного устройства. Чтобы создать GUID, используйте средство Создания GUID в Microsoft Visual Studio или Guidgen.exe, которые входят в пакет sdk для Microsoft Windows. Затем можно связать GUID с символьной константой в файле заголовка драйвера, как показано в примере.

Вам также может потребоваться создать новые идентификаторы GUID для событий WMI драйвера. Примеры драйверов тостера определяют следующий ИДЕНТИФИКАТОР GUID для уведомления о прибытии устройства тостера:


DEFINE_GUID (TOASTER_NOTIFY_DEVICE_ARRIVAL_EVENT, \
             0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, \
             0x27, 0x25, 0xe2, 0x9c);
// {01CDAFF1-C901-45b4-B359-B5542725E29C}

Необходимо создать новый GUID для каждого события WMI в драйвере.

Если пример драйвера использует трассировку программного обеспечения WPP, создайте новый GUID поставщика трассировки для всех драйверов, которые вы используете на примере. Например, файл заголовка Trace.h примера Osrusbfx2 в %WinDDK%\Src\Kmdf\Osrusbfx2\Final определяет GUID элемента управления следующим образом:

#define WPP_CONTROL_GUIDS \
    WPP_DEFINE_CONTROL_GUID( \
           OsrUsbFxTraceGuid,(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \
        WPP_DEFINE_BIT(DBG_INIT)          /* bit  0 = 0x00000001 */ \
        WPP_DEFINE_BIT(DBG_PNP)           /* bit  1 = 0x00000002 */ \
        WPP_DEFINE_BIT(DBG_POWER)         /* bit  2 = 0x00000004 */ \
        WPP_DEFINE_BIT(DBG_WMI)           /* bit  3 = 0x00000008 */ \
        WPP_DEFINE_BIT(DBG_CREATE_CLOSE)  /* bit  4 = 0x00000010 */ \
        WPP_DEFINE_BIT(DBG_IOCTL)         /* bit  5 = 0x00000020 */ \
        WPP_DEFINE_BIT(DBG_WRITE)         /* bit  6 = 0x00000040 */ \
        WPP_DEFINE_BIT(DBG_READ)          /* bit  7 = 0x00000080 */ \
       )

В собственном драйвере текст, выделенный полужирным шрифтом, замените именем драйвера и созданным идентификатором GUID.

Если в примере определено имя символьной ссылки, замените имя в примере именем, которое применяется к вашему драйверу. Однако не изменяйте известные имена ссылок, например \DosDevices\COM1. Как правило, если имя ссылки очень похоже на имя образца (например, \DosDevices\CancelSamp), его следует изменить.

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

Драйвер фильтра тостера KMDF в %WinDDK\Src\Kmdf\Тостер\Filter создает символьное имя ссылки, в котором используется строка, определенная следующим образом в файле заголовка Filter.h:

#define SYMBOLIC_NAME_STRING     L"\\DosDevices\\ToasterFilter"

Измените полужирную строку, чтобы точнее описать собственный драйвер.

Имя объекта устройства

Если в примере создается имя объекта устройства, необходимо изменить имя при адаптации примера кода.

Драйвер фильтра тостера KMDF присваивает объекту устройства в файле заголовка Filter.h следующим образом:

#define NTDEVICE_NAME_STRING      L\\Device\\ToasterFilter

Как и в случае с именем символьной ссылки, необходимо изменить строку, чтобы описать драйвер.

Помните, что именованные объекты устройств могут представлять угрозу безопасности. Физические объекты устройств должны иметь имена, и большинство таких имен создаются системой, а не явно назначаются драйвером. Другие объекты устройства должны называться только в том случае, если они представляют объекты управляющего устройства, которые используются для взаимодействия по боковой полосе между приложением и драйвером. Платформа драйвера в режиме ядра (KMDF) и модель драйвера Windows (WDM) позволяют Windows создавать имя. Такой подход гарантирует, что имя объекта устройства является уникальным и что непривилегированные пользователи не могут получить к нему доступ. Дополнительные сведения см. в разделах Управление доступом к пространству имен устройств и Управление доступом устройств в драйверах KMDF.

Теги пула

Тег пула — это литерал с одним или четырьмя символами, который определяет определенное выделение памяти и может помочь в отладке.

Многие из примеров драйверов определяют тег пула в файле заголовка драйвера, как показано в следующей строке из Файла Тостер.h:

#define TOASTER_POOL_TAG (ULONG) 'saoT'

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

В файлеPooltag.txt перечислены теги пула, используемые компонентами и драйверами режима ядра, которые поставляются вместе с Windows. Pooltag.txt устанавливается вместе с WDK в папке %winddk%\Tools\Other<i>platform\Poolmon, где платформа — amd64, i386 или ia64. Не используйте теги, которые отображаются в этом списке.

Определения IOCTL

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

Например, пример Osrusbfx2 включает следующее определение для IOCTL_OSRUSBFX2_READ_SWITCHES:

#define IOCTL_OSRUSBFX2_READ_SWITCHES   
                    CTL_CODE(FILE_DEVICE_OSRUSBFX2, \
                             IOCTL_INDEX + 6, \
                             METHOD_BUFFERED, \
                             FILE_READ_ACCESS)

Для примера драйвера для другого устройства потребуется внести изменения в это определение.

Имена файлов

В INF или INX измените имена драйвера, предоставленного поставщиком совместного установщика и любых других файлов, копируемых процедурой установки в системную папку. Эти имена файлов обычно отображаются в разделах [SourceDisksFiles] и [ClassInstall32] inf и в записях CopyFiles .

Следующий пример из INX-файла для примера KMDF Featured Тостер, который доступен в папке %WinDDK%\src\kmdf\Тостер\Func\Featured. Имена файлов, которые необходимо изменить, выделены полужирным шрифтом:

[ClassInstall32]
Addreg=ToasterClassReg
CopyFiles=ToasterClassInstallerCopyFileshighlight

[ToasterClassReg]
...
HKR,,Installer32,,"tostrcls.dll,ToasterClassInstaller"
...

[ToasterClassInstallerCopyFiles]
tostrcls.dll									    
...

Чтобы адаптировать эту часть файла для другого драйвера, измените значение "tostrcls.dll" на имя файла установщика класса и измените строку "ТостерКлассУстановщик" для описания собственного установщика. Эти изменения гарантируют, что процедура установки копирует правильный файл совместного установщика и что раздел реестра записывает правильное имя файла.

Не изменяйте имена соинсталляторов, которые предоставляются в WDK или в Windows, таких как совместные установщики KMDF, UMDF и WinUSB.

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

[Toaster_Device.NT]
CopyFiles=Toaster_Device.NT.Copy

[Toaster_Device.NT.Copy]
wdffeatured.sys

В этом примере имя файла с полужирным шрифтом изменится на имя созданного файла драйвера.

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

Идентификатор устройства PnP, идентификатор оборудования и совместимые идентификаторы

Программа установки использует идентификатор устройства вместе с идентификаторами оборудования и совместимыми идентификаторами, чтобы выбрать INF-файл, используемый для установки устройства.

Идентификатор устройства — это строка, определяемая поставщиком, которая однозначно идентифицирует конкретное устройство. Каждое устройство имеет ровно один идентификатор устройства. Драйвер шины сообщает идентификатор устройства во время перечисления, и программа установки использует его для сопоставления устройства с правильным INF-файлом. Идентификатор устройства определен в разделе [Производитель] inf-файла.

В следующем примере показан идентификатор устройства OSR USB Fx2, как указано в файле Osrusbfx2.inx:

[Manufacturer]
%MfgName%=Microsoft,NT$ARCH$

; For Win2K
[Microsoft]
%USB\VID_045E&PID_930A.DeviceDesc%=osrusbfx2.Dev, 
        USB\VID_0547&PID_1002
...

; For XP and later
[Microsoft.NT$ARCH$]
%USB\VID_045E&PID_930A.DeviceDesc%=osrusbfx2.Dev, 
        USB\VID_0547&PID_1002

Чтобы адаптировать эту директиву INF для собственного драйвера, замените идентификатор устройства, выделенный полужирным шрифтом, на идентификатор устройства для собственного устройства. Также следует изменить название производителя на название вашей компании.

Идентификатор оборудования и совместимый идентификатор являются менее конкретными идентификаторами, которые программа установки использует, если не удается сопоставить идентификатор устройства с INF. Если inf может поддерживать другие устройства, следует изменить эти значения в дополнение к идентификатору устройства. В следующем примере из драйвера KMDF Featured Тостер показан идентификатор оборудования:


[Manufacturer]
%StdMfg%=Standard,NT$ARCH$

; For Win2K
[Standard]
; DisplayName                   Section           DeviceId
; -----------                   -------           --------
%ToasterDevice.DeviceDesc%=Toaster_Device, 
         {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster

; For XP and later
[Standard.NT$ARCH$]
%ToasterDevice.DeviceDesc%=Toaster_Device, 
         {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster

Чтобы адаптировать эту директиву INF для собственного драйвера, замените идентификатор оборудования идентификатором устройства драйвера и замените "MsToaster" более описательной строкой.

Имя службы драйверов

Измените имя службы в директиве AddService в INF до значения, соответствующего вашему драйверу. Если имя службы драйвера конфликтует с именем другого драйвера в системе, драйвер не будет устанавливаться или загружаться.

Драйвер KMDF Featured Тостер называет свою службу следующим образом:


[Toaster_Device.NT.Services]
AddService = wdffeatured, %SPSVCINST_ASSOCSERVICE%,
     wdffeatured_Service_Inst
      

Имя службы является первой записью в директиве AddService . Чтобы адаптировать INF-файл рекомендуемого тостера, вы измените строку, выделенную полужирным шрифтом, на строку, более подходящую для вашего драйвера. В этом примере запись wdffeatured_Service_Inst просто ссылается на раздел, определенный INF, поэтому его изменение не имеет критического значения.

Описание устройства

Описание устройства состоит из нескольких строк, которые обычно определяются в разделе [Строки] INF и используются в разных местах в inf. Например, в примере рекомендуемого тостера KMDF определяются следующие строки в файле WdfFeatured.inx:

[Strings]
SPSVCINST_ASSOCSERVICE   = 0x00000002
MSFT                     = "Microsoft"
StdMfg                   = "(Standard system devices)"
ClassName                = "Toaster"
DiskId1                  = "Toaster Device Installation Disk #1"
ToasterDevice.DeviceDesc = "Microsoft WDF Featured Toaster"
Toaster.SVCDESC          = "Microsoft WDF Toaster Featured Device Driver"

Чтобы изменить этот файл для установки собственного драйвера, следует изменить строки, выделенные полужирным шрифтом, чтобы они отражали сведения о вашей компании, устройстве и драйвере.

Если название компании также отображается в разделе [Производитель] в INF, необходимо также изменить его.

Файл ресурсов

Драйверы и другие компоненты, такие как примеры совместного установщика, также имеют файлы ресурсов (RC-файлы), которые определяют конкретные строки драйвера, включая название продукта, версию файла и название компании. Измените эти строки на соответствующие значения для пакета драйверов.

Сводка. Что делать?

Перед выпуском драйвера, основанного на примере WDK, замените все сведения, относящиеся к примеру, в исходных файлах, inf и других ресурсах, которые использовались для создания собственного драйвера. Требуемые изменения различаются в разных примерах, но обычно включают любые сведения, которые однозначно идентифицируют пример драйвера или его устройство. Ниже приведены типичные изменения, которые необходимо внести:

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

  • Обновите имя символьной ссылки.

  • Обновите имя объекта устройства или используйте автоматически созданное имя.

  • Используйте теги пула, которые идентифицируют драйвер и не конфликтуют с известными тегами.

  • Определите коды IOCTL, подходящие для драйвера и устройства.

  • Обновите имена всех файлов, скопированных в системную папку.

  • Вставьте правильные Plug and Play идентификаторы устройств, идентификаторы оборудования и совместимые идентификаторы в INF.

  • Обновите имя службы драйвера в INF-файле.

  • Измените описание устройства.

  • Измените все строки, относящиеся к драйверу, в файле ресурсов.

  • Придерживайтесь рекомендаций по обеспечению безопасности и надежности

Дополнительные сведения

Книги

Разработка драйверов с помощью Windows Driver Foundation, Пенни Орвик (Penny Orwick) и Гай Смит (Guy Smith)

Разделы WDK

Определение и экспорт новых идентификаторов GUID

Управление доступом устройств в драйверах KMDF

Разработка, тестирование и развертывание драйверов

Создание надежных драйверов Kernel-Mode

Рекомендации по разработке драйвера surface Team Driver

Руководство по безопасности драйверов

Написание первого драйвера