Article Options
Recently Viewed
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:4.03846153846153 out of 5
 78 people have rated this page
Article Score71372
Comments    Submit Comment

Comment #1  (Posted by Artemis Psaras on 03/08/2003)

I tried this on Windows XP PRO. I am not receiving any error message , but the icon does not show up. I checked the Task Manager and the process seems to be running OK, but no icon appears in the tray. Any ideas?
 
Comment #2  (Posted by Peter Custance on 03/09/2003)

If you are trying this on Win XP Pro, please make sure IIS is installed as it is not installed by default. Because a windows service runs unattended it does not show error dialogs on screen if you want debug messages, try writing to the event log using the Event Log Object inside the procedures. See the dotnet help files for more details.

Peter Custance
 
Comment #3  (Posted by Artemis Psaras on 03/10/2003)

Peter, thanks for your prompt reply. The code is working OK now. Thanks a lot.
 
Comment #4  (Posted by Michael on 03/11/2003)

A much better solution would avoid polling and use another way to communicate a change in service state to the "monitor". Mutex's, for example.
 
Comment #5  (Posted by Chris Keeble on 05/19/2003)

To get this working, you'll need to add a reference from your project to the System.ServiceController namespace:

1. In Solution Explorer, right click "References" and select "Add Reference"

2. Scroll down and find "System.ServiceProcess.dll". Highlight it and click 'Select'.

3. Click 'OK'.


 
Comment #6  (Posted by jon ogden on 06/25/2003)

I found the article useful. I found some of the comments very unhelpful. "A much better way" neither explains why a different way would be better, nor explains the alternative approach in any detail. This approach seems to offer no increase in knowledge, only in intellectual entropy.
 
Comment #7  (Posted by Sorin on 07/14/2003)

Hi all,

I found this tip very interessing. I tested the VBproj and works. Than I translated everything in c#...

I have a problem with Sub Main. I put the code in a class and now using static void Main I want to run my application.

Does anybody knows how can I do the same thing in c#...

Thanks
 
Comment #8  (Posted by an unknown user on 07/15/2003)

OK,

I did'it, after all it was only about modifying few code lines. If you need the code send me a message.
 
Comment #9  (Posted by RF on 08/19/2003)

On Win2000 the service controller app slowly keeps chewing up memory.
 
Comment #10  (Posted by AL on 10/10/2003)

If you can't see the icon on winxp, try putting the icon directly in your bin directory, or wherever you have the exe stored.
 
Comment #11  (Posted by Fred on 12/09/2003)

Help,

I'm getting the following errors in Sub CreateMenu

Name 'PauseService' is not declared
Name 'ContinueService' is not declared
Name 'StartService' is not declared
Name AboutBox' is not declared
Name 'PauseService' is not declared

Also the 'New' keyword was missing in

Private mobServiceController As System.ServiceProcess.ServiceController()

Thanks in advance,

fw

 
Comment #12  (Posted by Peter Custance on 12/09/2003)

Fred, you are missing some functions in your code. Download the full source code to get these functions.
Regards

Peter
 
Comment #13  (Posted by Ashish Kar on 02/05/2004)

Hi,

I've written a VB.NET exe which runs and appears in the system tray to indicate the status of the service as in stopped, started or paused. This works perfectly ok when you invoke the exe (as in double-clicking on it) and it puts the icons in the sys tray. However, I've tried to put this in the Windows Startup - the result is that the exe appears in the Task Manager Processes but the SysTray icon does not appear. Do you have any ideas to what might be the problem???

The code for the Windows Start up induction is -

--------- WINDOWS STARTUP--------------- (This is in a windows service)
Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Run", True).SetValue("ServCont", "C:\0user\rts\bin\sc.exe")

---------SERVICE CONTROLLER ----------------
As you had instructed.

Thanks and Regards,
Ashish
Brisbane, Australia
 
Comment #14  (Posted by Andrew on 02/25/2004)

I just want to mention that default WinForm project does not include reference to system.serviceprocess.dll needed for System.ServiceProcess.ServiceController

So, don't forget to include it

 
Comment #15  (Posted by Anagha on 05/05/2004)

Hi
First of all thanx for giving such a good solution.
I had faced the same problem as that of Ashish. But I found that if you place shortcut of that exe in start up, the problem get solved
 
Comment #16  (Posted by Krish on 08/19/2004)

Hi,
If i double click it is working fine, if i try to call this exe inside my service, the process is running but it is not displaying the icon in systray..how to do it?

 
Comment #17  (Posted by Klint on 09/03/2004)

I have put the icons in the same folder as the .exe. When I launch the .exe, it shows it is running in my processes, but no icon is displayed in the system tray, so I have no way to control it. Windows XP Pro, SP1, VS.NET 2003. Ideas?
 
Comment #18  (Posted by BillD on 09/10/2004)

I have a project that requires firing up a process every 5 minutes to fetch files from a designated folder, 24/7. I've worked out the code of fetching part in VB.NET. I'm wondering how to incorporate your neat code and ideas into my project. Say push a Fetch button on UI to start the process. Thanks in advance.

Bill
 
Comment #19  (Posted by Peter Custance on 09/12/2004)

FAO Bill, Consider using the 'FileSystemWatcher' component which is in the components tab on the toolbox in Visual Studio. You should be able to watch a directory at intervals for files with a specific extentsion.

 
Comment #20  (Posted by Wayne Russell on 01/15/2005)
Rating
A good article which worked for me out of the box. Do you have a c# version available for download
 
Comment #21  (Posted by an unknown user on 08/03/2005)
Rating
This just uses all the build in stuff. Why don't you come up with a way to communicated more than start/stop/pause with a service
 
