ServiceBase Class
Assembly: System.ServiceProcess (in system.serviceprocess.dll)
Derive from ServiceBase when defining your service class in a service application. Any useful service overrides the OnStart and OnStop methods. For additional functionality, you can override OnPause and OnContinue with specific behavior in response to changes in the service state.
A service is a long-running executable that does not support a user interface, and which might not run under the logged-on user account. The service can run without any user being logged on to the computer.
By default, services run under the System account, which is not the same as the Administrator account. You cannot change the rights of the System account. Alternatively, you can use a ServiceProcessInstaller to specify a user account under which the service will run.
An executable can contain more than one service but must contain a separate ServiceInstaller for each service. The ServiceInstaller instance registers the service with the system. The installer also associates each service with an event log that you can use to record service commands. The main() function in the executable defines which services should run. The current working directory of the service is the system directory, not the directory in which the executable is located.
When you start a service, the system locates the executable and runs the OnStart method for that service, contained within the executable. However, running the service is not the same as running the executable. The executable only loads the service. The service is accessed (for example, started and stopped) through the Service Control Manager.
The executable calls the ServiceBase derived class's constructor the first time you call Start on the service. The OnStart command-handling method is called immediately after the constructor executes. The constructor is not executed again after the first time the service has been loaded, so it is necessary to separate the processing performed by the constructor from that performed by OnStart. Any resources that can be released by OnStop should be created in OnStart. Creating resources in the constructor prevents them from being created properly if the service is started again after OnStop has released the resources.
The Service Control Manager (SCM) provides a way to interact with the service. You can use the SCM to pass Start, Stop, Pause, Continue, or custom commands into the service. The SCM uses the values of CanStop and CanPauseAndContinue to determine whether the service accepts Stop, Pause, or Continue commands. Stop, Pause, and Continue are enabled in the SCM's context menus only if the corresponding property CanStop or CanPauseAndContinue is true in the service class. If enabled, the command is passed to the service, and OnStop, OnPause, or OnContinue is called. If CanStop, CanShutdown, or CanPauseAndContinue is false, the corresponding command-handling method (such as OnStop) will not be processed, even if you have implemented the method.
You can use the ServiceController class to do programmatically what the SCM does using a user interface. You can automate the tasks available in the console. If CanStop, CanShutdown, or CanPauseAndContinue is true but you have not implemented a corresponding command-handling method (such as OnStop) the system throws an exception and ignores the command.
You do not have to implement OnStart, OnStop, or any other method in ServiceBase. However, the service's behavior is described in OnStart, so at minimum, this member should be overridden. The main() function of the executable registers the service in the executable with the Service Control Manager by calling the Run method. The ServiceName property of the ServiceBase object passed to the Run method must match the ServiceName property of the service installer for that service.
You can use InstallUtil.exe to install services on your system.
The following example derives a simple service implementation from the ServiceBase class. The service handles various service commands including Stop, Start, Pause, Continue and custom commands.
' Turn on the constant for 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 pause As New ManualResetEvent(False) Private Shared userCount As New Integer Public Declare Auto Function SetServiceStatus Lib "ADVAPI32.DLL" Alias "SetServiceStatus" (ByVal hServiceStatus As IntPtr, ByVal lpServiceStatus As SERVICE_STATUS) As Boolean Private myServiceStatus As SERVICE_STATUS Private workerThread As Thread = Nothing Public Sub New() CanPauseAndContinue = True CanHandleSessionChangeEvent = True ServiceName = "SimpleService" 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 Private Sub InitializeComponent() ' Initialize the operating properties for the service. Me.CanPauseAndContinue = True Me.CanShutdown = True Me.CanHandleSessionChangeEvent = False Me.ServiceName = "SimpleService" End Sub 'InitializeComponent ' 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 Not (workerThread Is Nothing) Then #If LOGEVENTS 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) 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 ' 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 Not (workerThread Is Nothing) Then #If LOGEVENTS 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. workerThread.Suspend() Case Fix(SimpleServiceCustomCommands.RestartWorker) ' Restart the worker thread if necessary. workerThread.Resume() 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 recieved: " + _ 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 pausing or 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
System.MarshalByRefObject
System.ComponentModel.Component
System.ServiceProcess.ServiceBase
Note: