Por que eu devo ler este artigo: Esse artigo será útil para quem deseja aprender de uma forma bem simples como criar um serviço no Windows, abordando questões fundamentais como: o que é um Windows Service, como funciona, para que serve e o que é necessário para se desenvolver um aplicativo Windows Service.

Veremos todos esses conceitos aplicados em exemplos práticos, nos quais demonstraremos a utilização deste tipo de aplicação em cenários comuns, nos quais se faz necessária a execução de uma aplicação em segundo plano no sistema operacional, sem que haja interação direta com o usuário.

Vamos começar explicando um pouco, numa breve introdução, sobre no que consiste um Windows Service. Como o próprio nome diz, é um serviço do Windows, que nada mais é do que uma aplicação que inicia quando o Windows é carregado, ou sob demanda, e roda em segundo plano, ou seja, em background, enquanto o Windows estiver em execução.

Mesmo que você esteja na tela de login do Windows, por exemplo, o serviço pode estar sendo executado e fica residente na memória executando as operações que o serviço foi programado para realizar.

Os serviços do Windows sempre rodam em segundo plano no sistema operacional e são os responsáveis pelas tarefas essenciais, tais como serviços de impressão e serviços de e-mail.

Os serviços do Windows, quando inicializados corretamente, podem auxiliar no melhoramento do desempenho de sua máquina. É possível acessar determinado serviço desde que o mesmo esteja sendo executado e monitorar o desempenho e quais serviços estão sendo executados naquele momento pela CPU.

Existem muitos serviços que são conhecidos por todos, como os do SQL Server, do Microsoft Exchange, serviços de impressão, serviços de e-mail e etc.

Após a criação e construção do serviço, você poderá instalá-lo e executá-lo, o que pode ser feito usando o Gerenciador de Controle de Serviços, através da execução de comandos. Muitos desses comandos também podem ser realizados no Server Explorer ou no Service Controller, veremos tudo com mais detalhes mais adiante.

Uma aplicação Windows Service pode rodar em servidor ou estação de trabalho. Além disso, são frequentemente usados para executar o monitoramento de algum sistema, ou auxiliar algum sistema em tarefas que não dependem da interação com usuários.

Os Windows Services não estão disponíveis no Windows 95, 98 ou ME, você precisa ter uma versão do Windows NT ou superior (2000, XP, Vista, 7,8 ou Windows Server) para rodar esses serviços.

Através da ferramenta Visual Studio podemos criar um aplicativo que vai ser instalado como um serviço, onde você deverá definir as instruções antes de compilar o projeto e instalar em determinada máquina.

Mas antes de se criar um aplicativo Windows Service é necessário saber como manipular esses aplicativos, executando ações como Inicializar, Pausar, Parar e Finalizar esses serviços.

Todas essas ações podem ser desempenhadas via códigos dentro da aplicação, mas para o usuário final, ou qualquer um que não seja o próprio desenvolvedor, elas podem ser acessadas através de algumas etapas que serão mostradas logo a seguir.

Precisamos saber, antes de tudo, que as classes de serviço do Windows suportadas pelo .NET Framework não permitem a interação com estações interativas, que é o usuário conectado.

Um outro item importante é que o .NET Framework também não contém classes que representam estações e áreas de trabalho, e caso o seu serviço do Windows tenha que interagir com outras estações, vai ser preciso que você acesse a API do Windows não gerenciada.

Acessando os serviços do Windows

Antes de criar um novo serviço, vamos conhecer primeiramente a tela de serviços disponibilizados pelo Windows. Para acessar o “Sistema Gerenciador de Serviços do Windows” é necessário seguir alguns passos que vamos descrever a seguir.

Então, começaremos acessando o menu iniciar e clicando em painel de controle, depois em desempenho e manutenção, e por último em ferramentas administrativas e serviços.

Ou também por outro caminho, apenas clicando em Iniciar> Executar e digitando services.msc, como mostra a Figura 1. A tela de Executar também pode ser acessada utilizando o menu Windows + R.

Abrindo o gerenciador
de serviços a partir do menu Executar
Figura 1. Abrindo o gerenciador de serviços a partir do menu Executar.

Na Figura 2 vemos a tela de serviços do Windows, que exibe a relação dos serviços executados com várias informações sobre eles, como nome, descrição, status, tipo de inicialização, etc. Nesta tela também é possível iniciar, pausar e interromper os serviços, bastando clicar com a direita sobre eles ou usar o menu da barra superior.

Tela de serviços do Windows
Figura 2.Tela de serviços do Windows.

Criando um serviço

Agora que já sabemos o que é um Windows Service, vamos começar a criar a nossa aplicação no Visual Studio. Para os iniciantes em programação com o .NET Framework, pode ser um pouco confuso entender a lógica de como criar um aplicativo Windows Service, uma vez que se trata de um serviço e não será necessário possuir uma interface, o mesmo rodará em segundo plano em nossa máquina assim que for inicializado.

