Cómo crear un servicio de Windows obediente en .NET.

Paso 1. Creamos el proyecto.
Para empezar simplemente iniciamos VisualStudio.NET (en mi caso 2005) y seleccionamos la opción para crear un nuevo proyecto. Ahí seleccionamos Servicio de Windows, le damos un nombre agradable (a poder ser más que WindowsService1, por ejemplo ServicioAlertas) y aceptamos. Nos aparecerá directamente la clase Service1.vb que también podemos renombrar a algo más intuitivo como clsAlert.vb.
Paso 2. Agregamos un instalador.
En la vista diseño de la clase que se nos ha creado hacemos clic con el botón derecho del ratón y seleccionamos la opción Agregar instalador. Con esto se nos creará la clase ProjectInstaller.vb que contiene dos controles: ServiceInstaller1 y ServiceProcessInstaller1. En mi caso renombro estos dos controles simplemente para eliminarles el 1 final (maniático que es uno). Del código de ProjectInstaller.vb nos olvidaremos por completo, pero vamos a hacer algún ajuste en las propiedades de estos dos controles.
Paso 3. Configuramos el instalador.
En el control ServiceInstaller modificamos las propiedades DisplayName y ServiceName para dejarlas ambas en ServicioAlertas. Modificamos también la propiedad StartType para dejarla en Automatic. Esto último sirve para que después cuando instalemos el servicio, éste quede puesto para que arranque automáticamente al iniciarse el sistema operativo. Si no se desea este comportamiento, ajustar esta propiedad según convenga. Es decir:
DisplayName: ServicioAlertas
ServiceName: ServicioAlertas
StartType: Automatic
En el control ServiceProcessInstaller modificamos la propiedad Account para dejarla en LocalSystem. Esto indica qué tipo de cuenta se utilizará para ejecutar el servicio. Podemos dejarla en User, pero después al instalar el servicio pedirá cuenta de usuario y contraseña, así que yo recomiendo pasarla a LocalSystem. Así pues:
Account: LocalSystem
Con la clase ProjectInstaller.vb hemos terminado ya por completo, ahora nos centraremos en clsAlert.vb.
Paso 4. Programamos el servicio.
Accedemos al código de la clase clsAlert.vb y observamos que por defecto ya se nos han generado dos métodos: OnStart y OnStop. Está claro para lo que sirven, ¿no? Eso es, para configurar qué hacer y cómo para arrancar y detener el servicio. Personalmente no utilizo el OnStop para nada, así que no hablaré de él, pero por supuesto el que esté interesado puede buscar más información en la propia ayuda del IDE o en internet. Me voy a centrar en el OnStart y voy a ponerle un temporizador para que cada 5 segundos me escriba en un log la hora actual. Sí, lo sé, es un servicio de alertas mediocre, pero servirá como ejemplo de código sencillo con el que programar un servicio y hacer uso, además, de un temporizador (cosa terriblemente útil en ocasiones).
Muestro el código íntegro que dejo pues en la clase clsAlert.vb:
'--------------------------------------------------------------------
' Author: Albert Mata (www.albertmata.net)
' Date: 20080723
' Description: Class to show how to create a Windows service and how
' to work with a timer.
'--------------------------------------------------------------------
Public Class clsAlert
'----------------------------------------------------------------
' Attributes.
'----------------------------------------------------------------
Private DBTimer As System.Timers.Timer
'----------------------------------------------------------------
' Starts service.
'----------------------------------------------------------------
Protected Overrides Sub OnStart(ByVal args() As String)
'Creating timer with interval = 5000 milisec = 5 seconds.
DBTimer = New System.Timers.Timer(5000)
DBTimer.Enabled = True
AddHandler DBTimer.Elapsed, AddressOf Me.ShowAlert
End Sub
'----------------------------------------------------------------
' Stops service.
'----------------------------------------------------------------
Protected Overrides Sub OnStop()
'Void, as I'm not using this method.
End Sub
'----------------------------------------------------------------
' Main process executed every time DBTimer gives a signal.
'----------------------------------------------------------------
Private Sub ShowAlert(ByVal source As Object, _
ByVal e As System.Timers.ElapsedEventArgs)
DBTimer.Enabled = False
Dim LogFile As New System.IO.StreamWriter("C:\log.txt", True)
LogFile.WriteLine("Alerta www.albertmata.net - " & Date.Now)
LogFile.Close()
DBTimer.Enabled = True
End Sub
End Class
Con esto tenemos terminado nuestro servicio de Windows. Ahora sólo nos falta instalarlo.
Paso 5. Generamos el ejecutable.
Generamos el ejecutable de nuestro servicio (Generar o Volver a generar). A partir de aquí no necesitamos más el IDE, de modo que podemos cerrarlo. A partir de ahora sólo necesitamos el .exe que se nos acaba de generar y un par de archivos .bat que vamos a crear a continuación (podríamos no generarlos y escribir las instrucciones directamente en línea de comandos, pero a mí me resulta más cómodo hacerlo en archivos batch). El archivo .exe (que encontramos en la carpeta bin/Release de nuestro proyecto ServicioAlertas) lo copiaremos en una ruta más corta (C:\). Y los dos archivos .bat que necesitamos son los siguientes:
Instalador.bat
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil
"C:\ServicioAlertas.exe"
pause
Desinstalador.bat
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil /U
"C:\ServicioAlertas.exe"
pause
En ambos las dos primeras líneas deben ser una única línea continuada (el ancho del blog no lo permite) y la ruta de la aplicación InstallUtil puede variar ligeramente en función de la versión del Framework que estemos utilizando. Basta con verificarlo con el Explorador de Windows y modificarla según convenga.
Para lo que sirven está claro: uno instala el servicio y el otro lo desinstala.
Paso 6. Instalamos el servicio.
Simplemente ejecutamos el archivo Instalador.bat y se nos abrirá una ventana de línea de comando con el proceso de la instalación terminando exitosamente. Ahora nos vamos a Panel de control - Herramientas administrativas - Servicios y encontraremos nuestro servicio ServicioAlertas. Lo iniciamos y observaremos al cabo de pocos segundos que en la ruta C:\ se nos ha creado un archivo log.txt. Si dejamos el servicio un rato funcionando y después lo detenemos veremos que este archivo ha quedado más o menos así:
Alerta www.albertmata.net - 23/07/2008 21:12:18
Alerta www.albertmata.net - 23/07/2008 21:12:23
Alerta www.albertmata.net - 23/07/2008 21:12:28
Alerta www.albertmata.net - 23/07/2008 21:12:33
Alerta www.albertmata.net - 23/07/2008 21:12:38
Paso 7. Desinstalamos el servicio.
Si en algún momento queremos desinstalar el servicio (si es tan poco útil como ServicioAlertas seguro que querremos) solo debemos ejecutar Desinstalador.bat y el servicio quedará desinstalado (tendremos que refrescar la lista de servicios para ver que efectivamente así es).
Con esto queda visto el tema de los servicios de Windows. En internet se puede encontrar mucha otra información al respecto (p.ej. ésta en CodeGuru) en la que nos alertan de no utilizar MsgBox y similares en un servicio porque suelen dar problemillas.