Não é a linguagem de programação que define o programador, mas sim sua lógica

Service applications usando Delphi


Criando um serviço do windows podemos passar a responsabilidade de iniciar a aplicação para o próprio windows, deixando de ter a intervenção do usuário.
Vamos fazer um exemplo de um serviço que gera logs dos eventos disponível nele.

Então vamos começar basta ir em File >> New >> Other >> Delphi Projects >> Service Application:


Salve tudo projeto. O nome da Unit para Sistema e o Projeto para Log. Sua aplicação deverá ficar de acordo com a figura abaixo

 


Essa Unit criada contem uma espécie de DataModule que possui alguns eventos e propriedades cruciais para o funcionamento do serviço. Vejamos alguns dos principais funcionalidades:

Os eventos mais importantes são:
  • OnStart: Este evento é executado assim que o serviço é iniciado.
  • OnExecute: Este é o evento onde será implementado a funcionalidade do serviço, ele é executado logo após o evento OnStart, ou seja, quando o serviço entrar em execução definitiva. Funciona semelhante ao execute das threads.
  • OnStop: Este evento é executado assim que o serviço é parado.
  • OnPause: Este evento é executado quando o serviço é pausado.
  • OnContinue: Este evento é executando quando o serviço voltar a ser executado após uma pausa.
Eventos de instalação do serviço:
  • BeforeInstall / AfterInstall: Eventos executados antes (before) ou depois (after) da instalação do serviço

Propriedades cruciais para o bom funcionamento de um serviço do windows:
  • StartType: Esta propriedade define o modo de iniciação do serviço, por padrão essa opção vem marcada como stAuto que significa que o serviço será iniciado junto com o windows. Além da opção stAuto destaco a opção stManual que define que o serviço deverá ser iniciado manualmente e a opção stDisabled que define que somente um administrador pode iniciar o serviço.
  • DisplayName: Esta propriedade define o nome que será apresentado para o serviço no gerenciador de serviços do windows.
  • Dependencies: Define uma lista de dependências para a execução do serviço, ou seja, o serviço só será iniciado se todas as suas dependências (outros serviços) já estejam iniciados.
Então vamos começar a desenvolver:



Na propriedade DisplayName vamos colocar o nome do serviço que irá aparecer no Gerenciar de Serviços após sua execução.


Caso seja necessário que o serviço seja executado com credencias de um usuário que tem privilégios especiais você deverá informar o conteúdo das propriedades ServiceStartName (nome do usuário) e Password (sua senha).

const LOCAL_LOG = 'C:\Log.Text';

Agora que fizemos a função que ira gravar o Log, vamos implementar os eventos que irão gravar no log

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  FPrincipal.Controller(CtrlCode);
end;

function TFPrincipal.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TFPrincipal.SalvarLog(AMensagem: String);
var
  wLog: TStringList;
begin
  wLog := TStringList.Create;
  try
    try
      if FileExists(LOCAL_LOG) then
        wLog.LoadFromFile(LOCAL_LOG);
      wLog.Add(TimeToStr(Date) + ':' + AMensagem);
    except
      on e: exception do
      wLog.Add(TimeToStr(Date) + ':' + E.Message);
    end;
    wLog.SaveToFile(LOCAL_LOG);
  finally
    wLog.Free;
  end;
end;

procedure TFPrincipal.ServiceAfterInstall(Sender: TService);
begin
  SalvarLog('ServiceAfterInstall');
end;

procedure TFPrincipal.ServiceAfterUninstall(Sender: TService);
begin
  SalvarLog('ServiceAfterUninstall');
end;

procedure TFPrincipal.ServiceBeforeInstall(Sender: TService);
begin
  SalvarLog('ServiceBeforeInstall');
end;

procedure TFPrincipal.ServiceBeforeUninstall(Sender: TService);
begin
  SalvarLog('ServiceBeforeUninstall');
end;

procedure TFPrincipal.ServiceContinue(Sender: TService;
  var Continued: Boolean);
begin
  SalvarLog('ServiceContinue');
end;

procedure TFPrincipal.ServiceCreate(Sender: TObject);
begin
  SalvarLog('ServiceCreate');
end;

procedure TFPrincipal.ServiceDestroy(Sender: TObject);
begin
  SalvarLog('ServiceDestroy');
end;

procedure TFPrincipal.ServiceExecute(Sender: TService);
begin
  SalvarLog('ServiceExecute');
  while not self.Terminated do
    ServiceThread.ProcessRequests(true);
