Запуск из хранилища драйверов

INF-файл, использующий "run from Driver Store", означает, что INF использует DIRID 13, чтобы указать расположение для файлов пакетов драйверов при установке.

Для файла run from Driver Store полезные данные, загруженные INF, поддирир, указанный в записи SourceDisksFiles для файла в INF, должен соответствовать поддирию, указанному в записи DestinationDirs для файла в INF.

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

Так как записи SourceDisksFiles не могут содержать несколько записей с одинаковыми именами файлов и CopyFiles нельзя использовать для переименования файла, каждый файл run from Driver Store, который ссылки INF должны иметь уникальное имя файла.

Пакеты драйверов имеют общую поддержку запуска из Магазина драйверов, начиная с Windows 10 1709. Однако некоторые стеки устройств могут устанавливать дополнительные ограничения на файлы, необходимые для подключения к этому стеку. Ниже приведены некоторые примеры стека устройств, которые не поддерживают запуск из Магазина драйверов до Windows 10 1803:

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

Динамическое поиск и загрузка файлов из хранилища драйверов

Иногда требуется загрузить файл, который является частью пакета драйвера, использующего "run from Driver Store". Пути к этим файлам пакетов драйверов не должны быть жестко закодированы, так как они могут отличаться от разных версий пакета драйвера, разных версий ОС, разных выпусков ОС и т. д. Когда возникает такая необходимость загрузки файлов пакетов драйверов, эти файлы пакетов драйверов должны быть обнаружены и загружены динамически с помощью некоторых парадигм, описанных ниже.

Поиск и загрузка файлов в одном пакете драйверов

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

Драйвер WDM или KMDF, работающий из магазина драйверов в Windows 10 версии 1803 и более поздних версиях, который должен получить доступ к другим файлам из пакета драйвера, должен вызывать IoGetDriverDirectory с DriverDirectoryImage в качестве типа каталога, чтобы получить путь к каталогу, из который был загружен драйвер. Кроме того, для драйверов, которые должны поддерживать версии ОС до Windows 10 версии 1803, используйте IoQueryFullDriverPath для поиска пути драйвера, получения пути к каталогу, из него и поиска файлов относительно этого пути. Если драйвер режима ядра является драйвером KMDF, он может использовать WdfDriverWdmGetDriverObject для извлечения объекта драйвера WDM для передачи в IoQueryFullDriverPath.

Двоичные файлы в режиме пользователя могут использовать GetModuleHandleExW и GetModuleFileNameW, чтобы определить, откуда был загружен двоичный файл. Например, двоичный файл драйвера UMDF может сделать следующее:

bRet = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
                         (PCWSTR)&DriverEntry,
                         &handleModule);
