Crear e instalar un servicio Windows

 

Estos días he estado trabajando con servicios Windows, los cuales se utilizan para realizar operaciones en background. Una de las principales ventajas de los mismos es que tenemos la posibilidad de ejecutarlos sin necesidad de tener un usuario logado en el sistema. 

En este post voy a mostrar la forma de crear un proyecto con una pequeña demo y varias formas para instalarlo. 

Creación del proyecto

Creamos un proyecto del tipo de Windows Service. En este post lo llamaré CheckerWindowsService
 

 

Cuando carga la plantilla de Visual Studio, vemos que tenemos un nuevo archivo llamado Service1.cs y el típico Program.cs que acompaña a las aplicaciones de consola. Si accedemos al primero de ellos, nos mostrará la parte de diseño que básicamente es un fondo gris :D Si pulsamos sobre ella con el botón derecho y hacemos clic en View Code veremos la siguiente estructura: 

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text; 

namespace CheckerWindowsService
{
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
        } 

        protected override void OnStart(string[] args)
        {
        } 

        protected override void OnStop()
        {
        }
    }
} 
La clase Service1 debe heredar de ServiceBase para obtener todos los métodos y propiedades relacionadas con los servicios Windows. En esta plantilla se muestran los métodos que normalmente se sobrescriben: OnStart donde insertaremos el código que queremos que se ejecute nada más iniciar el servicio y OnStop en el caso de que el mismo sea parado. Para este ejemplo, voy a renombrar la clase Service1.cs a CheckerService.cs

Implementación

Lo primero que debemos modificar son las propiedades del archivo CheckerService.cs 
 
  

 
Por nombrar algunas de las propiedades más utilizadas, AutoLog se utiliza para permitir que el servicio registre o no los inicios, paradas, etcétera en el visor de eventos del sistema (opción por defecto). CanPauseAndContinue nos da la posibilidad de pausar y continuar con la ejecución del servicio, CanStop pararlo (al hacer esta opción pasará por el método OnStop) y ServiceName donde asignamos el nombre del servicio. 

En esta demo lo que vamos a hacer es que cada minuto vamos a comprobar si existe algún proceso del explorador Firefox abierto y, de ser así, vamos a finalizarlo (y si se resiste matarlo :D ).  Sobre la vista de diseño pulsamos con el botón derecho y seleccionamos View Code para agregar lo siguiente: 
protected override void OnStart(string[] args)
{

   var timer = new Timer { AutoReset = true, Interval = 60000 };
   timer.Elapsed += timer_Elapsed;
   timer.Start();
}

private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    var processes = Process.GetProcessesByName("firefox");

    foreach (var process in processes)
    {
       process.CloseMainWindow();

       if (!process.HasExited)
       {
            process.Kill();
            process.Close();
       }
    }
}

Añadir Instalador

Una vez que tengamos nuestro código implementado, es necesario añadir un instalador a la solución. Para ello nos ponemos en el modo diseño y con el botón derecho seleccionamos Add Installer

 

 
 

En este momento se agregará una nueva clase llamado ProjectInstaller.cs con dos componentes. Hacemos clic sobre serviceInstaller1 donde indicaremos el nombre del servicio (el mismo ServiceName que en CheckerService.cs) y el tipo de inicio (Manual, Automático o Deshabilitado). Además podemos indicar el nombre a mostrar y una descripción de lo que hace la aplicación. Estos dos últimos datos serán los que se mostrarán en el listado de servicios de Windows. 
 
 
 
Por último, si seleccionamos el otro elemento, serviceProjectInstaller1, podemos seleccionar el tipo de cuenta con la que queremos que se ejecute el servicio. En este caso, utilizaré LocalSystem para tener los permisos suficientes para matar procesos. 
 

 

Instalación/Desinstalación

Para la instalación del servicio Windows tenemos varias alternativas: 
  • Utilizar la plantilla para el proyecto del tipo Setup Project
  • Crear instaladores con InstallShield.
  • El comando InstallUtil.exe desde la línea de comandos. 

Setup Project

Adjuntamos a nuestra solución un nuevo proyecto del tipo Setup Project.
 
 
Seleccionamos el proyecto que acabamos de crear y añadimos la salida del proyecto del servicio web. 
 
 

Aparecerá un cuadro de diálogo con el proyecto Windows Service por defecto donde dejaremos seleccionado Primary output y confirmamos.
 

 
En el Explorer Solution hacemos click en el botón Custom Actions Editor.

 

 

 

