Bibliothèque de classes .NET Framework
ServiceBase, classe

Mise à jour : novembre 2007

Fournit une classe de base pour un service qui fera partie d'une application de service. ServiceBase doit être dérivé lors de la création d'une classe de service.

Espace de noms :  System.ServiceProcess
Assembly :  System.ServiceProcess (dans System.ServiceProcess.dll)

Syntaxe

Visual Basic (Déclaration)
Public Class ServiceBase _
    Inherits Component
Visual Basic (Utilisation)
Dim instance As ServiceBase
C#
public class ServiceBase : Component
VisualC++
public ref class ServiceBase : public Component
J#
public class ServiceBase extends Component
JScript
public class ServiceBase extends Component
Notes

Dérivez votre classe de service de ServiceBase lorsque vous la définissez dans une application de service. Tout service utile substitue les méthodes OnStart et OnStop. Pour une fonctionnalité plus riche, vous pouvez substituer OnPause et OnContinue par un comportement spécifique en réaction aux modifications d'état du service.

Un service est un exécutable fonctionnant en permanence, qui ne prend pas en charge d'interface utilisateur et qui peut ne pas s'exécuter sous le compte de l'utilisateur ayant ouvert une session. Le service peut s'exécuter quand aucun utilisateur n'est en session sur l'ordinateur.

Par défaut, les services s'exécutent sous le compte système, lequel est différent du compte d'administrateur. Vous ne pouvez pas modifier les droits associés au compte système. Vous avez également la possibilité d'utiliser ServiceProcessInstaller pour spécifier un compte d'utilisateur sous lequel le service s'exécutera.

Un exécutable peut contenir plus d'un service à condition de comprendre un ServiceInstaller distinct pour chaque service. L'instance de ServiceInstaller inscrit le service dans le système. Le programme d'installation associe aussi chaque service à un journal des événements que vous pouvez utiliser pour enregistrer les commandes du service. La fonction main() de l'exécutable définit les services qui doivent s'exécuter. Le répertoire de travail actif du service est le répertoire système et non le répertoire où se trouve l'exécutable.

Lorsque vous démarrez un service, le système trouve l'exécutable et exécute la méthode OnStart pour ce service qui se trouve dans l'exécutable. Toutefois, il convient de faire la distinction entre l'exécution du service et celle de l'exécutable. L'exécutable se contente de charger le service. Vous accédez au service lui-même (pour le démarrer et l'arrêter notamment) par le biais du Gestionnaire de contrôle des services.

L'exécutable appelle le constructeur de la classe dérivée ServiceBase lorsque vous appelez pour la première fois Start sur le service. La méthode de gestion de commande OnStart est appelée immédiatement après l'exécution du constructeur. Le constructeur ne s'exécute plus après le chargement initial du service ; il est donc nécessaire de séparer le traitement effectué par le constructeur de celui effectué par OnStart. Toutes les ressources qui peuvent être libérées par OnStop doivent être créées dans OnStart. Le fait de créer les ressources dans le constructeur empêche qu'elles ne soient créées correctement dans le cas où le service serait redémarré après la libération de ces ressources par OnStop.

Le Gestionnaire de contrôle des services (SCM, Service Control Manager) permet l'interaction avec le service. Vous pouvez utiliser SCM pour passer au service des commandes Démarrer, Arrêter, Suspendre, Continuer ou des commandes personnalisées. Le Gestionnaire de contrôle des services utilise les valeurs de CanStop et CanPauseAndContinue pour déterminer si le service accepte les commandes Arrêter, Suspendre et Continuer. Les commandes Arrêter, Suspendre et Continuer ne sont activées dans les menus contextuels de SCM que si la propriété correspondante CanStop ou CanPauseAndContinue a la valeur true dans la classe du service. Si elle est activée, la commande est passée au service et la méthode OnStop, OnPause ou OnContinue est appelée. Si CanStop, CanShutdown ou CanPauseAndContinue a la valeur false, la méthode de gestion de commande correspondante (par exemple, OnStop) n'est pas traitée, même si vous avez implémenté cette méthode.