Mas iremos aprender passo a passo e você vai perceber que o processo é bem simples e então, após desenvolver e compilar nosso aplicativo, ele ficará apto a ser instalado e executado a partir de uma linha de comando "InstallUtil.exe", passando o caminho para o arquivo executável de serviço.

O sistema do Windows oferece um gerenciamento desses serviços que é o "Gerenciador de Controle e Serviços", o qual iremos entender com detalhes mais adiante.

Para iniciarmos, vamos começar criando um novo projeto no Visual Studio, primeiramente clicando em FILE, depois em New Project e na categoria Windows, escolhendo o template Windows Service. Em seguida vamos definir um nome e um local onde será salvo aquele projeto, conforme vemos na Figura 3.

Criação de um novo
projeto do tipo Windows Service
Figura 3. Criação de um novo projeto do tipo Windows Service.

Métodos OnStart e OnStop

Assim que criado o projeto, podemos perceber que foi criada uma classe com o nome padrão de Service1 e nela são implementados dois métodos: OnStart e OnStop, cuja função é descrita a seguir.

  • OnStart(): esse método é executado quando o serviço é iniciado, nele devemos efetuar qualquer processamento que seja necessário no início do funcionamento serviço.
  • OnStop(): esse método é executado quando o serviço é parado, aqui podemos executar algum código necessário quando o serviço receber o comando Stop, como registrar algum log.

Tempo de vida de um Windows Service

Um Windows Service é um serviço que passa por vários estados internos no tempo de vida. Assim que é instalado no sistema operacional e é inicializado, ele passa a executar os instaladores desenvolvidos para inicializar aquele aplicativo ou serviço e carrega o serviço no Gerenciador de Controle de Serviços para a máquina, de acordo com a instrução daquela aplicação desenvolvida.

O Gerenciador de Controle de Serviços é o utilitário central fornecido pelo Windows para administrar, inicializar e parar os serviços de acordo com suas necessidades.

Logo depois de executado e carregado, ele passa a adquirir o status de "Inicializado". Iniciar o serviço significa permitir que ele comece a funcionar. Pode-se iniciar o serviço através do Gerenciador de Serviço do Windows ou de seu próprio código, chamando o método criado para inicializar de acordo com seu código fonte.

Um serviço em execução pode existir nesse estado indefinidamente até que seja interrompido ou pausado, ou até que o computador seja desligado. Um serviço pode estar em um dos três estados básicos: Running (Executando), Paused (Pausado), ou Stopped (Parado).

Cada uma das ações de Iniciar, Pausar e Parar pode chamar um procedimento associado no serviço (OnStop, OnPause ou OnContinue), em que é possível definir o processamento adicional a ser executado quando o serviço altera o estado.

Assim que o serviço for desenvolvido, sua execução relata seu status para o Gerenciador de Controle de Serviço, para que os usuários possam determinar se um serviço está funcionando corretamente. Por padrão, os serviços herdados de ServiceBase relatam um conjunto limitado de configurações de status, inclusive Interrompido, Pausado e Em execução.

Se um serviço demora um pouco para inicializar, pode ser útil relatar um status “Iniciar pendente”, por exemplo.

É possível implementar as configurações de status Iniciar pendente e Parar pendente, adicionando código que chama a função do Windows SetServiceStatus.

Nosso aplicativo de serviço foi projetado para ser executado a longo prazo, por isso ele geralmente controla ou monitora algo no sistema.O monitoramento é configurado no método OnStart.No entanto, OnStart não realiza, de fato, o monitoramento.

O método OnStartdeve ser retornado ao sistema operacional depois que a operação do serviço tiver começado.Ele não deve entrar em loop contínuo ou bloquear.

Regras Para a Criação do Serviço

Antes de começarmos a desenvolver o serviço propriamente dito, precisamos saber que para se criar um serviço, é necessário seguir algumas regras como apresentado a seguir:

  • A propriedade ServiceName (nome do serviço) do projeto a ser desenvolvido deve ser definida durante o processo de desenvolvimento, ou seja, definir um nome para aquele serviço;
  • Criar instaladores para chamar determinado serviço;
  • Codificar os métodos OnStart e OnStop que se encontram vazios.

Após conhecer os métodos que iremos utilizar no desenvolvimento da aplicação, vamos desenvolver o serviço do Windows propriamente dito, de acordo com as listagens a seguir.

Nosso serviço realizará um monitoramento constante de um determinado diretório e fará cópias de seus arquivos quando forem criados. Obviamente, este é apenas um exemplo simples, mas que ilustra bem o funcionamento de um serviço.