end;

procedure TFPrincipal.ServicePause(Sender: TService; var Paused: Boolean);
begin
  SalvarLog('ServicePause');
end;

procedure TFPrincipal.ServiceShutdown(Sender: TService);
begin
  SalvarLog('ServiceShutdown');
end;

procedure TFPrincipal.ServiceStart(Sender: TService; var Started: Boolean);
begin
  SalvarLog('ServiceStart');
end;

procedure TFPrincipal.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  SalvarLog('ServiceStop');
end;

Instalação do serviço

procedure TFInstalar.BtnInstalarClick(Sender: TObject);
var
  wLista: TStringList;
begin
  try
    wLista := TStringList.Create;
    if Sender = BtnDesinstalar then
      wLista.Text := 'Log /uninstall'
    else
      wLista.Text := 'Log /install';
    wLista.SaveToFile('Service.bat');
    Sleep(2000);
    ShellExecute(Application.Handle, nil, PChar('Service.bat'), nil, nil, 0);
  finally
    FreeAndNil(wLista);
    Sleep(2000);
    DeleteFile('Service.bat');
  end;
end;

procedure TFInstalar.ExibirNotificacao(const aMensagem: string);
var
  Notification: TNotification;
begin
  Notification := NotificationCenter.CreateNotification;
  try
    Notification.Title := 'Serviço';
    Notification.AlertBody := aMensagem;
    NotificationCenter.PresentNotification(Notification);
  finally
    Notification.Free;
  end;
end;

Exemplo acima 

Pode ser instalado por meio de linhas de comando
c:\windows | abra o prompt 

Agora dispare o seguinte comando:

C:\>Log.exe /install

Se o serviço for instalado com sucesso você verá a mensagem "Service installed successfully". 
Para desinstalar o serviço basta disparar:

C:\>Log.exe /uninstall

Se o serviço for desinstalado com sucesso teremos a mensagem "Service uninstalled successfully".


Criado e Instalado, vamos verificar se ele está funcionando, vá em Painel de Controle -> Ferramentas administrativas -> Serviços e veja se o serviço já está na lista de serviços e qual seu status.


Espero ter ajudado :) 

Exemplo: Download do exemplo

8 comentários:

  1. Boa tarde. Estamos em 2020! rs brincadeiras à parte...
    Estou com um exemplo simples, totalmente idêntico ao seu, mas está apresentando uma mensagem toda vez que inicializo o serviço. A mensagem é: "O Windows não pôde iniciar o serviço MyServiceTeste em Computador local. Erro 1067: O processo foi finalizado de forma inesperada."

    ResponderExcluir
    Respostas
    1. Boa tarde, hahha! Verificou o antivirus ou se algum ou processo do Windows esta barrando ele?

      Excluir
  2. Bom dia! Fiz um serviço e está funcionando bem, mas preciso colocar outras tarefas em um serviço. É possível criar um serviço que execute várias tarefas diferente com intervalos diferentes? Ou seria preciso criar um serviço diferente para cada tarefa?

    ResponderExcluir
    Respostas
    1. Bom dia! Um serviço pode executar varias tarefas com intervalos diferentes! Mas se as tarefas foram bem distinta uma da outra eu sempre acabo criado um serviço para cada tarefa para ter um melhor controle na hora de atualizar.

      Excluir
    2. Bom dia, já teve esse tipo de problema?
      quando tentamos executar um exe externo o mesmo aparece no gerenciador de tarefas mas não é exibido(show)? ex: se usarmos ShellExecute(Application.Handle, nil, PChar('C:\Windows\System32\calc.exe'), nil, nil, 0); porque a calculadora não é exibida mas dica no processo do windows?

      Excluir
  3. porque quando tentamos executar um exe externo o mesmo aparece no gerenciador de tarefas mas não é exibido(show)? ex: se usarmos ShellExecute(Application.Handle, nil, PChar('C:\Windows\System32\calc.exe'), nil, nil, 0); porque a calculadora não é exibida mas dica no processo do windows?

    ResponderExcluir
    Respostas
    1. Boa tarde! Isso ele não da o Show, mas pode fazer aparecer um icone no canto direito da barra (Perto da Data e hora) onde fica os serviços e dai fazer uma tela para dar o show de um form

      Excluir
    2. apenas quero que o serviço execute um exe e esse exe fique visivel.

      Excluir