Serviços Win32 interagindo com dispositivos

Um serviço Win32 ideal instalado por meio do InF AddService que interage com dispositivos se comporta de forma semelhante à maneira 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 começar somente quando uma interface do 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 o comportamento indesejado e indefinido. Vamos percorrer 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 faz o serviço iniciar sob 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 do dispositivo chegar (consulte AddService para obter mais detalhes sobre AddTrigger). Veja abaixo um exemplo de como o 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 no 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, a primeira etapa do seu serviço deve ser registrar-se para receber notificações de interface do dispositivo. Diretrizes prescritivas sobre como fazer isso podem ser encontradas nesta página: Registrando-se para Notificação de Chegada da Interface do Dispositivo e Remoção do Dispositivo.

Em particular, você deve usar CM_Register_Notification com o flag CM_NOTIFY_FILTERY_TYPE_DEVICEINTERFACE para realizar o registro apropriado de notificações de 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 de uma 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á existem interfaces presentes.

Depois de se registrar para 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 da notificação via callback. Para consultar a lista de interfaces de dispositivo existentes para examinar 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 chance de a interface do dispositivo chegar entre o registro 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 no retorno de chamada de notificação e na lista de interfaces do dispositivo.

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

A próxima etapa é registrar notificações secundárias por alça para ser notificado sobre alterações de estado no dispositivo, como tentativas de consultar ou remover o dispositivo ou o dispositivo sendo desconectado. Isso pode ser feito usando CM_Register_Notification com o flag CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE. Seguir as diretrizes em Registrar-se para Notificação de Chegada da Interface do Dispositivo e Remoção de Dispositivos garantirá que, quando um dispositivo estiver sendo removido, o identificador possa ser liberado adequadamente.

As chegadas e remoções da interface do dispositivo devem ser controladas para que a remoção da última interface do dispositivo com a qual o serviço deseja interagir implique que o serviço pode ser interrompido. Depois que a última interface tiver sido removida, interrompa o serviço (informações detalhadas podem ser encontradas nesta página). Isso pode ser feito seguindo estas etapas:

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

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

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

Se o serviço estiver sendo interrompido, verifique e passe por todas as alças abertas existentes nas interfaces do dispositivo (talvez não haja nenhuma) e limpe-as.

A interface do dispositivo pode voltar durante a instalação do dispositivo, habilitar/desabilitar o dispositivo, renumeraçã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á iniciado com base no registro de inicialização do gatilho.

Esse fluxo garantirá que o serviço comece na chegada de uma interface do dispositivo e pare quando a última interface do 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: Exemplo de serviço Win32.

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