Vous pouvez utiliser la classe ServiceController pour accomplir par programme ce que fait le Gestionnaire de contrôle des services à l'aide d'une interface utilisateur. Il est possible d'automatiser les tâches disponibles dans la console. Si CanStop, CanShutdown ou CanPauseAndContinue a la valeur true et que vous n'avez pas implémenté la méthode de gestion de commande correspondante (par exemple, OnStop), le système lève une exception et ignore la commande.

Il n'est pas nécessaire d'implémenter OnStart, OnStop ou toute autre méthode de ServiceBase. Toutefois, comme le comportement du service est décrit dans OnStart, il convient au minimum de substituer ce membre. La fonction main() de l'exécutable inscrit le service dans l'exécutable avec le Gestionnaire de contrôle des services en appelant la méthode Run. La propriété ServiceName de l'objet ServiceBase passé à la méthode Run doit correspondre à la propriété ServiceName du programme d'installation de service pour ce service.

Vous pouvez utiliser InstallUtil.exe pour installer des services sur votre système.

Remarque :

Vous pouvez spécifier un journal différent du journal des événements de l'application pour recevoir la notification des appels du service ; toutefois, aucune des propriétés AutoLog et EventLog ne peut écrire dans un journal personnalisé. Affectez à AutoLog la valeur false si vous ne souhaitez pas utiliser l'enregistrement automatique dans le journal.

Exemples

L'exemple suivant dérive une implémentation de service simple de la classe ServiceBase. Ce service gère diverses commandes de service, notamment Stop, Start, Pause, Continue et les commandes personnalisées.

Visual Basic
' Turn on logging to the event log.
#Const LOGEVENTS = True

Imports System
Imports System.IO
Imports System.Threading
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Diagnostics
Imports System.ServiceProcess
Imports System.Text
Imports Microsoft.Win32
Imports System.Runtime.InteropServices


' Define custom commands for the SimpleService.

Public Enum SimpleServiceCustomCommands
    StopWorker = 128
    RestartWorker
    CheckWorker
End Enum 'SimpleServiceCustomCommands
<StructLayout(LayoutKind.Sequential)> _
Public Structure SERVICE_STATUS
    Public serviceType As Integer
    Public currentState As Integer
    Public controlsAccepted As Integer
    Public win32ExitCode As Integer
    Public serviceSpecificExitCode As Integer
    Public checkPoint As Integer
    Public waitHint As Integer
End Structure 'SERVICE_STATUS


Public Enum State
    SERVICE_STOPPED = &H1
    SERVICE_START_PENDING = &H2
    SERVICE_STOP_PENDING = &H3
    SERVICE_RUNNING = &H4
    SERVICE_CONTINUE_PENDING = &H5
    SERVICE_PAUSE_PENDING = &H6
    SERVICE_PAUSED = &H7
End Enum 'State

' Define a simple service implementation.

Public Class SimpleService
    Inherits System.ServiceProcess.ServiceBase
    Private Shared userCount As Integer = 0
    Private Shared pause As New ManualResetEvent(False)

    Public Declare Auto Function SetServiceStatus Lib "ADVAPI32.DLL" Alias "SetServiceStatus" (ByVal hServiceStatus As IntPtr, ByRef lpServiceStatus As SERVICE_STATUS) As Boolean
    Private myServiceStatus As SERVICE_STATUS

    Private workerThread As Thread = Nothing

    Public Sub New()
        CanPauseAndContinue = True
        CanHandleSessionChangeEvent = True
        CanShutdown = True
        CanStop = True
        ServiceName = "Simple Service"
        System.Diagnostics.EventLog.WriteEntry("SimpleService", DateTime.Now.ToLongTimeString())

    End Sub 'New

    Shared Sub Main()
#If LOGEVENTS Then
        System.Diagnostics.EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() + " - Service main method starting...")
#End If

        ' Load the service into memory.
        System.ServiceProcess.ServiceBase.Run(New SimpleService())

#If LOGEVENTS Then
        System.Diagnostics.EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() + " - Service main method exiting...")
