Serviços Win32 interagindo com dispositivos

Um serviço Win32 ideal instalado via INF AddService que interage com dispositivos se comporta de forma semelhante a como um driver interage com dispositivos. Um driver é carregado e descarregado dependendo da presença de um dispositivo, e um serviço Win32 que interage com dispositivos deve seguir esse mesmo padrão de iniciar e parar , dependendo da presença de um dispositivo.

Os serviços devem ser iniciados somente quando uma interface de dispositivo estiver presente e habilitada para interagir e parar quando a interface do dispositivo não estiver mais habilitada. Esse padrão de design garante um serviço robusto que minimiza comportamentos indesejados e indefinidos. Vamos explicar como um serviço deve ser projetado para seguir esse padrão.

Instalação do serviço

Para instalar o serviço, use a diretiva INF AddService . Isso permitirá que você crie e inicie o serviço.

Adicione a configuração que define o serviço para iniciar mediante demanda. Isso pode ser feito definindo StartType=0x3 que faz com que o gatilho de serviço seja iniciado.

A etapa final nesta seção é usar a diretiva AddTrigger para iniciar o serviço quando uma interface de dispositivo chegar (consulte AddService para obter mais detalhes sobre AddTrigger). Abaixo está um exemplo de como AddTrigger deve ser usado:

[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

Observe que o HardwareId especificado em DataItem é opcional e geralmente só é necessário ao usar uma interface de classe genérica para definir o escopo do gatilho para um dispositivo mais específico.

Tempo de execução do serviço

Do ponto de vista do tempo de execução, o primeiro passo para o seu serviço deve ser registar-se para notificações da interface do dispositivo. Orientações prescritivas sobre como fazer isso podem ser encontradas nesta página: Registar-se para Notificação da Chegada e Remoção da Interface do Dispositivo.

Em especial, você deve usar CM_Register_Notification com a flag CM_NOTIFY_FILTERY_TYPE_DEVICEINTERFACE para realizar o registro apropriado das notificações da interface do dispositivo.

Observação

Quando um serviço está sendo iniciado, você não pode confiar no fato de que receberá notificações da interface do dispositivo, pois a notificação de chegada pode já ter passado, especialmente se a chegada da interface do dispositivo for a causa do início do serviço. Em vez disso, você deve obter uma lista de interfaces de dispositivo para verificar se já há interfaces presentes.

Depois de se registrar para receber notificações para interfaces de dispositivo, você será notificado sobre novas interfaces de dispositivo sendo habilitadas ou interfaces de dispositivo existentes sendo desabilitadas. Você pode descobrir o caminho da interface do dispositivo a partir do retorno de chamada de notificação. Para consultar a lista de interfaces de dispositivo existentes para examinar as interfaces de dispositivo que existiam antes do serviço ser iniciado e registrado para notificações, você pode obter uma lista de interfaces de dispositivo por meio de APIs como CM_Get_Device_Interface_List.

Observação

Há uma possibilidade de que a interface do dispositivo chegue entre o momento do registo de notificações e a recuperação de uma lista de interfaces de dispositivo já presentes no sistema. Nesse caso, a interface do dispositivo será listada tanto no callback de notificação quanto na lista de interfaces do dispositivo.

Se você quiser interagir com a interface do dispositivo com APIs de E/S, depois de encontrar a interface do dispositivo desejada, abra um identificador para a interface via CreateFile.

A próxima etapa é registrar-se para notificações secundárias por identificador para ser notificado de alterações de estado no dispositivo, como tentativas de consulta, remoção do dispositivo ou desaparecimento do dispositivo. Isso pode ser feito usando CM_Register_Notification com o indicador CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE. Seguir as orientações em Registrando-se para Notificação de Chegada e Remoção da Interface do Dispositivo garantirá que, quando um dispositivo estiver indo embora, a alça possa ser liberada de acordo.

As chegadas e remoções da interface do dispositivo devem ser rastreadas para que a remoção da última interface do dispositivo com a qual o serviço possa querer interagir signifique que o serviço possa ser interrompido. Uma vez que a última interface tenha sido removida, pare o seu serviço (informações detalhadas podem ser encontradas nesta página). Isso pode ser feito seguindo estas etapas:

  1. Postar SERVICE_STOP_PENDING estado para SCM para indicar que o serviço está caindo

  2. Desinicializar/limpar tudo o que o serviço estava usando

  3. Post SERVICE_STOP estado para SCM para concluir a operação de parada

Se o serviço estiver sendo interrompido, certifique-se de verificar e passar por todas as alças abertas existentes para interfaces de dispositivo (pode não haver nenhuma) e limpá-las.

A interface do dispositivo pode voltar durante a instalação do dispositivo, ativar/desativar o dispositivo, reenumeração do dispositivo, reinicialização do sistema ou durante outros cenários não listados. Quando a interface do dispositivo voltar, o serviço será acionado com base no seu registro de início por gatilho.

Esse fluxo garantirá que o serviço comece na chegada de uma interface de dispositivo e pare quando a última interface de dispositivo não estiver mais presente.

Há um exemplo no GitHub que explica como um serviço pode aproveitar esse fluxo de eventos. O exemplo pode ser encontrado aqui: Win32 Service Sample.

Além disso, você pode encontrar documentação útil sobre AddTrigger na página AddService .