Aggiornamento: novembre 2007
Fornisce una classe base per un servizio che esisterà nel contesto di un'applicazione di servizio. È necessario derivare ServiceBase durante la creazione di una nuova classe di servizio.
Spazio dei nomi:
System.ServiceProcess Assembly:
System.ServiceProcess (in System.ServiceProcess.dll)
Visual Basic - (Dichiarazione)
Public Class ServiceBase _
Inherits Component
Dim instance As ServiceBase
public class ServiceBase : Component
public ref class ServiceBase : public Component
public class ServiceBase extends Component
public class ServiceBase extends Component
Derivare da ServiceBase quando si definisce la classe di servizio in un'applicazione di servizio. Ogni servizio utile esegue l'override dei metodi OnStart e OnStop. Per funzionalità aggiuntive, è possibile eseguire l'override di OnPause e OnContinue con un funzionamento specifico in risposta alle variazioni dello stato di servizio.
Il servizio è un eseguibile ad esecuzione prolungata che non supporta un'interfaccia utente e che potrebbe non essere avviato con l'account utente connesso. Per eseguire il servizio non è necessario che un utente sia connesso al computer.
In base all'impostazione predefinita, i servizi vengono eseguiti con l'account System, che non corrisponde all'account Administrator. Non è possibile modificare i privilegi dell'account System. In alternativa, è possibile utilizzare un oggetto ServiceProcessInstaller per specificare un account utente con il quale verrà eseguito il servizio.
Un eseguibile può contenere più servizi ma è necessario che contenga un oggetto ServiceInstaller separato per ciascuno di essi. L'istanza di ServiceInstaller registra il servizio nel sistema. Il programma di installazione, inoltre, associa ciascun servizio a un registro eventi che può essere utilizzato per registrare i comandi di servizio. La funzione main() nell'eseguibile definisce quali servizi è necessario eseguire. La directory di lavoro corrente del servizio è la directory di sistema e non quella in cui si trova l'eseguibile.
Quando si avvia un servizio, il sistema individua l'eseguibile ed esegue il metodo OnStart per tale servizio, contenuto all'interno dell'eseguibile. Eseguire un servizio, tuttavia, non significa avviare l'eseguibile. L'eseguibile carica solo il servizio. Al servizio è possibile accedere (ad esempio, per l'avvio e l'interruzione) mediante Gestione controllo servizi.
L'eseguibile chiama il costruttore della classe derivata ServiceBase la prima volta che si chiama il metodo Start sul servizio. Il metodo per la gestione dei comandi OnStart viene chiamato subito dopo l'esecuzione del costruttore. Poiché il costruttore non viene più eseguito dopo il primo caricamento del servizio, è necessario separare l'elaborazione eseguita dal costruttore da quella eseguita dal metodo OnStart . È necessario che tutte le risorse che possono essere rilasciate dal metodo OnStop siano create nel metodo OnStart . La creazione di risorse nel costruttore ne impedisce la creazione corretta se il servizio viene riavviato dopo che il metodo OnStop le ha rilasciate.
Gestione controllo servizi (SCM, Service Control Manager) fornisce un modo per interagire con il servizio. Il gestore SCM può essere utilizzato per passare comandi di avvio, interruzione, pausa o continuazione oppure comandi personalizzati nel servizio. Il gestore SCM utilizza i valori di CanStop e CanPauseAndContinue per determinare se il servizio accetta i comandi di avvio, pausa o continuazione. Tali comandi vengono attivati nei menu di scelta rapida di SCM solo se la corrispondente proprietà CanStop o CanPauseAndContinue è true nella classe di servizio. Se attivato, il comando viene passato al servizio e viene chiamato OnStop, OnPause o OnContinue. Se la proprietà CanStop, CanShutdown o CanPauseAndContinue è false, il corrispondente metodo per la gestione dei comandi (ad esempio OnStop ) non verrà elaborato, anche se il metodo è stato implementato.
È possibile utilizzare la classe ServiceController per eseguire in modo programmatico ciò che il gestore SCM effettua tramite un'interfaccia utente. È possibile automatizzare le attività disponibili nella console. Se CanStop, CanShutdown o CanPauseAndContinue è true ma non è stato implementato un corrispondente metodo per la gestione dei comandi (ad esempio OnStop), il sistema genera un'eccezione e ignora il comando.
Non è necessario implementare OnStart, OnStop o un altro metodo in ServiceBase. Comunque, il funzionamento del servizio è descritto nel OnStart, quindi occorrere almeno eseguire l'override di questo membro. La funzione main() del file eseguibile registra il servizio nel file eseguibile con il gestore SCM mediante la chiamata del metodo Run. La proprietà ServiceName dell'oggetto ServiceBase passata al metodo Run deve corrispondere alla proprietà ServiceName del programma di installazione di tale servizio.
Per installare servizi nel sistema, è possibile utilizzare InstallUtil.exe.
Nota: |
|---|
Sebbene sia possibile specificare un log diverso dal log eventi delle applicazioni per ricevere la notifica delle chiamate ai servizi, tenere presente che le proprietà AutoLog e EventLog non possono scrivere in un log personalizzato. Se non si desidera utilizzare la registrazione automatica, impostare AutoLog su false. |
Nell'esempio seguente la semplice implementazione di un servizio viene derivata dalla classe ServiceBase. Il servizio gestisce vari comandi di servizio tra i quali Stop, Start, Pause, Continue e i comandi personalizzati.
' 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
}
}
}
Gerarchia di ereditarietà
System..::.Object
System..::.MarshalByRefObject
System.ComponentModel..::.Component
System.ServiceProcess..::.ServiceBase
Qualsiasi membro static (Shared in Visual Basic) pubblico di questo tipo è thread-safe. I membri di istanza non sono garantiti come thread-safe.
Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition , Windows XP Starter Edition, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98
.NET Framework e .NET Compact Framework non supportano tutte le versioni di ciascuna piattaforma. Per un elenco delle versioni supportate, vedere Requisiti di sistema di .NET Framework.
Informazioni sulla versione
.NET Framework
Supportato in: 3.5, 3.0, 2.0, 1.1, 1.0
Riferimenti