Primeiramente, definiremos algumas variáveis e constantes básicas que serão utilizadas em toda a aplicação. A classe FileSystemWatcher nos permite “observar” um determinado diretório e receber notificações quando mudanças ocorrem em seus arquivos (arquivos criados, alterados ou removidos).

A constante ARQUIVOS indica o diretório que queremos gerenciar, e sempre que um novo arquivo for criado, faremos uma cópia dele para o diretório indicado pela constante ARQUIVOS_EXECUTADOS, de acordo com a Listagem 1.

Listagem 1. Definido variáveis básicas da classe.

  private FileSystemWatcher _watcher;
  const string ARQUIVOS = "C:\\Temp\\Arquivos";
  const string ARQUIVOS_EXECUTADOS = "C:\\Temp\\ArquivosExecutados";

Em seguida, precisamos instanciar nosso objeto _watcher no construtor da classe Service1 e definir um método para tratar seu evento Created, que é disparado sempre que um novo arquivo é criado no diretório (Listagem 2). O método _watcher_Created deve ser criado de acordo com a Listagem 3.

Listagem 2. Instanciando a classeFileSystemWatcher dentro do Service1.

  public Service1()
  {
       InitializeComponent();
       this._watcher = new FileSystemWatcher(ARQUIVOS);
       this._watcher.Created += new FileSystemEventHandler(_watcher_Created);
  }
Listagem 3. Método em que processamos o arquivo criado.


  void _watcher_Created(object sender, FileSystemEventArgs e)
  {
  File.Copy(e.FullPath, Path.Combine(ARQUIVOS_EXECUTADOS, e.Name), true);
  }

Para que o watcher funcione, é necessário habilitar a propriedade EnableRaisingEvents, que faz com que os eventos sejam disparados quando o diretório sofrer modificação. Como queremos que esse gerenciamento seja feito assim que o serviço for iniciado, devemos definir essa propriedade no método OnStart da classe Service1, de acordo com a Listagem 4.

Listagem 4. Ativando o processamento ao iniciar o serviço.

  protectedoverridevoidOnStart(string[] args)
  {
  this._watcher.EnableRaisingEvents = true;
  }

De forma semelhante, devemos também cancelar esse processamento (ou pausá-lo) quando o serviço for parado (seja definitivamente, ou de forma temporária). Para isso, basta definir a propriedade EnableRaisingEvents como false no método OnStop, de acordo com a Listagem 5.

Listagem 5. Definindo método OnStop.

  protectedoverridevoidOnStop()
  {
  this._watcher.EnableRaisingEvents = false;
  }

Agora que boa parte de nosso projeto está concluída, como mencionado anteriormente é necessário seguir algumas etapas para colocá-lo em correto funcionamento no sistema operacional. O que foi desenvolvido até agora foi basicamente a codificação do funcionamento do serviço.

O desenvolvimento da aplicação se encontra finalizado, agora é preciso que criemos um instalador e em seguida colocá-lo em execução no sistema Windows.

Testando o Projeto

Um Windows Service, como mencionado no início desse artigo, é uma aplicação que não possui uma interface e que para ser chamado é necessário inicializá-lo.

Para isso, é necessário que seja criado um instalador. Vamos primeiro testar o que foi feito até o momento, mas para testar nosso serviço não podemos simplesmente executá-lo a partir do Visual Studio, o processo é um pouco mais delicado, é necessário instalar nosso serviço no Windows, como dito anteriormente. Esse processo será melhor detalhado logo mais adiante.

Adicionando um instalador à aplicação Windows Service

O .NET Framework contém algumas classes que encapsulam o processo de instalação de serviços no Windows.

Para começar, vamos entender um pouco esse processo de instalação do serviço. Quando adicionamos um instalador ao nosso projeto, uma nova classe que recebe o nome deProjectInstaller vai ser criada, e dentro dela são vão ser criadas instâncias dos componentes de instalação.

Essa classe vai desempenhar um papel de um ponto central para todos os componentes de instalação do nosso projeto.

Nós não iremos precisar fazer nenhuma codificação especial dentro dos instaladores para que os serviços sejam instalados de forma correta.No entanto, você pode às vezes precisar de alterar o conteúdo dos instaladores caso necessite adicionar alguma funcionalidade especial no processo de instalação.

Similar à classe ServiceBase, também existem duas classes que pertencem ao namespace System.ServiceProcess que são a ServiceProcess e ServiceProcessinstaller. Mas antes vamos entender um pouco sobre o que são essas duas classes e para que cada uma delas serve:

  • A classe ServiceInstaller é a responsável por instalar um serviço e implementa a classe ServiceBase;
  • A classe ServiceProcessInstaller instala um executável que contém classes que estendem a classe ServiceBase, que no caso é o próprio serviço. É nela que são definidas as configurações de segurança e demais propriedades.

Devemos saber que para cada aplicativo de serviço existem no mínimo dois componentes de instalação na classeProjectInstaller, que são um que instala os processos para todos os serviços no projeto, e um outro instalador para cada serviço que o aplicativo possui.

