Click here to Skip to main content
Click here to Skip to main content
Go to top

Create a System Tray Application in VB.NET

, 4 May 2010
Rate this:
Please Sign up or sign in to vote.
Write an application that launches in the notification area.

TrayApp

Introduction

This article was prompted by a question in Quick Answers about how to write a VB.NET application that started in the tray. There were a number of examples here at CodeProject -- this article[^] by member [ICR] in particular -- but I could not find anything in VB. This article is meant to remedy that situation.

The Theory

As C# programmers know, applications start with a call to System.Windows.Forms.Application.Run. This call is normally hidden from VB.NET programmers, with the compiler supplying the required code behind the scenes. We can call this explicitly, however, which allows us to write applications that do not rely on start-up forms.

AppContext Class

The first step is to create a class that inherits from System.Windows.Forms.ApplicationContext. This provides the information needed by the Operating System to manage your application. This is also where you instantiate your NotifyIcon for the system tray, a menu to interact with the icon and any other essentials.

Public Class AppContext
    Inherits ApplicationContext

#Region " Storage "

    Private WithEvents Tray As NotifyIcon
    Private WithEvents MainMenu As ContextMenuStrip
    Private WithEvents mnuDisplayForm As ToolStripMenuItem
    Private WithEvents mnuSep1 As ToolStripSeparator
    Private WithEvents mnuExit As ToolStripMenuItem

#End Region

#Region " Constructor "

    Public Sub New()
        'Initialize the menus
        mnuDisplayForm = New ToolStripMenuItem("Display form")
        mnuSep1 = New ToolStripSeparator()
        mnuExit = New ToolStripMenuItem("Exit")
        MainMenu = New ContextMenuStrip
        MainMenu.Items.AddRange(New ToolStripItem() {mnuDisplayForm, mnuSep1, mnuExit})

        'Initialize the tray
        Tray = New NotifyIcon
        Tray.Icon = My.Resources.TrayIcon
        Tray.ContextMenuStrip = MainMenu
        Tray.Text = "Formless tray application"

        'Display
        Tray.Visible = True
    End Sub

#End Region

#Region " Event handlers "

    Private Sub AppContext_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.ThreadExit
        'Guarantees that the icon will not linger.
        Tray.Visible = False
    End Sub

    Private Sub mnuDisplayForm_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles mnuDisplayForm.Click
        ShowDialog()
    End Sub

    Private Sub mnuExit_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles mnuExit.Click
        ExitApplication()
    End Sub

    Private Sub Tray_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Tray.DoubleClick
        ShowDialog()
    End Sub

#End Region

End Class

This is pretty straightforward. The icon and menus are initialized in the class' Sub New, and the icon is made visible. The ThreadExit is where you clean up objects created within the class. The class also handles the Click event for mnuDisplay, which displays a dialog form, and mnuExit, which closes the application. Double clicking on the icon has the same effect as clicking mnuDisplay.

OtherMethods Module

I put the methods ExitApplication and ShowDialog in a separate code file.

Friend Module OtherMethods

    Private PF As PopupForm

    Public Sub ExitApplication()
        'Perform any clean-up here
        'Then exit the application
        Application.Exit()
    End Sub

    Public Sub ShowDialog()
        If PF IsNot Nothing AndAlso Not PF.IsDisposed Then Exit Sub

        Dim CloseApp As Boolean = False

        PF = New PopupForm
        PF.ShowDialog()
        CloseApp = (PF.DialogResult = DialogResult.Abort)
        PF = Nothing

        If CloseApp Then ExitApplication
    End Sub

End Module

The module is tagged as Friend to prevent it from being exported. ExitApplication is where you would clean up any objects that are external to AppContext. Your application shuts down with the call to Application.Exit, which triggers AppContext's ThreadExit event. If you have any open forms, Application.Exit will close those down, exactly as you would expect.

Dialog.jpg

