Partilhar via


Serviço ServiceMain Função

Quando um programa de controle de serviço solicita que um novo serviço seja executado, o Gerenciador de Controle de Serviço (SCM) 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çãoRegisterServiceCtrlHandler imediatamente para registrar uma funçãoHandlerpara lidar com solicitações de controle para o serviço. O valor de retorno de RegisterServiceCtrlHandler é um identificador de status de serviço que será usado em chamadas para notificar o SCM do status do serviço.

  3. Execute a inicialização. Se se espera que o tempo de execução do código de inicialização seja muito curto (menos de um segundo), a inicialização pode ser executada diretamente no ServiceMain.

    Se se espera que o tempo de inicialização seja superior a um segundo, o serviço deve usar uma das seguintes técnicas de inicialização:

    • Chame a função SetServiceStatus para relatar SERVICE_RUNNING mas não aceite nenhum controle 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 que ele esteja pronto e libera o SCM para gerenciar outros serviços. Essa abordagem de inicialização é recomendada para desempenho, especialmente para serviços de inicialização automática.

    • Relatório SERVICE_START_PENDING, não aceite nenhum controle 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, o código deverá chamar a função SetServiceStatus periodicamente (possivelmente com uma dica de espera revisada) para indicar que o progresso está sendo feito. Certifique-se de chamar SetServiceStatus somente se a inicialização estiver progredindo. Caso contrário, o SCM pode aguardar que o serviço entre no estado SERVICE_RUNNING, supondo que o serviço esteja progredindo e bloqueando a inicialização de outros serviços. Não chame SetServiceStatus de um thread separado, a menos que tenha certeza de que o thread que executa a inicialização está realmente progredindo.

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

  4. Quando a inicialização estiver 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 para o chamador. Qualquer alteração no estado do serviço justifica uma chamada para SetServiceStatus para relatar novas informações de status.

  6. Se ocorrer um erro durante a inicialização ou execução do serviço, o serviço deverá chamar SetServiceStatus para definir o estado do serviço como SERVICE_STOP_PENDING se a limpeza for demorada. Após a conclusão da limpeza, chame SetServiceStatus para definir o estado do serviço para SERVICE_STOPPED do último thread a ser encerrado. Certifique-se de definir o dwServiceSpecificExitCode e dwWin32ExitCode membros da estrutura SERVICE_STATUS para identificar o erro.

Escrevendo uma função ServiceMain