Comment #22  (Posted by an unknown user on 10/03/2005)
Rating
Not sure how this solution can work at all... When I run it, it goes right through the Main subroutine and then exits.
 
Comment #23  (Posted by an unknown user on 10/14/2005)
Rating
Execellent in the way the topic was explained, with good example,
 
Comment #24  (Posted by an unknown user on 12/04/2005)
Rating
It does not explaing how you install this program. Am I supposted to just run it. Do I execute it from my service?
 
Comment #25  (Posted by an unknown user on 12/08/2005)
Rating
This was the only page I found which provided a solution to controlling a service from the system tray icon. The other sites I visited were full of speculation and discussion, but no workable solutions for this issue.
 
Comment #26  (Posted by Jim Smith on 03/30/2006)
Rating
The reason the icon doesn't show up in the system tray is because the executable needs to be ran from the folder containing the .ico files. You need to make a shortcut to the .exe in that folder or include the .ico files in your install folder.
 
Comment #27  (Posted by an unknown user on 04/12/2006)
Rating
Not seen anything else like this. Written well. Excellent code.
 
Comment #28  (Posted by an unknown user on 04/19/2006)
Rating
Excellent article
 
Comment #29  (Posted by an unknown user on 05/18/2006)
Rating
CoOl
 
Comment #30  (Posted by an unknown user on 05/29/2006)
Rating
Excellent
 
Comment #31  (Posted by an unknown user on 06/22/2006)
Rating
Exactly what I wanted to know, shown in very clear coding.
 
Comment #32  (Posted by an unknown user on 06/27/2006)
Rating
Very Usefull, thanks
 
Comment #33  (Posted by an unknown user on 08/30/2006)
Rating
its VB
 
Comment #34  (Posted by an unknown user on 09/22/2006)
Rating
Excellent - I knew there was a better way to do this rather than shelling sysinternals psservice commands :-)
 
Comment #35  (Posted by an unknown user on 10/09/2006)
Rating
Is it possible to run te service as another account? Because I want to use this on a PC to manage a service remote.

Tia.
 
Comment #36  (Posted by an unknown user on 10/25/2006)
Rating
Hi

can I use for Windows CE.Net?
 
Comment #37  (Posted by Muru on 10/25/2006)
Rating
Hi

How to use the above in Windows CE.Net platform?
 
Comment #38  (Posted by an unknown user on 02/14/2007)
Rating
VERY GOOD
 
Comment #39  (Posted by an unknown user on 04/05/2007)
Rating
Works like a champ
 
Comment #40  (Posted by an unknown user on 05/03/2007)
Rating
very nice Really looking for this type of code
 
Comment #41  (Posted by an unknown user on 07/05/2007)
Rating
Good code!!
 
Comment #42  (Posted by an unknown user on 11/04/2007)
Rating
Peter, Thanks you very much for your code and sorry if I have modified your code to protected my application from naughty contractor company, maybe I will submit you my revision from your code.
 
Comment #43  (Posted by an unknown user on 11/22/2007)
Rating
It works seamlessly with what I'm trying to do. The example and explanation were very clear. Read once, copied, pasted, modified, tested many, SUCCESS! Now I just need to package it in such a way that the exe runs as soon as Windows starts. Any idea how?
 
Comment #44  (Posted by Pradeep Sattikar on 11/28/2007)
Rating
hi,
thanks for giving such a wonderful code on internet.
the code works fine. Now I need to handle exceptions in windows service.What is best way to inform user to inform about exception in windows service?

Thanks in advance
Regards
Pradeep Sattikar
 
Comment #45  (Posted by Suresh Kumar on 12/13/2007)
Rating
Hi peter can you help me in creating a my own windows service application where it will create a log file with date and time when the IIS was started and Stopped with which user in the server? can you help me out.
 
Comment #46  (Posted by an unknown user on 01/11/2008)
Rating
this is what i'm looking for
 
Comment #47  (Posted by an unknown user on 02/19/2008)
Rating
Great sample. It works very well. Thanks a lot !!!
 
Comment #48  (Posted by an unknown user on 02/21/2008)
Rating
Hi

Does anybode have a easy sample of the following:

I have a little .NET Windows Service with one public function
to return just a string.
Now I want to build a .NET WinForms application and call
this function from another pc.

What is the easyest way to do ??

Thanks a lot for any comments !

Best regards
Parimal Thakkar
 
Comment #49  (Posted by an unknown user on 03/05/2008)
Rating
can anyone post a C# version of this code??
 
Comment #50  (Posted by an unknown user on 06/06/2008)
Rating
Just what I was looking for - saved me a lot of work - thanks for sharing
 
Comment #51  (Posted by an unknown user on 11/16/2008)
Rating
Hi,
It has helped me a lot and it is put in very simple steps. The only thing is that how should i set it up to automatically go in my windows startup.
Thanks,
Shailesh
 
Comment #52  (Posted by an unknown user on 11/18/2008)
Rating
thanks peter it help me to run the services from tray launcher
 
Comment #53  (Posted by an unknown user on 04/13/2009)
Rating
informative but a little wordy, good job tho :)
 
Comment #54  (Posted by Lionel Slade on 06/17/2009)
Rating
Only thing missing is tool tip on hover over the icon in the sys tray
 
Comment #55  (Posted by an unknown user on 12/20/2009)
Rating
good
it helps me a lot
 
Comment #56  (Posted by an unknown user on 01/05/2011)
Rating
Very Good
 
Comment #57  (Posted by Discount OEM Software on 03/07/2012)
Rating
ojXDQ4 Im thankful for the blog article.Thanks Again. Will read on...
 
Comment #58  (Posted by Bristol Airport Hotels on 04/18/2012)
Rating
oqExHv Really appreciate you sharing this blog article.Really looking forward to read more.
 
Sponsored Links