Após a criação e construção do serviço, você poderá instalá-lo executando o utilitário de linha de comando InstallUtil.exe ou pode também instalá-lo usando recursos de implantação do Visual Studio.

Vamos clicar com o botão direito do mouse na região de design do serviço, que já se encontra aberta, e selecionar a opção Add Installer, como mostra a Figura 4.

Adicionando instalador pelo designer do serviço
Figura 4. Adicionando instalador pelo designer do serviço.

É necessário que destaquemos que existem três propriedades de extrema importância para o bom e correto funcionamento do serviço, que são as seguintes:

  • StartType: esta propriedade define o modo de inicializaçã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, iremos destacar também outras opções importantes, que são a 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: já 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á estiverem iniciadas.

Agora que sabemos que para ser criado um instalador de serviço, será necessário trabalhar com essas duas classes ServiceInstaller e ServiceProcessInstaller. Vamos agora implementar essas classes para a instalação do nosso serviço.

Precisamos definir também no projeto como esse serviço deverá ser inicializado. Na propriedade da classe ServiceInstaller é preciso definir a propriedade de StartType de como você deseja que o seu serviço seja inicializado as propriedades podem ser inicializadas como:

  • Disabled: O serviço não pode ser iniciado.
  • Manual: O serviço deve ser iniciado manualmente após a instalação.
  • Automatic: O serviço por si só irá iniciar sempre que o computador reinicializa.

Em nosso projeto vamos deixar a opção “Automatic”, que significa que sempre que o computador for ligado esse serviço será executado automaticamente.

Logo após finalizarmos o instalador do serviço, vamos instalá-lo no Windows. Para instalar um serviço no Windows é necessário usar o utilitário installutil.exe a partir do Visual Studio Command Prompt da seguinte maneira: C:\Windows\system32\installutil. Logo em seguida, informamos o caminho físico de nosso assembly, por exemplo: C:\ temp\serviceProcessInstaller1.exe, de acordo com a Figura 5.

Tela de instalação da
aplicação pelo Visual Studio Command Prompt
Figura 5. Tela de instalação da aplicação pelo Visual Studio Command Prompt.

Após cada uma dessas etapas ser concluída, finalizamos nossa aplicação Windows Service, agora ela já se encontra instalada no sistema operacional do Windows pronta para ser testada.

Para visualizar o serviço que desenvolvemos, basta acessar o formulário de Gerenciador de Serviços do Windows e teremos na tela do Windows Service a aplicação que acabamos de desenvolver pronta para ser inicializada, como mostra a Figura 6.

Tela de Gerenciamento
de Serviços do Windows com a nossa aplicação recém criada pronta para ser
inicializada.
Figura 6.Tela de Gerenciamento de Serviços do Windows com a nossa aplicação recém criada pronta para ser inicializada.

Nota: Caso você tenha o serviço instalado e deseje realizar algumas modificações é necessário que o serviço seja parado, a janela do gerenciador fechada e que seja desinstalado o serviço para que depois seja instalado novamente com as modificações desejadas.

Esse é um exemplo rápido e prático de como se desenvolver um aplicativo Windows Service. Como você pode ter visto, não é nada difícil desenvolver um serviço e ele é muito útil para aplicações de longa duração ou processos periódicos que não necessitam de interação com o usuário.

Os Windows Services são essenciais quando desejarmos monitorar o teclado, arquivos e pastas ou mesmo criar arquivos de log (que é o que faremos a seguir) quando determinados eventos ocorrerem.

Antes de seguirmos em frente, é interessante destacar que os aplicativos do Windows Service são executados em seu próprio contexto de segurança e iniciados antes mesmo do usuário efetuar logon na máquina onde os mesmos estão instalados.

É importante que você estude antes em qual conta de usuário o serviço será executado, pelo seguinte motivo: uma execução de serviço na conta de sistema tem mais permissões e privilégios do que em uma conta de usuário.

A seguir vamos desenvolver também um outro tipo de aplicação Windows Service para gravar de forma simples e segura em um arquivo de “log” sempre que ele for inicializado e finalizado.

Desenvolvendo um aplicativo Windows Service para registro de “log”

A estrutura do desenvolvimento da aplicação é basicamente a mesma do exemplo anterior, porém teremos que destacar alguns outros pontos que no exemplo anterior não houve a necessidade de usar, então vamos começar o desenvolvimento do nosso projeto.

Um Windows Service não provê meios de interação com o usuário e irá reportar o resultado e os seus eventos ao usuário através de mensagens no log de eventos. Essa versão que iremos utilizar já possui algumas classes que incluem algumas funcionalidades para criarmos um Windows Service e essas classes estão sob o namespace System.ServiceProcess.

