Windows Services
Serviços no windows nada mais são do que aplicativos que rodam em segundo plano,
normalmente, escritos para assumir uma tarefa especifica. Com esta simples afirmação traz à
tona vários momentos em que poderia ter sido escrito um serviço, mas ao invés disto, por um
motivo ou outro acabou sendo implementado um aplicativo, normal..., que fica-lá, ao lado do
relógio. (lembrou?).
Como dito, os motivos podem ser muitos, acredito que o principal é a falta de familiaridade
com os recursos da ferramenta de desenvolvimento ou os padrões de software adotados.
O momento certo para desenvolver um aplicativo as vezes passa despercebido pela maioria,
que vai logo em File | New | VCL Forms application... (acertei). A principal razão dos serviços é
que não devem ter contato com o utilizador, na verdade, o minimo possível, algo como nada
alem do iniciar e parar. Não que isto seja um fator limitador para o desenvolvimento, pois, um
serviço poderá como qualquer outro aplicativo ter suas configurações para determinar a sua
forma de execução, mas sim o ideal a ser feito.
As sugestões para desenvolvimento são:
a) O aplicativo precisará de alguma interação com o usuário? sim, (confirmação de alguma
coisa) desenvolva um aplicativo normal (VCL Forms Application).
b) O aplicativo será autosuficiente? sim, Crie um serviço (Service Application);
Criando um serviço simples
Crie um novo serviço pelo e salve os arquivos como segue:
Menu File | New | Other... Service
Application.
Unit1 – uWindowsService.pas
Project1 – WindowsService.dpr/droj
Por padrão sempre que um novo serviço é criado – TService1 (uWindowsService.pas) que é
uma especie de DataModule é criado, de forma a permitir a inclusão de componentes não
visuais, tais como queries e acesso a dados.
Altere a property Name deste serviço para srvWindowsServicesDemo (ou outro de sua
preferência, apenas lembre o nome dele)
Não cometa o engano de
continuar chamando isto de
DataModule, e sim, apenas
de serviço, pois, observe que
diferentemente as
propriedades são bem
diferentes.
Sobre as propriedades, bem sugestivas inclusive.
AllowPause: Permite que o serviço seja pausado, momentaneamente.
AllowStop: Permite que o serviço seja paralisado.
DisplayName: Nome de exibição;
ServiceStartName: Nome de usuário que o serviço utilizará para iniciar. Conforme o nível dos
usuários do windows, permitindo que rode à nivel (e com permissões) do usuário definido. O
padrão é Local System (em branco).
Password: Senha do usuário ou em branco para o nível padrão.
ServiceType: Tipo de serviço (são 3, serviço, driver e driver de serviço de arquivos)
StartType: Tipo de inicio do serviço.
Apenas ajuste a propriedade DisplayName por hora para: Demonstração ServDemo (ou algo
de sua preferência).
Caminho dos projeto (opcional)
Por padrão e opcional, aqui os arquivos do projeto serão salvos em locais separados. Este
ajuste pode ser realizado nas opções de projeto. (Ctrl + Shift + F11)
bin\ - local para arquivos de saida
(executavel e dlls compilados).
dcu\ - local para units compiladas.
Em resumo isto indica que quando
o projeto for compilado (F9) os
arquivos gerados pelo delphi serão
em locais separados, sempre nos
respectivos sub-diretorios do local
onde foi salvo o projeto. Isto é uma
opção particular, faça a sua!
Ex:
D:\WindowsServices\ + bin\
D:\WindowsServices\ + dcu\
Compilando o serviço
Compilar o serviço não tem nada de especial, mas antes disto existe algo de interessante a ver
no que tange como os serviçoes são executados. Você tranquilamente poderia pressionar F9 e
ver o serviço rodar ...e fechar sem fazer absolutamente nada, o que no momento é obvio.
Portanto apenas compile e veja o seguinte:
-install – utilizado para instalar um serviço no gerenciamento do windows;
-uninstall – utilizado para desinstalar um serviço
net start %NomeServico% - utilizado para iniciar um serviço
net stop %NomeServico% - utilizado para parar um serviço
net pause %NomeServico% - utilizado para pausar um serviço
net continue %NomeServico% - utilizado para continuar a execução do serviço
Para instalar o serviço é necessário faze-lo via linha de comando (existe formas via
programação, mas não serão abordadas aqui) e executar o aplicativo do serviço utilizando o
parametro desejado.
NomeServico.exe -Install ou
NomeServico.exe -Uninstall.
Aproveitando a linha de comando, utilize os comandos net start, net stop para deixar o serviço
rodando ou parado.
Duas imagens exibindo o serviço
rodando normalmente.
Mantenha esta tela aberta, irá
precisar da mesma mais vezes
até o final do artigo.
Eventos de um serviço
Como visto nas imagens anteriores nosso serviço não está exibindo a descrição do mesmo,
(esta funcionalidade não foi implementada na classe base TService) entretanto o meio simples
de definir a mesma é via programação, ajustando diretamente no registro do windows,
aproveitando para conhecer alguns eventos de TService.
Eventos de TService
Todos os nomes bem
sugestivos e seguindo o
padrão de outros
componentes já bem
conhecidos.
AfterInstall – Ocorre logo após a instalação do serviço, este será o evento utilizado para
registrar a descrição do serviço.
OnExecute – Semelhante ao execute de uma Thread, é onde o serviço propriamente faz o seu
trabalho.
OnStart – Indicado para iniciar o processamento do serviço, neste evento por exemplo
poderia ser utilizado para implementar a inicialização de uma Thread.
OnStop – Indicado para finalizar o processamento do serviço, neste evento por exemplo
poderia ser implementado a finalização de uma Thread;
OnPause – Indicado para implementar a pausa no processamento.
OnContinue – Indicado para implementar a continuação de execução de um processamento.
Código para definir a descrição do serviço é muito simples, será apenas instanciado um
manipulador do registro e atribuindo a descrição no local especifico, adicione o codigo abaixo
ao evento, que assim que instalado novamente a descrição será exibida!
...
uses
..., Registry;
...
...
procedure TsrvWindowsServicesDemo.ServiceAfterInstall(Sender: TService);
var
FRegistro : TRegistry;
begin
{ Manipulado do registro }
FRegistro := Tregistry.Create;
try
{ Abrir o local especifico e ajustas as infromações da descrição }
FRegistro.RootKey := HKEY_LOCAL_MACHINE;
if FRegistro.OpenKey('\SYSTEM\CurrentControlSet\Services\' + Name, False) then begin
FRegistro.WriteString('Description', 'Delphi - Windows Services exemplo');
FRegistro.CloseKey;
end;
finally
FRegistro.Free;
end;
{ Gravar mensagem nos eventos do windows, yes, você pode fazer isto! }
LogMessage('Descrição do serivço foi adicionada normalmente', EVENTLOG_SUCCESS);
end;
...
Apenas como titulo de exemplo, será utilizado os eventos Execute, Start, Stop, Pause e
Continue nos próximos sources para descrever um serviço simples, basicamente é um
contador, incrementando sequencialmente uma variável e respeitando os respectivos eventos
citados. Atente que para casos onde a tarefa executada seja mais longa (do que incrementar
uma variável) em termos de tempo de execução é aconselhado a implementação de uma
Thread própria para realizar tal tarefa, pois os métodos necessariamente precisam retornar o
mais rápido possível (já estão dentro de uma thread principal) evitando que o serviço pare de
responder ao gerenciador (windows).
...
private
{ Private declarations }
FCount : Integer;
FStop : Boolean;
...
...
procedure TsrvWindowsServicesDemo.ServiceStart(Sender: TService; var Started: Boolean);
begin
FCount := 0;
FStop := False;
end;
procedure TsrvWindowsServicesDemo.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
FStop
:= True;
Stopped := True;
LogMessage('Solicitação service stop', EVENTLOG_SUCCESS);
end;
procedure TsrvWindowsServicesDemo.ServicePause(Sender: TService; var Paused: Boolean);
begin
FStop := True;
Paused := True;
LogMessage('Solicitação service pause', EVENTLOG_SUCCESS);
end;
procedure TsrvWindowsServicesDemo.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
// FCount := 0; Se zerar vai não vai continuar de onde parou
FStop
:= False;
Continued := True;
LogMessage('Solicitação service continue', EVENTLOG_SUCCESS);
end;
procedure TsrvWindowsServicesDemo.ServiceExecute(Sender: TService);
begin
{ Como um serviço é uma thread e neste caso a tarefa é simples, nada mais justo do que fazer um loop na mesma.
Utilizado um if para não realizar processamento algum enquanto estiver paralisada.
}
while not Terminated do begin
if not FStop then begin
Inc(FCount);
LogMessage(Format('Contador %d', [FCount]), EVENTLOG_SUCCESS);
end;
{ Neste caso estritamente, atual como o conhecido Application.ProcessMessages.
A grosso modo, desta forma não interrompe a comunicação do serviço com o gerenciador.
Não seria necessário em caso de utilizar uma Thread especifica para fazer o trabalho }
Sleep(1000);
ServiceThread.ProcessRequests(False);
end;
end;
Facilmente os métodos OnStart e OnStop implementar um procedimento de persistência em
disco do contador para conseguir ser inicializado sempre no ultimo valor, mesmo após a
desinstalação-instalação do serviço.
Testando o serviço
Uma vez o serviço instalado, net start nele, e abra o visualizador de eventos do windows,
acompanhe a sequencia:
...
Contador 1
Contador 2
...
Contador 22
solicitação de service pause
net continue srvWindowServicesDemo
solicitação de service continue
Contador 23
Contador 24
...
Sugestões
Se você estiver implementando, compilando, testando o serviço, evento por evento
provavelmente encontre algumas dificuldades onde sugere que o aplicativo (serviço) esteja em
uso, impedindo a compilação, tente apenas renomear para outro nome qualquer e em seguida
tente compilar novamente.
Em alguns casos, conforme o andamento da implementação dos metodos, é possível apenas
utilizar os comandos Net Stop/Start via comando para compilar (e substituir) o serviço.
Em outros casos, apenas o gerenciador de tarefas resolveu :-P;
Revisão: Elazar Dornelles Ceza – 2013.05.02.0124 – Criação do artigo.
Download

Windows Services Serviços no windows nada mais são do que