Delphi: rodando um executável como um Serviço do Windows

Publicado por Marcos Dell Antonio em 28/06/2007 | Delphi

[Update 04/07/2007] Se você pretende criar uma aplicação para rodar como serviço e sabe que ela precisará de uma interface gráfica para entrada de dados, a melhor solução é criar o serviço em um projeto e a GUI em outro (dois executáveis).

Desta forma, você deverá estabelecer algum meio de comunicação entre a GUI e o serviço. Para isto, poderá usar sockets, objetos distribuídos (acho que não compensa), named pipes ou qualquer outro recurso de compartilhamento de memória entre processos.

Estas foram as conclusões que eu e outro colega de trabalho chegamos após diversos testes com um serviço que precisava de uma interface para administrá-lo. [Fim do update]

Os serviços do windows são uma boa solução quando você precisa executar alguma tarefa antes do login de qualquer usuário no sistema.

Na empresa onde trabalho atualmente, utilizamos esta tecnologia em um servidor que gerencia o acesso dos usuários ao sistema.

Neste post apresento como criar um serviço a partir de uma aplicação pronta. Além disso, também vou descrever alguns detalhes que só a experiência em trabalhar com esta tecnologia pode trazer à tona.

Os exemplos foram criados com base no Delphi 6 e utilizando o Windows XP.

- Criando o serviço

Antes de tudo, é claro, você deve ter uma aplicação normal para transformá-la em um serviço. Com ela aberta no Delphi, vá até o menu File / New / Other e escolha o item Service. Veja:

Delphi - Criando um novo serviço

Com o serviço criado (eu chamei de srvServidor) você deve fazer as seguintes alterações:

Projeto (dpr): o uses Forms deve ser removido e o SvcMgr adicionado. Além disso, o único objeto que deve ser criado na inicialização é o serviço. Veja:

Criação do serviço no dpr

Implementar o método Execute: o serviço possui um método chamado Execute. É nele que você deverá criar a tela principal da sua aplicação. Veja:

Método Execute do Serviço

Ignore por enquanto a inicialização do COM (método CoInitialize) . Ela será explicada mais adiante.

Instalar o serviço: a instalação de um serviço no windows é feita executando a aplicação com o parâmetro /INSTALL. A desinstalação é feita com o /UNINSTALL. Veja um exemplo:

Instalação de um serviço

- Adaptando o executável para rodar como um serviço

Existem diversas alterações que você deve fazer para rodar sua aplicação como um serviço. Abaixo segue uma lista das mais comuns.

Objeto TService

A primeira alteração deve ser feita no objeto TService criado anteriormente. Você precisa definir as seguintes propriedades:

  • DisplayName: nome que aparecerá na lista de serviços;
  • Interactive: define se o serviço poderá se comunicar com o Desktop ou não. Para mostrar um form ou até mesmo uma simples mensagem (ShowMessage, por exemplo), esta propriedade deve estar definida como true.

Inicialização do COM

Se a sua aplicação utiliza algum objeto COM, você deverá inicializar o suporte ao COM com o método CoInitialize. Isto pode ser visto no método Execute apresentado acima.

Sem esta alteração, provavelmente você receberá uma mensagem do tipo “CoInitialize has not been called” ao rodar o serviço.

Método GetCurrentDir

O método GetCurrentDir quando utilizado em um serviço retorna sempre c:\windows\System32. Eu não achei em lugar algum documentação que explicasse este comportamento.

Para contornar este problema, utilizei o ParamStr(0) juntamente com ExtractFilePath.

OnMouseLeave

Se você utiliza este evento em Labels (talvez em outros componentes também), terá que esquecê-lo. Em todos os testes que fiz o OnMouseLeave não foi executado. Logo, deixei de usá-lo.

FormStyle

O form principal de uma aplicação normalmente é do tipo fsMDIForm. Em um serviço você deverá alterar esta propriedade para fsNormal.

Nos testes que fiz, ao utilizar o tipo fsMDIForm não foi possível modificar a propriedade Visible de alguns frames.

É isso ae.

Até +.