Todo Windows Service roda com permissão de algum usuário, independentemente dos usuários ou programas que estão rodando no mesmo computador, estas aplicações rodam sob uma identidade de segurança, ou seja, não necessariamente a que está ligada na máquina no momento.

O Visual Studio oferece um template de projeto que automaticamente será a referência para este namespace e também provê alguns códigos de exemplo, porém não vai ser necessário o utilizar aqui.

Vale a pena ressaltar novamente que não será criada uma interface, pois se tratando de um serviço do Windows ele irá trabalhar em segundo plano, e a única forma possível de acessar o serviço é pelo Gerenciador de Serviço do Windows.

Antes de começarmos um novo projeto, vamos entender e aprofundar um pouco mais nosso conhecimento em algumas propriedades dessas classes que iremos utilizar no desenvolvimento do aplicativo Windows Service para arquivos de “log”.

A classe ServiceBase possui algumas propriedades, que são descritas a seguir:

  • AutoLog: esta propriedade é setada para True nos eventos de iniciar, parar, pausar e continuar.
  • CanHandlePowerEvent: esta propriedade, quando estiver com o valor igual a True poderá ser editado um código customizado para o OnPowerEvent.
  • CanPauseAndContinue: quando o valor estiver True, esta outra propriedade permite que o serviço seja pausado;
  • CanShutdown: já nesta propriedade, o valor True permite escrever um código customizado para o método OnShutDown;
  • CanHandleSessionChangeEvent: recebe um boolean determinando se o serviço pode obter eventos de mudança de sessão de um Terminal Server.
  • CanStop: normalmente o valor desta propriedade é setado para True e permite que o serviço possa ser parado;
  • EventLog: se o AutoLog estiver setado para true, a mensagem será escrita pelo Windows Application Event Log. Se setado para false poderá ser especificado uma mensagem customizada;
  • ServiceName: esta propriedade define ou retorna o nome do serviço.

Essa classe também possui alguns métodos importantes, que são os seguintes:

  • OnContinue: este método é usado para continuar rodando o serviço depois que ele for pausado;
  • OnCustomCommand: este outro método é usado quando é necessário implementar ações customizadas pelo objeto ServiceController;
  • OnPause: este método roda quando existir a necessidade de pausar o serviço;
  • OnPowerEvent: é chamado quando o status de energia do computador for alterado;
  • OnShutdown: roda antes do computador ser desligado;
  • OnStart: o código contido neste método roda quando o serviço é inicializado;
  • OnStop: o código implementado neste método roda quando o serviço for parado.
  • Run: esse método é estático e é executado no evento Main da aplicação. Ele tem dois overloads, um recebe uma instância da classe ServiceBase e o outro recebe um array de instâncias da classe ServiceBase. Sua finalidade é iniciar o(s) serviço(s).

Vamos utilizar também a classe ServiceInstaller, que é a classe responsável por instalar um serviço, ou seja, uma classe que implementa a classe ServiceBase. Essa é chamada quando o serviço está sendo instalado. Abaixo seguem apenas algumas de suas principais propriedades:

  • Description: esta propriedade recebe uma string contendo a descrição do serviço. Essa descrição é visualizada no SCM;
  • DisplayName: esta outra propriedade recebe uma string onde é definido o nome do serviço;
  • ServiceName: esta serve para indicar ao Windows o nome do serviço. Essa string deve ser exatamente igual à propriedade ServiceName da classe ServiceBase do serviço a ser instalado;
  • StartType: indica como o serviço será iniciado. Essa propriedade recebe uma das três opções do enumerador ServiceStartMode que são os seguintes: Automatic, Disabled e Manual.

A classe ServiceProcessInstaller instala um executável que contém classes que estendem a classe ServiceBase, ou seja, o serviço. É nela que devemos definir configurações de segurança do serviço.Account é a principal propriedade que a classe ServiceProcessInstaller possui e essa propriedade determina o tipo de conta de usuário que o serviço executará. Essa propriedade recebe uma das quatro opções do enumerador ServiceAccount:

  • LocalService: executará no contexto de uma conta de usuário sem privilégios no computador local mas com credenciais anônimas em computadores remotos;
  • LocalSystem: executará no contexto de uma conta de usuário com privilégios locais e credenciais em computadores remotos;
  • NetworkService: executará no contexto de uma conta de usuário sem privilégios no computador local mas com credenciais em computadores remotos;
  • User: essa é a opção default. Quando o serviço for instalado será requisitado ao usuário que digite o UserName e o Password para que o serviço execute sob essas credenciais.

É importante conseguirmos entender um pouco sobre algumas das propriedades vistas anteriormente para que possamos iniciar a construção desse outro aplicativo do Windows Service.

Ao desenvolver um serviço devemos saber que existem dois tipos de serviços que podem serem criados no Visual Studio. O primeiro tipo, que é o Win32wnProcess, para serviços que são o único serviço em processo.