ShowDialog displays a simple dialog box that allows the user to either cancel the form or close the application. I had to do a bit of extra work to guarantee that one and only one dialog box gets displayed: clicking mnuDisplayForm will happily spawn multiple forms otherwise.

Main Method

The next step is to write the code that launches your application. In a public module, declare one of four variations of the Main method.

Public Module LaunchApp

    'Version 1
    '
    Public Sub Main()
        Application.EnableVisualStyles()
        Application.Run(New AppContext)
    End Sub

    'Version 2
    '
    'Public Sub Main(ByVal cmdArgs() As String)
    'End Sub

    'Version 3
    '
    'Public Function Main() As Integer
    'End Function

    'Version 4
    '
    'Public Function Main(ByVal cmdArgs() As String) As Integer
    'End Function

End Module

In most cases, version 1 will be sufficient. If you need access to the command line, then you will want to use version 2. Versions 3 and 4 allow you to return an integer value to the Operating System when your application closes, which is useful only in rare situations.

The call to Application.Run is the key here. There are three overloads: instead of an ApplicationContext, you can also pass a Form object or no parameter. The no parameter version creates a default context which is useful for console applications. The Form version is what VB normally uses internally. You can conditionally call different versions of Application.Run, like so:

Public Sub Main(ByVal cmdArgs() As String)
    Application.EnableVisualStyles()

    Dim UseTray As Boolean = False

    For Each Cmd As String In cmdArgs
        If Cmd.ToLower = "-tray" Then
            UseTray = True
            Exit For
        End If
    Next

    If UseTray Then
        Application.Run(New AppContext)
    Else
        Application.Run(New MainForm)
    End If
End Sub

With this, you can use a command line switch to decide whether your app will launch with a main form or into the notification area.

Note that the first line of code is Application.EnableVisualStyles. For reasons explained below, it is necessary to turn visual styles off when configuring your project; this is where you turn them back on. You don't have to do this, of course, but if your app has any interface elements, they will look nicer if you do.

My Project

The last step is to configure your project to use the Main method. Start by pulling up the My Project interface. On the Application tab, uncheck the "Enable application framework" box. This disables various application framework properties, including the XP visual styles (which is why we need to turn them back on). Now, go to the "Startup object" drop-down and select Sub Main. Be aware that you will select Sub Main even if you are using one of the Function Main methods.

When you run your application, the bootstrap will now call Main. Your custom context class will be launched, which sets up an interactive icon in the notification area.

Conclusion

I hope you found this article useful; if so, please vote it up. And if you find any bugs, please let me know below and I will try to get them fixed.

History

  • Version 4 - May 4, 2010 - Clarified a few points, fixed some grammar, and changed references to "tray" into either "notification area" (the official name) or "system tray" (which Microsoft says is wrong, but still uses in its own documentation). My apologies for the naming confusion.
  • Version 2, 3 - April 26, 2010 - Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gregory Gadow
Software Developer (Senior)
United States United States
Gregory Gadow lives in Seattle, Washington and has been writing code for almost 25 years in more than a dozen programming languages. He works for a mid-size brokerage firm and holds the Series 7 and Series 66 brokerage licenses, but much prefers working as the company's programming department doing VB6, VB.Net, ASP, HTML, XML and SQL.

