Scrivere un'interfaccia per un Servizio in Visual Basic.NET

pubblicato il 20/03/2007

Come abbiamo visto nel precedente articolo, i Servizi di Windows consentono di lasciare un applicazione attiva anche se nessun utente ha effettuato il login sul computer, ma proprio per questa loro caratteristica non hanno (né possono avere) un interfaccia utente.

In questo articolo vedremo come realizzare un applicazione che funga da interfaccia di uno o più servizi: l'idea ispiratrice è il Microsoft Sql Server Service Manager, quella piccola applicazione ben conosciuta a chi ha installato Microsoft Sql Server 2000 e che risiede nella tray-bar per mostrarci lo stato dei servizi legati a Sql Server o permetterci di stopparli, riavviarli o metterli in pausa.

Al cuore di tutto c'è la classe ServiceController che appartiene alla namespace System.ServiceProcesses. Occorre innanzitutto creare una variabile di questo tipo (per comodità riprendo i valori dell'articolo precedente):

Dim controller As New ServiceController
controller.ServiceName = "tmFirst"
controller.MachineName = "."    '  indica il computer locale

A questo punto abbiamo a disposizione tutte le proprietà del servizio; ma non solo, abbiamo a disposizione anche i metodi Start, Stop, Pause e Continue che - rispettivamente - avviano, fermano, mettono in pausa e riavviano il servizio. Diventa perciò sufficiente agganciare una riga tipo

controller.Start

all'handler di un evento qualsiasi come un click di una voce di menu o di un pulsante.

Volendo perciò realizzare un applicazione che controlli un solo servizio, potremmo realilzzare un applicazione residente nella tray-bar cui venga legato un menu con le classiche voci "Avvia", "Ferma", "Pausa", "Continua": al click su una di queste voci, viene creata una variabile ServiceController cui vengono impostate le proprietà MachineName e ServiceName, infine invocato il metodo Start o Stop o Pause o Continua

Private Sub mnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnStart.Click
  Dim controller As New ServiceController

  controller.MachineName = "."
  controller.ServiceName = "tmFirst"

  controller.Start

End Sub

Private Sub mnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnStop.Click
  Dim controller As New ServiceController

  controller.MachineName = "."
  controller.ServiceName = "tmFirst"

  If controller.CanStop
    controller.Stop

  End If

End Sub

Private Sub mnPause_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnPause.Click
  Dim controller As New ServiceController

  controller.MachineName = "."
  controller.ServiceName = "tmFirst"

  If controller.CanPauseAndContinue
    controller.Pause

  End If

End Sub

Private Sub mnContinue_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnContinue.Click
  Dim controller As New ServiceController

  controller.MachineName = "."
  controller.ServiceName = "tmFirst"

  If controller.CanPauseAndContinue
    controller.Continue

  End If

End Sub

Come possiamo notare, è buona norma verificare che il servizio possa essere fermato prima di invocare il metodo Stop; analogamente è bene verificare che il servizio possa essere messo in pausa e riavviato (ovviamente le due operazioni "vanno a braccetto") prima di tentare di metterlo effettivamente in pausa o riavviarlo.

A questo punto potremmo raffinare ulteriormente il programma, abilitando i menu item a seconda dello stato attuale del servizio e delle varie probabilità CanStop e CanPauseAndContinue:

Private Sub EnableMenuItems()

  Dim controller As New ServiceController

  controller.MachineName = "."
  controller.ServiceName = "tmFirst"

  Select Case controller.Status
    Case ServiceControllerStatus.Paused, ServiceControllerStatus.PausePending
    mnStart.Enabled = False
    mnPause.Enabled = False
    mnStop.Enabled = False
    mnContinue.Enabled = True

    Case ServiceProcess.ServiceControllerStatus.Stopped, ServiceProcess.ServiceControllerStatus.StopPending
    mnStart.Enabled = True
    mnPause.Enabled = False
    mnStop.Enabled = False
    mnContinue.Enabled = False

    Case Else
    mnStart.Enabled = False
    mnPause.Enabled = controller.CanPauseAndContinue
    mnStop.Enabled = controller.CanStop
    mnContinue.Enabled = controller.CanPauseAndContinue

  End Select

End Sub