#End If

    End Sub 'Main



    ' Start the service.
    Protected Overrides Sub OnStart(ByVal args() As String)
        Dim handle As IntPtr = Me.ServiceHandle
        myServiceStatus.currentState = Fix(State.SERVICE_START_PENDING)
        SetServiceStatus(handle, myServiceStatus)

        ' Start a separate thread that does the actual work.
        If workerThread Is Nothing OrElse (workerThread.ThreadState And System.Threading.ThreadState.Unstarted Or System.Threading.ThreadState.Stopped) <> 0 Then
#If LOGEVENTS Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() + " - Starting the service worker thread.")
#End If

            workerThread = New Thread(New ThreadStart(AddressOf ServiceWorkerMethod))
            workerThread.Start()
        End If
#If LOGEVENTS Then
        If Not (workerThread Is Nothing) Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() + " - Worker thread state = " + workerThread.ThreadState.ToString())
        End If
#End If
        myServiceStatus.currentState = Fix(State.SERVICE_RUNNING)
        SetServiceStatus(handle, myServiceStatus)
        System.Diagnostics.EventLog.WriteEntry("SimpleService", "Starting SimpleService")

        ' Get arguments from the ImagePath string value for the service's registry 
        ' key (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SimpleService).
        ' These arguments are not used by this sample, this code is only intended to
        ' demonstrate how to obtain the arguments.
        Dim imagePathArgs As String() = Environment.GetCommandLineArgs()
        If imagePathArgs.Length > 1 Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.ImagePath", "argument 1: " + imagePathArgs(1))
            If imagePathArgs.Length > 2 Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.ImagePath", "argument 2: " + imagePathArgs(2))
            End If
        End If ' Get values for arguments passed in from the Services control panel or
        ' by the ServiceController class Start(string[]) method.
        ' Note:  The arguments are not persisted by the control panel. You must
        ' open the properties for the service, set the arguments, then start the
        ' service. You may find this functionality useful when debugging a service.
        ' These arguments are not used by this sample, this code is only
        ' intended to demonstrate how to obtain the arguments.
        If args.Length > 1 Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.Arguments", args(0))
            If args.Length > 1 Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.Arguments", args(1))
            End If
        End If

    End Sub 'OnStart

    ' Stop this service.
    Protected Overrides Sub OnStop()
        ' New in .NET Framework version 2.0.
        Me.RequestAdditionalTime(4000)
        ' Signal the worker thread to exit.
        If Not (workerThread Is Nothing) AndAlso workerThread.IsAlive Then
#If LOGEVENTS Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() + " - Stopping the service worker thread.")
#End If
            pause.Reset()
            Thread.Sleep(5000)
            workerThread.Abort()
        End If
        If Not (workerThread Is Nothing) Then
#If LOGEVENTS Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() + " - OnStop Worker thread state = " + workerThread.ThreadState.ToString())
#End If
        End If
        ' Indicate a successful exit.
        Me.ExitCode = 0

    End Sub 'OnStop

    ' Pause the service.
    Protected Overrides Sub OnPause()
        ' Pause the worker thread.
        If Not (workerThread Is Nothing) AndAlso workerThread.IsAlive AndAlso (workerThread.ThreadState And System.Threading.ThreadState.Suspended Or System.Threading.ThreadState.SuspendRequested) = 0 Then
#If LOGEVENTS Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() + " - Pausing the service worker thread.")
#End If

            pause.Reset()
            Thread.Sleep(5000)
        End If

        If Not (workerThread Is Nothing) Then
#If LOGEVENTS Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() + " OnPause - Worker thread state = " + workerThread.ThreadState.ToString())
#End If
        End If

    End Sub 'OnPause

    Protected Overrides Sub OnShutdown()
#If LOGEVENTS Then
        System.Diagnostics.EventLog.WriteEntry("SimpleService.OnShutdown", DateTime.Now.ToLongTimeString() + " - Stopping the SimpleService.")
#End If

    End Sub 'OnShutdown

    ' Continue a paused service.
    Protected Overrides Sub OnContinue()

        ' Signal the worker thread to continue.
        If Not (workerThread Is Nothing) AndAlso (workerThread.ThreadState And System.Threading.ThreadState.Suspended Or System.Threading.ThreadState.SuspendRequested) <> 0 Then
#If LOGEVENTS Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() + " - Resuming the service worker thread.")

#End If
            pause.Set()
        End If