14 comentários

  1. 1
    Frank // September 11th, 2007 at 11:33 am

    Bom Dia!

    Amigo!

    Não consegui seguir o seu exemplo para criar um serviço, tem como voce me enviar um exemplo, ou seja, os codigos de fontes de exemplo de serviço simples seu???

    Obrigado!

  2. 2
    Dianzinho // October 11th, 2007 at 11:37 pm

    Boa Noite, Amigo, fiz tudo do geitinho q vc mandou, intalou o servico de boa, mas dentro do meu form1 tenho link para outros forms, quando abrou esses forms, aparece normal mas nao esta hailitada a entrada de dados. POderia me ajudar ????

  3. 3
    Leandro // November 6th, 2007 at 1:50 pm

    Olá amigo, consegui utilizar o teu exemplo porém ao rodar aplicacao.exe /install no prompt do DOS não consigo obter a mensagem confirmando a instalação do serviço. E o serviço não entra na lista. Alguma idéia???

    Abraço
    Leandro.

  4. 4
    Celio // December 6th, 2007 at 1:17 pm

    Preciso de uma rotina onde eu habilito o serviço de mensagens do windows, como faço isto via programação em delphi ?
    por favor se alguém souber me retorne por e-mail: celioecarol@bol.com.br
    fico no aguardo de quem poder me ajudar, boa tarde.

  5. 5
    Paulo // December 7th, 2007 at 12:18 pm

    Celio…
    tenta olhar o comando “sc” do windows e ver o que consegue fazer.
    este comando manipula serviços do windows através de linha de comando.

    Você pode utiliza-lo no Delphi a partir dos comandos WinExec ou ShellExecute.

    OBS: eu nao cheguei a testar, mas acho que funciona.

  6. 6
    Jean Posser // November 27th, 2008 at 2:48 pm

    Excelente este código… me ajudou muito
    Obrigado

  7. 7
    LaBamba // December 12th, 2008 at 7:31 pm

    Fiz algumas mudanças que são necessárias: incuir a unit ActiveX na cláusula uses e mudei a chamada ao frmPrincipal evitando a mensagem de erro ao abrir o serviço.

    unit Servico;

    interface

    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;

    type
    TService1 = class(TService)
    procedure ServiceExecute(Sender: TService);
    private
    { Private declarations }
    public
    function GetServiceController: TServiceController; override;
    { Public declarations }
    end;

    var
    Service1: TService1;

    implementation

    uses ActiveX, Principal;

    {$R *.DFM}

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

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

    procedure TService1.ServiceExecute(Sender: TService);
    begin
    try
    CoInitialize(nil);
    try
    //frmPrincipal := frmPrincipal.Create(nil);
    Application.CreateForm(TfrmPrincipal, frmPrincipal);
    frmPrincipal.Show;
    except
    on E:Exception do
    ShowMessage(’Erro ao abrir o COM+ : ‘+E.Message);
    end;

    while (not(Self.Terminated)) do
    ServiceThread.ProcessRequests(true);
    finally
    frmPrincipal.Free;
    CoUninitialize;
    end;
    end;

    end.

  8. 8
    Márcio Elias // January 2nd, 2009 at 4:27 pm

    Bom, consegui fazer funcionar o serviço, porem o mesmo seria o responsável por atualizar uma base MySQL remota partir de Arquivos DBF, esses arquivos estão em uma unidade de rede mapeada, e rodando como serviço os mesmos não são encontrados pela aplicação, se rodar como uma aplicação standalone normal, não tenho esse problema… O que pode ser isso, tenho que habilitar alguma dependência no meu serviço???

  9. 9
    Leonardo // March 11th, 2009 at 10:41 am

    Cara não gostei da explicação, não da para entender nada !

  10. 10
    Rafael Cristian // October 15th, 2009 at 9:16 pm

    Boa noite,

    Estou montando uma aplicação em delphi onde capturo a tela e armazeno em um JPG até ai tudo bem. Mas precisava que colocar essa aplicação para rodar como serviço. Utilizei o seu post que explica como rodar uma aplicação feita em delphi como serviço, so que quando executo essa aplicação como serviço ele captura a tela com tudo em branco. O estranho que se rodar sem ser via serviço ele captura normalmente. Utilizo a seguinte função para capturar a tela
    BitBlt( Canvas.Handle, 0, 0, Width, Height, ScreenDC, Left, Top, SRCCOPY );

    Por que será que quando coloco como serviço essa função captura a tela como em branco ???
    Desde ja agradeço

  11. 11
    José Spolaor // January 5th, 2010 at 8:22 am

    Spolaor aqui! Como eu crio um serviço em DOS?

  12. 12
    Suesley // February 22nd, 2010 at 11:20 am

    Ei teria como você enviar o arquivo fonte para o meu email ou postar um link para download do código fonte, não consegui fazer funcionar está dando problema na CoInicialize…

    Att:
    Suesley Sunnie

  13. 13
    dj rastfary // March 9th, 2010 at 12:17 pm

    tem alguem ai que sabe mediser como eu faço pramodificar um executavel que foi criado em delfhi tipo asim eu quero modicar todo o pro grama reno mear quem poder me ajudar eu ficarei muito grato o brigado ??

  14. 14
    zedaneves // January 3rd, 2012 at 2:38 pm

    Alguém um programa simples desse de serviço funcionado. que possa mandar o código fonte para eu examinar.

Deixe o seu comentário

Anúncios

Anúncio provido pelo BuscaPé