E o segundo tipoque é o Win32ShareProcess, para serviços que dividem um processo com outro serviço. Podem ser criados outros tipos de serviços, porém fora do Visual Studio.

Agora que conhecemos um pouco mais sobre as classes que utilizaremos no desenvolvimento dessa nova aplicação, vamos aprimorar o que acabamos de conhecer colocando tudo na prática.

Não será necessário trabalhar com todos os métodos nem todas as propriedades que foram citadas acima. Para criar nossa aplicação de arquivos de log vamos utilizar apenas algumas e criarmos uma nova aplicação Windows Service, esse para gravar log em arquivos.

Vamos criar uma variável global, fora de qualquer método, do tipo da classe StreamWriter, que será nosso arquivo de log de acordo com a Listagem 6.

Listagem 6. Definindo variável da classe StreamWriter.

  namespace ArquivoLog
  {
      public partial class Service1 : ServiceBase
      {
          StreamWriter arquivoLog;
   
          public Service1()
          {
              InitializeComponent();
          }
      }
  }

No método OnStart vamos instanciar nosso StreamWriter, criar um arquivo de texto e já escrever nele a informação de quando o serviço foi iniciado, de acordo com a Listagem 7.

Listagem 7. Codificando o método OnStart para inicializar o serviço assim que for chamado.

  protected override void OnStart(string[] args)
  {
     arquivoLog = new StreamWriter(@"C:\\testandlog.txt", true);
     arquivoLog.WriteLine("Serviço iniciado em: " + DateTime.Now);
     arquivoLog.Flush();
  }

De forma semelhante, vamos escrever no artigo uma mensagem no momento em que o serviço for parado, como mostra a Listagem 8.

Listagem 8. Definindo o método OnStop.

  protected override void OnStop()
  {
  arquivoLog.WriteLine("Serviço encerrado em : " + DateTime.Now);
  arquivoLog.Close();
  }

Poderíamos ainda sobrescrever os métodos OnPause e OnContinue e efetuar um procedimento semelhante, registrando no arquivo as ações executadas e a mudança de estado do serviço.

Esse tipo de funcionalidade pode ser utilizada, por exemplo, no monitoramento de algum recurso do computador ou da rede, em que seja necessário registar os eventos ocorridos para posterior consulta.

Uma outra aplicação bastante útil seria a notificação do administrador do sistema, por e-mail, avisando que algum evento incomum, ou erro, ocorreu no sistema.

Depurar aplicativos Windows Service

Ao se desenvolver um aplicativo Windows Service, às vezes é necessário depurar seu código em execução, para isso ele deve ser executado de dentro do contexto do Gerenciador de Controle de Serviços, ao invés de dentro do Visual Studio, por esse motivo, depurar um serviço não é tão simples como depurar outros tipos de aplicativos do Visual Studio.

Para depurar um serviço, você deve iniciar o serviço e, em seguida, anexar um depurador ao processo no qual ele está sendo executado.Em seguida, você pode depurar seu aplicativo usando todas as funcionalidades de depuração padrão do Visual Studio.

Primeiramente é necessário anexar o depurador somente a um serviço que não esteja em execução.O processo de anexação interrompe o funcionamento atual do seu serviço, por isso é necessário parar o serviço, que pode ser acessado pelo “Gerenciador de Serviço do Windows”.

Depois de anexá-lo ao processo é necessário definir pontos de interrupção e usá-los para depurar seu código.Depois que sair da caixa de diálogo usada para anexá-lo ao processo, você estará efetivamente em modo de depuração.

Pode-se usar o Gerenciador de Controle de Serviços para iniciar, parar, pausar e continuar seu serviço. Posteriormente, você pode remover esse serviço fictício depois da depuração ser concluída com êxito.

Para se obter informações significativas para depuração, o depurador do Visual Studio deve localizar os arquivos de símbolo para os binários que estão sendo depurados.Se você estiver depurando um serviço que você criou no Visual Studio, os arquivos de símbolo (arquivos .pdb) estarão na mesma pasta que o executável ou biblioteca, e o depurador os carregará automaticamente.

Se você estiver depurando um serviço que não criou, deve primeiro localizar símbolos para o serviço e certificar-se de que eles podem ser encontrados pelo depurador.

Algumas dicas na hora da depuração: é importante ao depurar o programa, anexar o processo do serviço por partes, mas nunca à aplicação toda.

Caso o serviço já tenha sido inicializado, não será possível depurar o código no serviço do método OnStart ou o código no métodoMainque está sendo usado para carregar o serviço.

Uma maneira de contornar essa limitação é criar um segundo serviço temporário no seu aplicativo de serviço que existe somente para ajudar na depuração.Você pode instalar os dois serviços e, em seguida, iniciar o serviço fictício para carregar o processo do serviço.