#If LOGEVENTS Then
        If Not (workerThread Is Nothing) Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() + " OnContinue - Worker thread state = " + workerThread.ThreadState.ToString())
#End If
        End If

    End Sub 'OnContinue

    ' Handle a custom command.
    Protected Overrides Sub OnCustomCommand(ByVal command As Integer)
#If LOGEVENTS Then
        System.Diagnostics.EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() + " - Custom command received: " + command.ToString())
#End If

        ' If the custom command is recognized,
        ' signal the worker thread appropriately.
        Select Case command
            Case Fix(SimpleServiceCustomCommands.StopWorker)
                ' Signal the worker thread to terminate.
                ' For this custom command, the main service
                ' continues to run without a worker thread.
                pause.Reset()

            Case Fix(SimpleServiceCustomCommands.RestartWorker)

                ' Restart the worker thread if necessary.
                pause.Set()

            Case Fix(SimpleServiceCustomCommands.CheckWorker)
#If LOGEVENTS Then
                ' Log the current worker thread state.
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() + " OnCustomCommand - Worker thread state = " + workerThread.ThreadState.ToString())
#End If


            Case Else
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString())
#End If
        End Select

    End Sub 'OnCustomCommand

    ' Handle a session change notice
    Protected Overrides Sub OnSessionChange(ByVal changeDescription As SessionChangeDescription)
#If LOGEVENTS Then
        System.Diagnostics.EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " - Session change notice received: " + changeDescription.Reason.ToString() + "  Session ID: " + changeDescription.SessionId.ToString())
#End If

        Select Case changeDescription.Reason
            Case SessionChangeReason.SessionLogon
                userCount += 1
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionLogon, total users: " + userCount.ToString())
#End If
            Case SessionChangeReason.SessionLogoff

                userCount -= 1
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionLogoff, total users: " + userCount.ToString())
#End If
            Case SessionChangeReason.RemoteConnect
                userCount += 1
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " RemoteConnect, total users: " + userCount.ToString())
#End If
            Case SessionChangeReason.RemoteDisconnect
                userCount -= 1
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " RemoteDisconnect, total users: " + userCount.ToString())
#End If
            Case SessionChangeReason.SessionLock
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionLock")
#End If
            Case SessionChangeReason.SessionUnlock
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionUnlock")
#End If
            Case Else
        End Select

    End Sub 'OnSessionChange

    ' Define a simple method that runs as the worker thread for 
    ' the service.  
    Public Sub ServiceWorkerMethod()
#If LOGEVENTS Then
        System.Diagnostics.EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - Starting the service worker thread.")
#End If

        Try
            Do
                ' Simulate 4 seconds of work.
                Thread.Sleep(4000)
                ' Block if the service is paused or is shutting down.
                pause.WaitOne()
#If LOGEVENTS Then
                System.Diagnostics.EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - heartbeat cycle.")
#End If
            Loop While True
        Catch
            ' Another thread has signalled that this worker
            ' thread must terminate.  Typically, this occurs when
            ' the main service thread receives a service stop 
            ' command.
            ' Write a trace line indicating that the worker thread
            ' is exiting.  Notice that this simple thread does
            ' not have any local objects or data to clean up.
#If LOGEVENTS Then
            System.Diagnostics.EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - Thread abort signaled.")
#End If
        End Try
#If LOGEVENTS Then

        System.Diagnostics.EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - Exiting the service worker thread.")
#End If

    End Sub 'ServiceWorkerMethod 
End Class 'SimpleService
C#
// Turn on logging to the event log.
#define LOGEVENTS

using System;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using Microsoft.Win32;
using System.Runtime.InteropServices;

namespace SimpleService
{
    // Define custom commands for the SimpleService.
    public enum SimpleServiceCustomCommands { StopWorker = 128, RestartWorker, CheckWorker };
    [StructLayout(LayoutKind.Sequential)]
    public struct SERVICE_STATUS
    {
        public int serviceType;
        public int currentState;
        public int controlsAccepted;
        public int win32ExitCode;
        public int serviceSpecificExitCode;
        public int checkPoint;
        public int waitHint;
    }