Y aparecerá una nueva ventana donde se alojan las acciones personalizadas. Con el botón derecho añadimos una nueva como se muestra en la imagen:
 

Seleccionamos Application Folder.
 

Y por último aparecerá únicamente Primary output from CheckerWindowsService que es la que añadimos anteriormente. Pulsamos en OK y ¡Listo!
 

 
Para instalarlo, compilamos nuestra solución y posteriormente el proyecto Setup Project. Seleccionamos el proyecto de instalación con el botón derecho y hacemos click en Install.

 

 
Para desinstalar la operación sería la misma pero con Unistall :D

InstallShield
De lo poco que pude trastear con InstallShield, pude ver que las opciones de configuración son mayores que con Setup Project y te permite una mejor personalización de las instalaciones.
 Si bien con Visual Studio 2010 puedes hacer uso de InstallShield Limited Edition.
 
 

Para poder crear un installer para un windows service necesitas tener al menos una versión Premium, obviamente de pago.

InstallUtil.exe 

Desde la línea de comandos también podemos instalar/desinstalar un servicio Windows. El comando InstallUtil.exe se instala automáticamente con Visual Studio y podemos ejecutarlo a través de Visual Studio Command Prompt.
 
Instalación

InstallUtil.exe miEjecutable.exe
Desinstalación
InstallUtil.exe /u miEjecutable.exe
Espero que os sea de utilidad :D  

¡Saludos!
 

12 comentarios en “Crear e instalar un servicio Windows”

  1. Gracias fravelgue por tu aportación 🙂

    @Jim, En primer lugar nadie dijo que lo aprendiera ayer 😉 y en segundo lugar no escribí nunca de ello y tengo el derecho de hacerlo cuando me parezca.

    ¡Saludos!

  2. @fravelgue, muy interesante lo que comentas.
    Me lo voy a mirar. 🙂

    @Jim, está claro que esta entrada no está dirigida a personas como tú que ya saben todo de todo, sino que van dirigidas a personas que no tienen tu extraordinario perfil.
    Agradeceríamos todos una entrada tuya aportando esos aspectos que hechas en falta a la entrada de Gisela y que consideras que debería tener.
    Así nos enriquecemos todos más y ya de paso escriben una entrada con cosas menos “peregrinas”.
    Estoy deseando leer tu artículo, ponnos la referencia por aquí para que nos sirva a todos.

    Muchas gracias. 🙂

  3. Seguro que el tal Jim nos hará el favor de dejarnos la url de su blog sobre computación neuronal y aplicación de la holografía para almacenamiento masivo, que seguro que es lo más básico que se dedica.

    Ah no, que simplemente eres un BOCAZAS.

  4. Siempre aparece algún @Jim aburrido en su casa. La personas con más de dos neuronas funcionando se toman un tiempo antes de faltar al respeto de forma gratuita.

    Desde aqui animo a @Jin a que exponga su gran nivel en forma de artículo/entrada/post/publicación en lugar de criticar al que no le agrada. Pensando un poco.. no será que tiene un problema que no sabe resolver y pretendía encontrar en la entrada de Gisela la solución? perphaps

    Ánimo y un saludo

  5. Thanks Gis,

    Como curiosidad, aparte del metodo “attach to process” hay un truco que me encanta (o encanto ya que hace ya minimi un año que no toco un servicio windows) que permite ejectuar y depurar directamente un servicio en visual studio, es tan tonto como invocarlo desde otra aplicación en la misma solución, una aplicación de consola u otro. otras formas son con instrucciones #if debug o atributos[conditional(“DEBUG SERVICE”)] para iniciar un modo de ejecución u otro.
    Dejo enlaces de referencia pero no los he probado :P.
    http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx
    http://stackoverflow.com/questions/125964/easier-way-to-start-debugging-a-windows-service-in-c

    Salu2 y que se porten bien los reyes con todos y todas!! 🙂

  6. Al menos el tal Jim no a insultado a diestro y siniestro, porque de tanto en tanto aparece alguno que en vez de agradecer el esfuerzo de una persona que aporta algo a la comunidad. Comienza a insultar demostrando su poca integración con la misma.

    Saludos 😉

  7. No hagan caso, la mayoría agradecemos estos artículos, yes más ojalá sigan así y en más profundidad. Nada resulta peregrino.

    salu2grz

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *