10 de julho de 2010

Controlando Serviços do Windows através de APIs

Há situações em que um programa precisa obter informações a respeito de Serviços do Windows para saber seus estado atual ou até mesmo para instalar automaticamente um serviço que seja necessário.

Um exemplo é o programa que configura o Agendador da ABC71 - programa que executa processos e relatórios do nosso ERP previamente agendados. Uma das funções inerentes ao Configurador é exibir o status atual do Serviço de Agendamento, dando ao usuário rapidamente a informação se o Servfiço está instalado, se está em execução, etc.

O Windows fornece um conjunto de funções (APIs) para este tipo de operação. A base do acesso aos Serviços do Windows é o Service Control Manager (SCM), uma espécie de repositório que armazena as informações sobre os serviços. Como todo objeto do Windows, acessar o SCM exige a obtenção de um handle, que deve ser desalocado quando não for mais ser usado. Abra a conexão com o SCM usando a função OpenSCManager e notifique o fim do uso com CloseServiceHandle.
SC_HANDLE scmHnd = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (scmHnd != NULL)
{
/* ... */
CloseServiceHandle (scmHnd);
}
O último parâmetro de OpenSCManager estabelece o tipo de permissão de acesso será atribuída ao handle retornado e indicando o tipo de operação que poderá ser executada com esse handle. No código acima, usei o valor predefinido SC_MANAGER_ALL_ACCESS, que significa que o handle poderá ser usado em qualquer das funções da API de Serviços. No entanto, apenas processos com privilégios de administrador poderão obter um handle que permita instalar um novo serviço. Veja Access Rights for the Service Control Manager para mais informações.

Com handle para o SCM, podemos pesquisar o estado de um serviço e exibir este estado para o usuário. Para realizar uma operação num serviço que já existe, devemos antes abrí-lo como a função OpenService, que também retorna um handle. Com esse handle podemos, entre outras coisas, iniciar e interromper a execução do Serviço associado ou obter o estado atual dele:
SC_HANDLE sh = OpenService(scmHnd, "SchedService", SC_MANAGER_ALL_ACCESS);
AnsiString Status = "Status Desconhecido";

if (sh != NULL)
{
SERVICE_STATUS lpInfo;

if (QueryServiceStatus(sh, &lpInfo) )
{
switch (lpInfo.dwCurrentState)
{
case SERVICE_RUNNING :
Status = "está em execução";
break;
case SERVICE_STOPPED:
Status = "está interrompido";
break;
case SERVICE_CONTINUE_PENDING :
case SERVICE_START_PENDING :
Status = "está sendo iniciado";
break;
case SERVICE_PAUSE_PENDING :
case SERVICE_STOP_PENDING :
Status = "está sendo interrompido";
break;
case SERVICE_PAUSED :
Status = "está pausado";
break;
}
}
CloseServiceHandle (sh);
O nome do Serviço passado como parâmetro para o OpenService é o mesmo encontrado no console de Serviços existente nas Ferramentas Administrativas do Windows - acesse as propriedades do Serviço e veja o valor de Service Name.

A função QueryServiceStatus retorna uma estrutura do tipo SERVICE_STATUS preenchida com uma série de dados sobre Serviço, incluindo seu estado.

Há ainda funções para instalar e desinstalar um serviço, equivalentes a executar um serviço criado com Delphi ou C++ Builder com os parâmetros /INSTALL ou /UNINSTALL. Essas funções são CreateService para instalar um novo serviço (cujos parâmetros permitem estipular um nome interno e outro de exibição para o serviço, o tipo de inicialização desejado, credenciais para login no Windows, caminho do programa que executa o serviço, etc.) e DeleteService para remover do SCM um serviço.

Um comentário :

Anônimo disse...

Muito bom.

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.