    public enum State
    {
        SERVICE_STOPPED = 0x00000001,
        SERVICE_START_PENDING = 0x00000002,
        SERVICE_STOP_PENDING = 0x00000003,
        SERVICE_RUNNING = 0x00000004,
        SERVICE_CONTINUE_PENDING = 0x00000005,
        SERVICE_PAUSE_PENDING = 0x00000006,
        SERVICE_PAUSED = 0x00000007,
    }

    // Define a simple service implementation.
    public class SimpleService : System.ServiceProcess.ServiceBase
    {
        private static int userCount = 0;
        private static ManualResetEvent pause = new ManualResetEvent(false);

        [DllImport("ADVAPI32.DLL", EntryPoint = "SetServiceStatus")]
        public static extern bool SetServiceStatus(
                        IntPtr hServiceStatus,
                        ref SERVICE_STATUS lpServiceStatus
                        );
        private SERVICE_STATUS myServiceStatus;

        private Thread workerThread = null;

        public SimpleService()
        {
            CanPauseAndContinue = true;
            CanHandleSessionChangeEvent = true;
            CanShutdown = true;
            CanStop = true;
            ServiceName = "Simple Service";
            EventLog.WriteEntry("SimpleService", DateTime.Now.ToLongTimeString());
        }

        static void Main()
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() +
                " - Service main method starting...");
#endif

            // Load the service into memory.
            System.ServiceProcess.ServiceBase.Run(new SimpleService());

#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() +
                " - Service main method exiting...");
#endif

        }


        // Start the service.
        protected override void OnStart(string[] args)
        {
            IntPtr handle = this.ServiceHandle;
            myServiceStatus.currentState = (int)State.SERVICE_START_PENDING;
            SetServiceStatus(handle, ref myServiceStatus);

            // Start a separate thread that does the actual work.

            if ((workerThread == null) ||
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() +
                    " - Starting the service worker thread.");
#endif

                workerThread = new Thread(new ThreadStart(ServiceWorkerMethod));
                workerThread.Start();
            }
#if LOGEVENTS
            if (workerThread != null)
            {
                EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() +
                    " - Worker thread state = " +
                    workerThread.ThreadState.ToString());
            }
#endif
            myServiceStatus.currentState = (int)State.SERVICE_RUNNING;
            SetServiceStatus(handle, ref myServiceStatus);
            EventLog.WriteEntry("SimpleService", "Starting SimpleService");

            // Get arguments from the ImagePath string value for the service's registry 
            // key (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SimpleService).
            // These arguments are not used by this sample, this code is only intended to
            // demonstrate how to obtain the arguments.
            string[] imagePathArgs = Environment.GetCommandLineArgs();
            if (imagePathArgs.Length > 1)
            {
                EventLog.WriteEntry("SimpleService.ImagePath", "argument 1: " + imagePathArgs[1]);
                if (imagePathArgs.Length > 2)
                    EventLog.WriteEntry("SimpleService.ImagePath", "argument 2: " + imagePathArgs[2]);
            }
            // Get values for arguments passed in from the Services control panel or
            // by the ServiceController class Start(string[]) method.
            // Note:  The arguments are not persisted by the control panel. You must
            // open the properties for the service, set the arguments, then start the
            // service. You may find this functionality useful when debugging a service.
            // These arguments are not used by this sample, this code is only
            // intended to demonstrate how to obtain the arguments.
            if (args.Length > 1)
            {
                EventLog.WriteEntry("SimpleService.Arguments", args[0]);
                if (args.Length > 1)
                    EventLog.WriteEntry("SimpleService.Arguments", args[1]);
            }

        }

        // Stop this service.
        protected override void OnStop()
        {
            // New in .NET Framework version 2.0.
            this.RequestAdditionalTime(4000);
            // Signal the worker thread to exit.
            if ((workerThread != null) && (workerThread.IsAlive))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() +
                    " - Stopping the service worker thread.");
#endif
                pause.Reset();
                Thread.Sleep(5000);
                workerThread.Abort();

            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() +
                    " - OnStop Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
            // Indicate a successful exit.
            this.ExitCode = 0;
        }

        // Pause the service.
        protected override void OnPause()
        {
            // Pause the worker thread.
            if ((workerThread != null) &&
                (workerThread.IsAlive) &&
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) == 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() +
                    " - Pausing the service worker thread.");