Comments and Discussions

 
GeneralRe: Added single-click event: Right-click triggers single-click + context menu Pinmemberfredtheman17-Dec-13 5:15 
GeneralRe: Added single-click event: Right-click triggers single-click + context menu Pinmemberfredtheman17-Dec-13 5:28 
QuestionSingle Instance Application PinmemberMember 80698198-Nov-13 3:42 
AnswerRe: Single Instance Application PinmemberGregory.Gadow8-Nov-13 3:53 
GeneralRe: Single Instance Application PinmemberSurazal Taken8-Nov-13 4:35 
QuestionNice Work Pinmember$yKer24-Apr-13 17:13 
GeneralMy vote of 5 Pinmemberjudgedreddgr17-Apr-13 8:08 
QuestionShow a balloon tip Pinmemberstepef11-Feb-13 23:41 
AnswerRe: Show a balloon tip PinmemberGregory.Gadow12-Feb-13 3:53 
GeneralRe: Show a balloon tip Pinmemberstepef12-Feb-13 4:06 
QuestionIcon not clearing PinmemberRodney Buxton14-Nov-12 2:58 
AnswerRe: Icon not clearing PinmemberGregory.Gadow12-Feb-13 3:56 
GeneralMy vote of 5 PinmemberPolinia5-Oct-12 2:34 
GeneralMy vote of 5 PinmemberSamoxin26-Sep-12 12:28 
GeneralMy vote of 5 PinmemberWillB121-Sep-12 18:05 
Questioni think its what im looking for PinmemberRicardo Martins8-Jul-12 2:04 
AnswerRe: i think its what im looking for PinmemberGregory.Gadow10-Jul-12 3:25 
GeneralRe: i think its what im looking for PinmemberRicardo Martins14-Aug-12 4:51 
GeneralMy vote of 5 Pinmemberbryanmajury16-May-12 23:42 
GeneralThanks ... great stuff Pinmemberchuck crego23-Apr-12 7:54 
QuestionForm Controls PinmemberMember 87185042-Apr-12 6:19 
QuestionAdd icons (images) to SubMenuItems [modified] PinmemberRosstarr1-Apr-12 23:56 
AnswerRe: Add icons (images) to SubMenuItems PinmemberGregory.Gadow2-Apr-12 2:25 
AnswerRe: Add icons (images) to SubMenuItems PinmemberZac Greve23-Jun-12 16:31 
QuestionCode Conversion PinmemberMember 871850411-Mar-12 3:59 
AnswerRe: Code Conversion PinmemberGregory.Gadow11-Mar-12 15:57 
QuestionRe: Code Conversion PinmemberMember 871850412-Mar-12 6:59 
AnswerRe: Code Conversion PinmemberGregory.Gadow12-Mar-12 9:41 
GeneralRe: Code Conversion PinmemberMember 871850412-Mar-12 9:59 
Questionusing classes PinmemberXaviersmork3-Mar-12 13:00 
AnswerRe: using classes PinmemberXaviersmork3-Mar-12 13:02 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Feb-12 18:21 
QuestionCan the try icon change on a condition? PinmemberMember 30702916-Jan-12 15:10 
AnswerRe: Can the try icon change on a condition? PinmemberGregory.Gadow26-Jan-12 4:32 
Questionbroker interactive system PinmemberMember 842330822-Nov-11 0:20 
AnswerRe: broker interactive system PinmemberGregory.Gadow22-Nov-11 2:59 
QuestionTray error PinmemberTheOctagon2-Nov-11 12:50 
AnswerRe: Tray error PinmemberGregory.Gadow22-Nov-11 3:05 
GeneralMy vote of 5 Pinmemberbacala027-Sep-11 3:29 
QuestionStart up. Pinmemberginodp25-Aug-11 8:02 
AnswerRe: Start up. Pinmemberginodp25-Aug-11 11:42 
GeneralMy vote of 5 PinmemberGlimmerMan19-Jul-11 5:12 
GeneralIt is really compact and helpful to me. Pinmemberjohnjcky5-Nov-10 1:33 
GeneralThank you Pinmemberdadoing125-Oct-10 3:09 
GeneralMy vote of 5 PinmemberJuan Decray22-Oct-10 11:15 
GeneralThanks PinmemberFreshbrew1-Oct-10 11:14 
GeneralGood job! PinmemberShane Story26-Aug-10 2:43 
GeneralTerminology Correction PinmemberBooGhost30-Apr-10 13:32 
GeneralRe: Terminology Correction PinmemberGregory.Gadow1-May-10 12:31 
GeneralRe: Terminology Correction PinmemberIrwan Hassan4-May-10 2:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 4 May 2010
Article Copyright 2010 by Gregory Gadow
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid