Безобразие с Phantom Marker у устройств Windows
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.07.21 22:19
Оценка:
При установке своих виртуальных звуковых драйверов я создаю устройство в Enum\Root при помощи SetupDiCreateDeviceInfo, как это делает devcon install. Все прекрасно работает у десятков тысяч пользователей, начиная с Win2k, и до последних версий десятки. Но изредка (несколько раз в год) пользователи восьмерок и десяток жалуются, что то ли удаление, то ли установка проходят неудачно, и последующие попытки установки не могут создать устройство, поскольку оно уже установлено, однако в Device Manager его не видно, даже с DEVMGR_SHOW_NONPRESENT_DEVICES.

В какой именно ситуации это возникает, никто внятно объяснить не смог — к моменту обращения в поддержку они уже успевали по нескольку раз перегрузиться, запустить траблшутеры, чистильщики реестра и прочую хрень. Закономерность пока только одна — в Enum\Root остается ключ недоустановленного устройства с параметром Phantom (REGSTR_VAL_PHANTOM), значение которого 1.

Этот параметр создается во всех системах, начиная с 2k, при выполнении SetupDiCreateDeviceInfo (через MapperSeedKey), и остается, пока не будет выполнено DIF_REGISTERDEVICE. Возможно, установщик в этих редких случаях падает до вызова DIF_REGISTERDEVICE (хотя там падать просто негде), или падает где-то внутри стандартного обработчика DIF_REGISTERDEVICE.

Но вся беда в том, что устройства с ненулевым параметром Phantom невозможно найти и удалить штатными средствами. Они недоступны даже для SetupDiOpenDeviceInfo по Instance ID, тем более — для SetupDiGetClassDevs/DIGCF_ALLCLASSES и SetupDiEnumDeviceInfo. Соответственно, DevCon их тоже не находит. Config Manager их не трогает, своих ключей/значений там не создает.

У CM_Locate_DevNode есть флаг CM_LOCATE_DEVNODE_PHANTOM, но он не для этого:

CM_LOCATE_DEVNODE_PHANTOM — Allows a device instance handle
to be returned for a device instance that is not
currently alive, but that does exist in the registry.
This may be used with other CM APIs that require a
devnode handle, but for which there currently is none
for a particular device (e.g., you want to set a device
registry property for a device not currently present).
This flag does not allow you to locate phantom devnodes
created by using CM_Create_DevNode with the
CM_CREATE_DEVNODE_PHANTOM flag (such device instances
are only accessible by the caller who holds the devnode
handle returned from that API).


Фактически, "phantom devices" в виндовой документации обычно называют "nonpresent devices", которые просто не подключены. Параметра Phantom у таких устройств нет, и все рекомендации, которые гуглятся по ключевым словам (вроде этой или этой), для такого случая не годятся.

Проблему можно легко воспроизвести вручную, создав в Enum\Root любой двухуровневый ключ (например, "00000000\0000") с параметрами ClassGUID, HardwareID и Phantom, со значением последнего 1. Никаким средствами не получается его найти ни в семерке, ни в десятках. Если Phantom обнулить, то устройство становится "phantom" уже в смысле вышеупомянутых рекомендаций. CM_Get_Device_ID_List и SetupDiEnumDeviceInfo его еще не находят, зато CM_Locate_DevNode/CM_LOCATE_DEVNODE_PHANTOM и SetupDiOpenDeviceInfo — уже да. Если выполнить перестройку дерева, то CM сам подхватывает устройство и делает из него DevNode (что, впрочем, не делает его доступным для перечисления).

Мне надо как-то дать пользователю возможность удалить этот зависший ключ, или хотя бы удалить/обнулить параметр Phantom. Править Enum напрямую от имени администратора нельзя — только от имени системы. Приходится отправлять таким юзерам длинную инструкцию по скачиванию и запуску psexec, через который запускать reg delete.

А сегодня один продвинутый юзер, который сам пытался вручную удалить ключ из Enum, еще до того, как я успел отправить ему инструкцию, радостно написал: "нашел в реестре другой ключ с почти с таким же именем, без проблем его удалил, и все заработало". Где и что именно удалил — не помнит.

И что со всем этим можно делать, кроме как клепать для таких юзеров скрипт с psexec или программу, загружающую драйвер, который удалит зависший ключ? Может, таки есть какой-нибудь менее кривой способ найти/поправить его через штатные API?
windows device enum root phantom
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.