#endif

                pause.Reset();
                Thread.Sleep(5000);
            }

            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() +
                    " OnPause - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
        }
        protected override void OnShutdown()
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.OnShutdown", DateTime.Now.ToLongTimeString() +
                " - Stopping the SimpleService.");
#endif
        }
        // Continue a paused service.
        protected override void OnContinue()
        {

            // Signal the worker thread to continue.
            if ((workerThread != null) &&
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) != 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() +
                    " - Resuming the service worker thread.");

#endif
                pause.Set();

            }
#if LOGEVENTS
            if (workerThread != null)
            {
                EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() +
                    " OnContinue - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
        }

        // Handle a custom command.
        protected override void OnCustomCommand(int command)
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() +
                " - Custom command received: " +
                command.ToString());
#endif

            // If the custom command is recognized,
            // signal the worker thread appropriately.

            switch (command)
            {
                case (int)SimpleServiceCustomCommands.StopWorker:
                    // Signal the worker thread to terminate.
                    // For this custom command, the main service
                    // continues to run without a worker thread.
                    pause.Reset();
                    break;

                case (int)SimpleServiceCustomCommands.RestartWorker:

                    // Restart the worker thread if necessary.
                    pause.Set();
                    break;

                case (int)SimpleServiceCustomCommands.CheckWorker:
#if LOGEVENTS
                    // Log the current worker thread state.
                    EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() +
                        " OnCustomCommand - Worker thread state = " +
                        workerThread.ThreadState.ToString());
#endif

                    break;

                default:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnCustomCommand",
                        DateTime.Now.ToLongTimeString());
#endif
                    break;
            }
        }
        // Handle a session change notice
        protected override void OnSessionChange(SessionChangeDescription changeDescription)
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() +
                " - Session change notice received: " +
                changeDescription.Reason.ToString() + "  Session ID: " +
                changeDescription.SessionId.ToString());
#endif

            switch (changeDescription.Reason)
            {
                case SessionChangeReason.SessionLogon:
                    userCount += 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionLogon, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.SessionLogoff:

                    userCount -= 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionLogoff, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.RemoteConnect:
                    userCount += 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " RemoteConnect, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.RemoteDisconnect:
                    userCount -= 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " RemoteDisconnect, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.SessionLock:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionLock");
#endif
                    break;
                case SessionChangeReason.SessionUnlock:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionUnlock");
#endif
                    break;
                default:
                    break;
            }
        }
        // Define a simple method that runs as the worker thread for 
        // the service.  
        public void ServiceWorkerMethod()
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                " - Starting the service worker thread.");
#endif

            try
            {
                do
                {
                    // Simulate 4 seconds of work.
                    Thread.Sleep(4000);
                    // Block if the service is paused or is shutting down.
                    pause.WaitOne();
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                        " - heartbeat cycle.");
#endif
                }
                while (true);
            }
            catch (ThreadAbortException)
            {
                // Another thread has signalled that this worker
                // thread must terminate.  Typically, this occurs when
                // the main service thread receives a service stop 
                // command.

                // Write a trace line indicating that the worker thread
                // is exiting.  Notice that this simple thread does
                // not have any local objects or data to clean up.
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                    " - Thread abort signaled.");
#endif
            }
#if LOGEVENTS

            EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                " - Exiting the service worker thread.");
#endif

        }
    }
}
Hiérarchie d'héritage

System..::.Object
  System..::.MarshalByRefObject
    System.ComponentModel..::.Component
      System.ServiceProcess..::.ServiceBase
Sécurité des threads

Tous les membres static (Shared en Visual Basic) publics de ce type sont thread-safe. Il n'est pas garanti que les membres d'instance soient thread-safe.
Plateformes

Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professionnel Édition x64, Windows XP Starter Edition, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98

Le .NET Framework et le .NET Compact Framework ne prennent pas en charge toutes les versions de chaque plateforme. Pour obtenir la liste des versions prises en charge, consultez Configuration requise du .NET Framework.

Informations de version

.NET Framework

Pris en charge dans : 3.5, 3.0, 2.0, 1.1, 1.0
Voir aussi

Référence

Mots clés :


Page view tracker