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)
Visual Basic (Déclaration)
Public Class ServiceBase _
Inherits Component
Visual Basic (Utilisation)
Dim instance As ServiceBase
public class ServiceBase : Component
public ref class ServiceBase : public Component
public class ServiceBase extends Component
public class ServiceBase extends Component
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. |
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.
' 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
// 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
}
}
}
System..::.Object
System..::.MarshalByRefObject
System.ComponentModel..::.Component
System.ServiceProcess..::.ServiceBase
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.
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.
.NET Framework
Pris en charge dans : 3.5, 3.0, 2.0, 1.1, 1.0
Référence