Поделиться через


Службы Win32, взаимодействующие с устройствами

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

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

Установка службы

Чтобы установить службу, используйте директиву INF AddService . Это позволит вам создать и запустить службу.

Добавьте параметр, который делает запуск службы по требованию. Это можно сделать, задав StartType=0x3 , что делает триггер службы запущенным.

Последний шаг этого раздела — использовать директиву AddTrigger для запуска службы при поступлении интерфейса устройства (дополнительные сведения о AddTrigger см. в разделе AddService). Ниже приведен пример использования AddTrigger:

[UserSvc_Install]
ServiceType   = 0x10 ; SERVICE_WIN32_OWN_PROCESS
StartType     = 3    ; SERVICE_DEMAND_START
ErrorControl  = 0    ; SERVICE_ERROR_IGNORE
ServiceBinary = %13%\oemsvc.exe
AddTrigger    = UserSvc_AddTrigger

[UserSvc_AddTrigger]
TriggerType = 1                           ; SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL
Action      = 1                           ; SERVICE_TRIGGER_ACTION_SERVICE_START
SubType     = %GUID_DEVINTERFACE_OSRFX2%  ; Interface class GUID
DataItem    = 2, "USB\VID_0547&PID_1002"  ; SERVICE_TRIGGER_DATA_TYPE_STRING

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

Время выполнения службы

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

В частности, следует использовать CM_Register_Notification с флагом CM_NOTIFY_FILTERY_TYPE_DEVICEINTERFACE для выполнения соответствующей регистрации уведомлений интерфейса устройства.

Замечание

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

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

Замечание

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

Если вы хотите взаимодействовать с интерфейсом устройства с помощью API для ввода-вывода, после того как вы нашли нужный интерфейс устройства, откройте дескриптор для интерфейса через CreateFile.

Следующим шагом является регистрация вторичных уведомлений для каждого дескриптора, чтобы получать уведомления об изменениях состояния устройства, например, попытки запроса на удаление устройства или отключение устройства. Это можно сделать с помощью CM_Register_Notification с флагом CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE . Следуя инструкциям по регистрации для уведомления о прибытии интерфейса устройства и его удалении, вы сможете надлежащим образом освободить дескриптор, когда устройство удаляется.

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

  1. Зарегистрировать состояние SERVICE_STOP_PENDING в SCM, чтобы указать, что служба останавливается

  2. Деинициализация и очистка всего, что использовалось службой

  3. Отправка состояния SERVICE_STOP в SCM для завершения операции остановки

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

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

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

На сайте GitHub представлен пример, который описывает, как служба может использовать этот поток событий. Пример можно найти здесь: пример службы Win32.

Кроме того, на странице AddService можно найти полезную документацию по AddTrigger.