Article Options
Premium Sponsor
Premium Sponsor

 »  Home  »  Windows Development  »  Controlling a Windows Service from the System Tray
Controlling a Windows Service from the System Tray
by Peter Custance | Published  02/26/2003 | Windows Development | Rating:
Peter Custance

I am currently a software programmer for a large Data Card Manufacturer in the UK. Contact me at peter.custance@id-data.co.uk or p.custance@btopenworld.com.

I have nine years experience in software programming, using C and Visual Basic on Windows and Linux. I have been using VB.NET since beta 2 and I have built 2 websites using ASP 3 and ASP.NET. Visit www.britxchange.com or my homepage at www.custec.co.uk. I am now using the Visual Studio.Net 1.0 release daily and believe it to be the best development IDE available.

 

View all articles by Peter Custance...
Controlling a Windows Service from the System Tray

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 ObjectByVal 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.ElapsedEventArgsHandles 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 ObjectByVal 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.

How would you rate the quality of this article?
1 2 3 4 5
Poor Excellent
Tell us why you rated this way (optional):

Article Rating
The average rating is: No-one else has rated this article yet.

Article rating:3.84955752212389 out of 5
 113 people have rated this page
Article Score85591
Sponsored Links