Depois que o serviço temporário iniciar o processo, você pode usar o menuDepurardo Visual Studio para anexar ao processo do serviço. Você pode adicionar chamadas para o método Sleep para atrasar a ação até que você possa anexar o processo.

Se for o caso, altere o programa para um aplicativo de console regular. Para executarmos um serviço em modo de depuração precisamos primeiro instalá-lo. Depois disso, iniciamos o serviço (se o mesmo ainda não estiver iniciado).

Para fazer isso, reescreva o métodoMainpara que ele possa ser executado como um serviço Windows e como um aplicativo de console, dependendo de como for iniciado.

Para depurar um serviço é necessário que se siga alguns passos:

Crie seu serviço na configuração de depuração clicando em “Instalar Serviço” ou pelo atalho Ctrl+Alt+P na tela do projeto do Visual Studio, como mostrado na Figura 7.

Tela de Depuração onde é anexado um
processo à execução
Figura 7. Tela de Depuração onde é anexado um processo à execução.

Adicione um método para o serviço que executa os métodos OnStart e OnStop, e nele vamos fazer referência para que haja a depuração e em seguida após se inicializar o método OnStop interrompe esse serviço de acordo com a Listagem 9.

Listagem 9. Depurando um serviço no VisualStudio.

  Internal void TestStartupAndStop(string[] args)
  {
  this.OnStart(args);
  Console.ReadLine();
  this.OnStop();
  }

Em seguida, codifique o métodoMainpara executar a depuração de acordo com a Listagem 10.

Listagem 10. Definindo o método Main.

  namespace Gerenciamento_Arquivos
  {
      static class Program
      {
          static void Main()
          {
              ServiceBase[] ServicesToRun;
              ServicesToRun = new ServiceBase[] 
              { 
                  new Service1() 
              };
   
              ServiceBase.Run(ServicesToRun);
          }
      }
  }

Agora que o método Main está codificado e preparado para se executar a depuração, é só inicializar o projeto clicando em “Start” no Visual Studio ou pressionar a tecla de atalho F5.

Adicionando uma Conta de Sistema

Ao instalar um serviço o Windows usa um contexto, que é o de determinar quais privilégios este serviço vai poder e deverá usar, por isso precisamos incluir em nosso projeto uma conta de sistema, que será o contexto que o Windows necessita para instalar o serviço. Os tipos de contas existentes são as seguintes:

  • Local Service: é a conta que direciona o Windows para rodar o serviço no contexto de uma conta no sistema local que pode ter privilégios estendidos;
  • Network Service: direciona o Windows para rodar o serviço no contexto de uma conta sem privilégios no sistema local. O serviço apresentará as credenciais a um servidor remoto (usado com vários computadores em uma rede, por exemplo);
  • Local System: é a conta que direciona o Windows para rodar o serviço no contexto de uma conta sem privilégios no sistema local. O serviço apresentará credenciais anônimas para o servidor remoto;
  • User: esta outra conta direciona o Windows para rodar o serviço no contexto que solicita ao usuário um nome e senha válidos a cada momento que o serviço rodar.

Nessa aplicação iremos usar a conta Local System, por isso teremos que seguir alguns passos para configurar nossa aplicação. Vale destacar que poderia ser usada uma outra conta qualquer:

  • Primeiramente, pressione a tecla F4 em cima do serviceInstaller1 e vamos alterar as propriedades DisplayName e ServiceName para ExemploServico, que será o nome do nosso serviço, que será exibido no gerenciador de serviços;
  • Agora pressione novamente a tecla F4 em cima do serviceProcessInstaller1 e altere a propriedade Account para Local System, que será o tipo de conta que explicamos anteriormente. Vamos compilar nossa aplicação pressionando CTRL + SHIFT + B.
  • Em seguida, para instalarmos nosso serviço, teremos que usar o InstallUtil, utilitário específico do .NET para instalar serviços no Windows. Ele se encontra na pasta do .NET Framework.
  • Então, abra o prompt de comando do MS-DOS e navegue até a pasta referente à versão do .NET que estejam utilizando. Nela, abra o installutil.exe. Será apresentada logo em seguida uma lista de opções deste utilitário.
  • Para instalarmos nosso serviço, temos que ir à pasta em que o mesmo foi compilado, dentro da pasta Debug, que por sua vez fica dentro da pasta Bin, que logo está localizada dentro da pasta do seu projeto do Visual Studio, que nesse exemplo é a ExemploWindowsService.
  • Dentro desta pasta arraste o executável para a janela de comando, não podendo esquecer de digitar installutil antes do caminho do arquivo. Seu prompt deverá ficar conforme mostrado na Figura 8.
Prompt de Comando no
momento que é instalado o serviço no Windows
Figura 8. Prompt de Comando no momento que é instalado o serviço no Windows.

