Службы 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 . Следуя указаниям, приведенным в разделе Регистрация для уведомления о прибытии интерфейса устройства и удалении устройства , при удалении устройства дескриптор может быть освобожден соответствующим образом.
Необходимо отслеживать поступления и удаления интерфейса устройства, чтобы удаление последнего интерфейса устройства, с которым служба может взаимодействовать, означает, что служба может быть остановлена. После удаления последнего интерфейса остановите службу (подробные сведения можно найти на этой странице). Это можно сделать, выполнив следующие действия.
Публикация состояния SERVICE_STOP_PENDING в SCM, чтобы указать, что служба не работает
Отмена инициализация и очистка всего, что использовала служба
Публикация состояния SERVICE_STOP в SCM для завершения операции остановки
Если служба останавливается, убедитесь, что проверка для и пройти через все существующие открытые дескрипторы для интерфейсов устройств (возможно, их нет) и очистить их.
Интерфейс устройства может вернуться во время установки устройства, включения или отключения устройства, повторного перечисления устройства, перезагрузки системы или во время других сценариев, не указанных в списке. Когда интерфейс устройства вернется, служба запускается на основе регистрации запуска триггера.
Этот поток гарантирует, что служба запускается по прибытии интерфейса устройства и останавливается, когда последний интерфейс устройства больше не присутствует.
Пример кода & связанных ссылок
На сайте GitHub есть пример, в который показано, как служба может использовать этот поток событий. Пример можно найти здесь: Пример службы Win32.
Кроме того, полезную документацию по AddTrigger можно найти на странице AddService .