if (bRet) {
    charsWritten = GetModuleFileNameW(handleModule,
                                      path,
                                      pathLength);
    …

Поиск и загрузка файлов в любом пакете драйвера

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

Ниже приведены несколько примеров сценариев, которые могут включать загрузку файлов из пакета драйвера:

  • Библиотека DLL в пользовательском режиме в пакете драйвера предоставляет интерфейс для взаимодействия с драйвером в пакете драйвера.

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

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

Пакет драйвера обычно использует надстройку HKR для задания этого состояния. В этом примере следует предположить, что для ExampleFile.dllпакета драйвера есть запись SourceDisksFiles без поддира. Это приводит к тому, что файл является корнем каталога пакета драйвера. Следует также предположить, что директива DestinationDirs для copyFiles указывает значение 13.

Ниже приведен пример INF для задания этого состояния устройства:

[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg

[Example_DDInstall.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

Пример INF для задания этого состояния интерфейса устройства будет следующим:

[ExampleDDInstall.Interfaces]
AddInterface = {<fill in an interface class GUID for an interface exposed by the device>},,Example_Add_Interface_Section

[Example_Add_Interface_Section]
AddReg = Example_Add_Interface_Section.AddReg

[Example_Add_Interface_Section.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

В предыдущих примерах используется значение пустых флагов, которое приводит к REG_SZ значению реестра. Это приводит к тому, что %13% превращается в полный путь к файлу в режиме пользователя. Во многих случаях предпочтительнее иметь путь относительно переменной среды. Если используется значение флагов 0x20000 , значение реестра имеет тип REG_EXPAND_SZ, а %13% преобразуется в путь с соответствующими переменными среды, чтобы абстрагировать расположение пути. При получении этого значения реестра вызовите ExpandEnvironmentStrings , чтобы разрешить переменные среды в пути.

Если значение должно считываться компонентом режима ядра, значение должно быть REG_SZ значением. Когда компонент режима ядра считывает это значение, перед \??\ передачей его в API, например ZwOpenFile.

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

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

Код режима ядра должен получить PDO (физический объект устройства) на устройство с состоянием и вызвать IoOpenDeviceRegistryKey. Один из возможных способов получения PDO устройства в режиме ядра — обнаружить включенный интерфейс, предоставляемый устройством, и использовать IoGetDeviceObjectPointer для получения объекта устройства.

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

Кроме того , CM_Register_Notification можно использовать для уведомления о поступлении и удалении интерфейсов устройств, чтобы код был уведомлен, когда интерфейс включен, а затем может получить состояние. В классе интерфейса устройства может быть несколько интерфейсов устройств, используемых в приведенных выше API. Изучите эти интерфейсы, чтобы определить, какой интерфейс является правильным для чтения параметра.

После обнаружения правильного интерфейса устройства вызовите CM_Open_Device_Interface_Key.

Код режима ядра может получить имя символьной ссылки для интерфейса устройства, из которого требуется получить состояние. Для этого вызовите IoRegisterPlugPlayNotification , чтобы зарегистрировать уведомления интерфейса устройства в соответствующем классе интерфейса устройства. Кроме того, вызовите IoGetDeviceInterfaces , чтобы получить список текущих интерфейсов устройств в системе. В классе интерфейса устройства может быть несколько интерфейсов устройств, используемых в приведенных выше API. Изучите эти интерфейсы, чтобы определить, какой интерфейс является правильным, который должен иметь параметр для чтения.

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

Примечание.

Используйте флаг CM_GETIDLIST_FILTER_PRESENT с CM_Get_Device_ID_List_Size и CM_Get_Device_ID_List или флагом CM_GET_DEVICE_INTERFACE_LIST_PRESENT с CM_Get_Device_Interface_List_Size и CM_Get_Device_Interface_List. Это гарантирует, что оборудование, связанное с состоянием, содержащим путь к файлу, присутствует и готово к обмену данными.

Удаление пакета драйверов

По умолчанию пакет драйвера не может быть удален из системы, если он по-прежнему установлен на любых устройствах. Однако некоторые варианты удаления пакета драйвера из системы позволяют попытаться удалить его. Это пытается удалить пакет драйвера, даже если этот пакет драйвера по-прежнему установлен на некоторых устройствах в системе. Принудительное удаление не допускается для пакетов драйверов с файлами, которые выполняются из Хранилища драйверов. Когда пакет драйвера удаляется из системы, его содержимое хранилища драйверов удаляется. Если в пакете драйверов все еще установлены какие-либо устройства, все файлы драйвера запускаются из Хранилища драйверов в этом пакете драйверов, и отсутствующие файлы могут привести к сбою устройства. Чтобы предотвратить размещение устройства в плохом состоянии, пакеты драйверов, содержащие любые файлы Driver Store, не могут быть принудительно удалены. Их можно удалить только после того, как они больше не установлены на каких-либо устройствах. Чтобы помочь в удалении таких пакетов драйверов, можно использовать DiUninstallDriver или pnputil /delete-driver <oem#.inf> /delete . Эти методы удаления сначала обновят все устройства с помощью пакета драйвера, который удаляется, чтобы больше не устанавливаться с этим пакетом драйверов, прежде чем пытаться удалить пакет драйвера.

Разработка пакета драйверов

Тестирование частных двоичных файлов

При разработке пакета драйверов, если необходимо заменить конкретный исполняемый файл из пакета драйвера частной версией вместо полной перестроения и замены пакета драйвера в системе, рекомендуется использовать отладчик ядра вместе с командой Kdfiles. Так как полный путь к файлу в Магазине драйверов не должен быть жестко закодирован, рекомендуется, чтобы в сопоставлении kdfiles имя файла OldDriver было просто прямым именем файла без сведений о предыдущем пути. Чтобы упростить это (и другие сценарии), имена файлов в пакетах драйверов должны быть как можно более уникальными, чтобы он не соответствовал имени файла из не связанного пакета драйвера в системе.

Перенос INF для использования запуска из Хранилища драйверов

Если у вас есть существующий пакет драйвера с INF-файлом, который не используется из хранилища драйверов и переносит его для использования из Хранилища драйверов, в следующих примерах показано общее использование файлов в INFs и шаблонах для обновления этих файлов, которые будут выполняться из DriverStore.

Краткий справочник по обновлениям каталога назначения

В следующей таблице приведен краткий справочник по поиску соответствующих рекомендаций на основе текущего конечного каталога DIRID , указанного в inf-файле пакета драйвера.

DIRID Подкаталог Сведения
13 Файл уже используется в Магазине драйверов. Дальнейшая работа не требуется.
1 DIRID 1 не следует использовать. Нет никакой гарантии, что исходный каталог будет доступен при необходимости разрешения ссылки на файл. Вместо этого, если компоненты пакета драйверов зависят от определенных файлов, включите эти файлы в пакет драйвера и запустите их из хранилища драйверов.
10 Firmware (Встроенное ПО) Сведения о том, как использовать DIRID 13 с пакетом драйвера обновления встроенного ПО, чтобы использовать его с помощью Driver Store, см. в статье "Создание пакета драйвера обновления для".
10 См. другие файлы.
11 См. другие файлы.
12 UMDF См . двоичный файл драйвера UMDF.
12 Большинство файлов с назначением DIRID 12 представляют двоичные файлы службы драйверов. См . двоичный файл службы.
16422, 16426, 16427, 16428 Большинство файлов с назначением этих DIRID представляют установку приложения. Вместо этого предоставьте приложение универсальная платформа Windows (UWP) и установите его с помощью директивы AddSoftware из раздела DDInstall.Software пакета драйвера INF. Дополнительные сведения см. в разделе Связывание драйвера с приложением универсальная платформа Windows (UWP).

Двоичный файл службы

Если inf добавляет службу и двоичный файл не запускается из Хранилища драйверов, то ваш INF-файл может выглядеть следующим образом:

[DestinationDirs]
 ; Copy the file to %windir%\system32\drivers
 Example_CopyFiles = 12

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the file in %windir%\system32\drivers
ServiceBinary = %12%\ExampleBinary.sys

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

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleBinary.sys

Двоичный файл драйвера UMDF

Если ваш INF добавляет драйвер UMDF, а двоичный файл не запускается из Магазина драйверов, ваш INF-файл может выглядеть следующим образом:

[DestinationDirs]
; Copy the file to %windir%\system32\drivers\UMDF
Example_CopyFiles = 12, UMDF

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the file in %windir%\system32\drivers\UMDF
ServiceBinary = %12%\UMDF\ExampleUmdfDriver.dll
...

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

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleUmdfDriver.dll
...

Другие файлы

Если INF-файл, который может загружаться другими компонентами и не запускается из Магазина драйверов, то ваш INF-файл может выглядеть следующим образом. В этом примере только имя файла записывается в состояние реестра устройства. Компоненты, которые считывают это значение реестра, чтобы определить, какой файл будет загружаться в зависимости от файла, в который находится %windir%\system32 или в зависимости от порядка поиска LoadLibrary, способных найти файл.

[DestinationDirs]
; Copy the file to %windir%\system32
Example_CopyFiles = 11

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
HKR,,FileLocation,,"ExampleFile.dll"

Чтобы переместить этот файл, который будет выполняться из хранилища драйверов, необходимо обновить запись DestinationDirs, в которой файл будет скопирован в и обновить расположение, сохраненное в состоянии устройства. Для этого требуются компоненты, которые считывают это значение реестра, чтобы иметь возможность обрабатывать это значение реестра как полный путь к файлу вместо файла относительно %windir%\system32файла.

[DestinationDirs]
Example_CopyFiles = 13 ; update the destination to DIRID 13

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
; Point at the run from Driver Store file using DIRID 13
HKR,,FileLocation,,"%13%\ExampleFile.dll"