Article source code: servicecontroller.zip
VB.NET contains built in classes which make creating a windows service a breeze,
but what if you want an application to control a service which is easy for anyone
to use. This article will show you how to create an application that runs in
the system tray. We will not be discussing the creation of a service. Instead
we will use this application to control IIS. This could be a great help for
developers creating ASP and ASP.NET applications where it is useful to be able
to re-start the web server without delving into Settings. The images below shows
the application running.
To develop this type of application you will start with a WinForm Project and
delete the form it creates. We will run this application from a Sub Main procedure
in a module you should add to your project.
Imports System.Diagnostics
Imports System.Text
Public Module modMain
Private mobNotifyIcon As NotifyIcon
Private WithEvents mobContextMenu As ContextMenu
Private WithEvents mobTimer As Timers.Timer
Private mobServiceController As System.ServiceProcess.ServiceController
End Module
The code above imports the Diagnostics
and Text
namespaces that we will need
later on in the code. A NotifyIcon
is declared which will show in the system
tray and a ContextMenu
to display the user menu. We also need a timer to keep
a check on the status of our service and update the menu and icon. A ServiceController
is then declared. Before you go further into the coding take some time out to
create three icons to represent the stopped, running and paused status of the
service. The ones I have created below resemble traffic lights, but you can
use any analogy you wish. VS.NET allows you to create icons within the IDE...which
is nice!

Next we need to add a procedure to set up the timer and start it running. Set
the interval at five seconds which is usually about the time IIS takes to start
or stop.
Private Sub SetUpTimer()
Try
mobTimer = New Timers.Timer()
With mobTimer
.AutoReset = True
.Interval = 5000
.Start()
End With
Catch obEx As Exception
Throw obEx
End Try
End Sub
To create the menu we will add a procedure that adds MenuItems
to the ContextMenu
and sets up the Event Handlers. Of course it may not be possible to Pause/Continue
some services but what we are creating here is generic and will work with any
service. Later in the code we will check if Pause or Continue are possible and
enable the menu items accordingly.
Private Sub CreateMenu()
Try
mobContextMenu.MenuItems.Add(New MenuItem("Stop", _
New EventHandler(AddressOf StopService)))
mobContextMenu.MenuItems.Add(New MenuItem("Pause", _
New EventHandler(AddressOf PauseService)))
mobContextMenu.MenuItems.Add(New MenuItem("Continue", _
New EventHandler(AddressOf ContinueService)))
mobContextMenu.MenuItems.Add(New MenuItem("Start", _
New EventHandler(AddressOf StartService)))
mobContextMenu.MenuItems.Add("-")
mobContextMenu.MenuItems.Add(New MenuItem("About", _
New EventHandler(AddressOf AboutBox)))
mobContextMenu.MenuItems.Add(New MenuItem("Exit", _
New EventHandler(AddressOf ExitController)))
Catch obEx As Exception
Throw obEx
End Try
End Sub
As you change the status of the service you will want to reflect this to the
user by changing the icon displayed. We must also establish the status of the
service when the application starts. The GetServiceStatus
procedure below first
of all, calls the Refresh
method of the ServiceController
. This will refresh
all the properties of the controller and is essential in order to get accurate
status information. A Select Case
statement then reads the status and sets up
the menu and icon. Ensure that you have placed your icons in the bin directory
of your project with the executable. If you wish to take this a step further
you could create a resource file for the icons and enumerate the Menu indexes.
Private Sub GetServiceStatus()
Try
'//REFRESH PROPERTIES BEFORE READING.
mobServiceController.Refresh()
'//REFLECT STATUS IN THE CONTEXT MENU.
Select Case mobServiceController.Status()
Case ServiceProcess.ServiceControllerStatus.Paused
mobNotifyIcon.Icon = New Icon("Paused.ico")
mobContextMenu.MenuItems(0).Enabled = False
mobContextMenu.MenuItems(1).Enabled = False
mobContextMenu.MenuItems(2).Enabled = True
mobContextMenu.MenuItems(3).Enabled = False
Case ServiceProcess.ServiceControllerStatus.Running
mobNotifyIcon.Icon = New Icon("Running.ico")
mobContextMenu.MenuItems(0).Enabled = True
mobContextMenu.MenuItems(1).Enabled = True
mobContextMenu.MenuItems(2).Enabled = False
mobContextMenu.MenuItems(3).Enabled = False
Case ServiceProcess.ServiceControllerStatus.Stopped
mobNotifyIcon.Icon = New Icon("Stopped.ico")
mobContextMenu.MenuItems(0).Enabled = False
mobContextMenu.MenuItems(1).Enabled = False
mobContextMenu.MenuItems(2).Enabled = False
mobContextMenu.MenuItems(3).Enabled = True
Case _
ServiceProcess.ServiceControllerStatus.ContinuePending, _
ServiceProcess.ServiceControllerStatus.PausePending, _
ServiceProcess.ServiceControllerStatus.StartPending, _
ServiceProcess.ServiceControllerStatus.StopPending
mobNotifyIcon.Icon = New Icon("Paused.ico")
mobContextMenu.MenuItems(0).Enabled = False
mobContextMenu.MenuItems(1).Enabled = False
mobContextMenu.MenuItems(2).Enabled = False
mobContextMenu.MenuItems(3).Enabled = False
End Select
'//FINALLY CHECK IF PAUSE & CONTINUE IS POSSIBLE ON THIS SERVICE.
If mobServiceController.CanPauseAndContinue = False Then
mobContextMenu.MenuItems(1).Enabled = False
mobContextMenu.MenuItems(2).Enabled = False
End If
Catch obEx As Exception
Throw obEx
End Try
End Sub
With the menu under control we can now set up the event handlers we named in
the procedure CreateMenu
. The code below shows an example and the others are
very similar. You can find the code for the other events in the project download.
Private Sub StopService(ByVal sender As Object, ByVal e As EventArgs)
Try
If mobServiceController.Status = _
ServiceProcess.ServiceControllerStatus.Running Then
If mobServiceController.CanStop = True Then
mobServiceController.Stop()
End If
End If
Catch obEx As Exception
Throw obEx
End Try
End Sub
In order for your system tray icon to reflect the status of your service we
need to call the GetServiceStatus
using our timer Elapsed
event.
Public Sub mobTimer_Elapsed(ByVal sender As Object, _
ByVal e As System.Timers.ElapsedEventArgs) Handles mobTimer.Elapsed
Try
GetServiceStatus()
Catch obEx As Exception
Throw obEx
End Try
End Sub
Finally when we exit the application we must do some tidying up of objects.
Although the framework will periodically come round and collect your garbage,
it is good programming practice to do a little housekeeping where you can.
Private Sub ExitController(ByVal sender As Object, ByVal e As EventArgs)
Try
mobTimer.Stop()
mobTimer.Dispose()
mobNotifyIcon.Visible = False
mobNotifyIcon.Dispose()
mobServiceController.Dispose()
Application.Exit()
Catch obEx As Exception
Throw obEx
End Try
End Sub
Well that about wraps up the code. Now you have seen how easy it is to control
a service you may be itching to program your own. Maybe an app to keep an eye
on your disc space and warn you when it is getting low or disc clean-up service.
These are some of the ideas that may be the subject of a future article.
