Compartilhar via


Função ServiceMain do Serviço

Quando um programa de controle de serviço solicita que um novo serviço seja executado, o SCM (Service Control Manager) inicia o serviço e envia uma solicitação de início para o dispatcher de controle. O dispatcher de controle cria um novo thread para executar a função ServiceMain para o serviço. Para obter um exemplo, consulte Escrevendo uma função ServiceMain.

A função ServiceMain deve executar as seguintes tarefas:

  1. Inicialize todas as variáveis globais.

  2. Chame a função RegisterServiceCtrlHandler imediatamente para registrar uma função Handler para lidar com solicitações de controle para o serviço. O valor retornado de RegisterServiceCtrlHandler é um identificador de status de serviço que será usado em chamadas para notificar o SCM do serviço status.

  3. Executar inicialização. Se o tempo de execução do código de inicialização for muito curto (menos de um segundo), a inicialização poderá ser executada diretamente no ServiceMain.

    Se o tempo de inicialização for maior que um segundo, o serviço deverá usar uma das seguintes técnicas de inicialização:

    • Chame a função SetServiceStatus para relatar SERVICE_RUNNING, mas não aceite controles até que a inicialização seja concluída. O serviço faz isso chamando SetServiceStatus com dwCurrentState definido como SERVICE_RUNNING e dwControlsAccepted definido como 0 na estrutura SERVICE_STATUS . Isso garante que o SCM não enviará nenhuma solicitação de controle para o serviço antes de estar pronto e libera o SCM para gerenciar outros serviços. Essa abordagem de inicialização é recomendada para desempenho, especialmente para serviços de início automático.

    • Relate SERVICE_START_PENDING, não aceite controles e especifique uma dica de espera. Se o código de inicialização do serviço executar tarefas que devem levar mais tempo do que o valor inicial da dica de espera, seu código deverá chamar a função SetServiceStatus periodicamente (possivelmente com uma dica de espera revisada) para indicar que o progresso está sendo feito. Lembre-se de chamar SetServiceStatus somente se a inicialização estiver progredindo. Caso contrário, o SCM poderá aguardar o serviço entrar no estado SERVICE_RUNNING supondo que seu serviço esteja progredindo e impedir que outros serviços sejam iniciados. Não chame SetServiceStatus de um thread separado, a menos que você tenha certeza de que o thread que está executando a inicialização está realmente progredindo.

      Um serviço que usa essa abordagem também pode especificar um valor de ponto de marcar e incrementar o valor periodicamente durante uma inicialização longa. O programa que iniciou o serviço pode chamar QueryServiceStatus ou QueryServiceStatusEx para obter o valor de ponto de marcar mais recente do SCM e usar o valor para relatar o progresso incremental para o usuário.

  4. Quando a inicialização for concluída, chame SetServiceStatus para definir o estado do serviço como SERVICE_RUNNING e especifique os controles que o serviço está preparado para aceitar. Para obter uma lista de controles, consulte a estrutura SERVICE_STATUS .

  5. Execute as tarefas de serviço ou, se não houver tarefas pendentes, retorne o controle ao chamador. Qualquer alteração no estado de serviço garante uma chamada para SetServiceStatus para relatar novas informações de status.

  6. Se ocorrer um erro enquanto o serviço estiver inicializando ou em execução, o serviço deverá chamar SetServiceStatus para definir o estado do serviço como SERVICE_STOP_PENDING se a limpeza for longa. Após a conclusão da limpeza, chame SetServiceStatus para definir o estado do serviço como SERVICE_STOPPED do último thread a ser encerrado. Defina os membros dwServiceSpecificExitCode e dwWin32ExitCode da estrutura SERVICE_STATUS para identificar o erro.

Escrevendo uma função ServiceMain