Agora com a aplicação criada, caso queira inicializá-la basta ir ao gerenciador de serviços e procurar pelo nome de seu serviço. Quando você encontrá-lo, clique com o botão direito em cima do serviço e por último clique em Iniciar, como é mostrado na Figura 9.

Tela de Gerenciador
de Serviços do Windows com a aplicação recém criada pronta para ser
inicializada.<
Figura 9. Tela de Gerenciador de Serviços do Windows com a aplicação recém criada pronta para ser inicializada.

Depois de inicializado nosso serviço, vamos agora verificar se ele foi executado corretamente, então basta ir no disco C: e verificar o arquivo testeLog.txt, que foi o arquivo criado no serviço conforme mostrado na Figura 10.

Arquivo .txt criado a
partir do serviço Windows Service com a data e hora que o aplicativo foi
finalizado
Figura 10. Arquivo .txt criado a partir do serviço Windows Service com a data e hora que o aplicativo foi finalizado.

Pronto, a nossa segunda aplicação foi criada e também já está funcionando. Como pode ser visto, na primeira aplicação desenvolvemos um simulador de monitoramento de arquivos e nessa segunda aplicação desenvolvida fizemos uma aplicação de um arquivo de log, ambas usando a mesma tecnologia e a mesma lógica.

É importante ressaltar que poderia ser criado um projeto com dois ou mais serviços. O que precisamos fazer após configurar o novo serviço é adicionar a instância desse serviço no método Main e adicionar também uma nova instância da classe ServiceInstaller ao arquivo ProjectInstaller.

Podemos fazer isso da mesma forma que adicionamos o instalador para o primeiro serviço, mas pode ser mais viável criar duas aplicações diferentes para acompanhar melhor o passo a passo de cada procedimento executado.

Removendo um Serviço

Caso você queira remover ou apagar algum serviço do Windows ao invés de apenas desativá-lo, por não estar sendo utilizado, ou estiver dando algum tipo de erro, também é possível pela linha do prompt de comando direto do Windows.

Então vamos aprender a como apagar um serviço. Mas primeiramente é necessário que você saiba que, uma vez o serviço apagado, ele não será reativado e dependendo do serviço não haverá possibilidade de recuperá-lo.

Começaremos clicando no menu Iniciar, então iremos pesquisar por “services” ou “serviços”. Também podemos simplesmente ir ao menu Executar e digitar “services.msc”.

Serão apresentados todos os serviços do Windows, ativados ou desativados. Vamos dar um duplo clique sobre o serviço que desejamos excluir, assim abrirá uma janela contendo as informações do mesmo, e nela você deverá copiar o nome do serviço.

Feito isso, abriremos o prompt de comando como Administrador (é possível pesquisar por cmd no menu Iniciar, clicar com a direita sobre o Prompt de Comando e depois em “Executar como Administrador”). Agora devemos executar o seguinte comando no prompt:

sc delete NOME-DO-SERVICO

Pronto, se você for até a janela de serviços do Windows, perceberá que o serviço não estará mais disponível, ou seja, foi removido. Sempre é essencial prestar atenção antes de excluir um serviço, para ter certeza, pois como dito anteriormente, após removido não terá volta.

Agora, de uma forma simples entendemos como funciona e também como criar um serviço do Windows, e vimos que não é complicado o desenvolvimento desse tipo de aplicativo. Esses serviços, embora o usuário não perceba sua execução, são essenciais para o bom funcionamento da máquina e facilitam o monitoramento da mesma.

Então, agora que este artigo explicou de forma simples e fácil na teoria e também na prática, basta você pensar e definir qual a sua necessidade no momento e criar um serviço, seguindo os passos expostos, que consiga satisfazer seu problema, daí podemos perceber o quão importante o Windows Serve é para resolver simples situações.

Além dessas funcionalidades, os serviços que são bem desenvolvidos, de forma correta, funcionam perfeitamente em sintonia com o sistema operacional, e que como podemos ver, existem alguns serviços que são necessários que sejam inicializados para que o sistema operacional possa ser executado.

Vale a pena ressaltar também que, caso pretenda excluir algum serviço do Windows por não estar sendo muito utilizado, confira sua relevância no sistema, para que não comprometa o funcionamento de algo ou que depois faça alguma falta ou caso que você deseje recuperá-lo, pois dependendo do tipo do serviço não haverá mais maneiras de recuperá-lo.

Alguns outros pontos são importantes de se destacar quando se trata da criação de uma aplicação Windows Service, por exemplo: devemos sempre evitar usar qualquer tipo de interface com o usuário, já que o serviço é feito exclusivamente para ser rodado em segundo plano, ou seja, totalmente oculto da visão do usuário.

Espero que tenham gostado desse artigo e tenham compreendido sobre o que é um Windows Service e como desenvolver um aplicativo que rode como um serviço em sua máquina.