Run VB.NET App in the System Tray, Executing at 6am, every day

I have an application that interfaces with QuickBooks and runs some reports based on sales.  The program takes about an hour to run, so I'm hoping to get it to run at 6am each day, so the user can come in, review the report and do what they need to.

In addition, I'd like the program to run in the background.  I don't want the user to accidently close the program, so I figured, the systray would be the best spot...  but i've never done that before.

So...  2 things :)  1.  How to I get the program to run at 6am every day?  2.  How do you run VB.NET program in the system tray?

If you can point me in the right direction, I'd appreciate it.  Thanks!

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Todd GerbertIT ConsultantCommented:
I would configure your application to run without any forms displayed (perhaps a console application), and use the system's task scheduler to make it run daily.
You also can use a timer who checks every minute what the time is
I dont know how critical your application is and if it is a problem that the procedure starts instead of 6:00:00 am on 6:00:59 am ?

You can run it in the systemtray like this
put a sytemtrayicon on your form
set visible on true
hide your form

Mike TomlinsonMiddle School Assistant TeacherCommented:
If you really want an app that stays open all the time but only has an Icon in the System Tray then here is one way to do it.

This Project can be downloaded at:

The code:
Module Module1

    '  *** How to make a FORMLESS WinForms Project that has a Tray Icon ***
    '  (1) Start with a standard WinForms project
    '  (2) Add a Module and a Public Sub Main to it (see below for example)
    '  (3) Click on Project --> Properties
    '  (4) UNCHEK the "Enable Application Framework" box
    '  (5) Change the "Startup object" to "Sub Main"
    '  (6) Optional: Delete the default Form1.vb from the Project if you don't need it
    '      Note that you CAN still use Forms in your project!  Just display them via code...
    '      (For example, you can use a Form to display a "Setup" or "About" Dialog.)
    '  (7) Change the Resources Tab
    '  (8) Click on the DROPDOWN arrow next to "Add Resource" and select "Add Existing File"
    '  (9) Navigate to your Icon File (.ico) and Double Click it
    ' (10) In the Properties Pane, change the "Persistence" Property to "Embedded"
    ' (11) Add the code below to Sub Main and Paste the "MyContext" Class below the Module

    Public Sub Main()
        Application.Run(New MyContext)
    End Sub

End Module

Public Class MyContext
    Inherits ApplicationContext

    Private Busy As Boolean = False
    Private RunTime As New TimeSpan(15, 34, 0) ' 6:00 am

    Private WithEvents Tray As New NotifyIcon
    Private WithEvents CMS As New ContextMenuStrip
    Private WithEvents mnuExit As New ToolStripMenuItem("Exit")
    Private WithEvents BGW As New System.ComponentModel.BackgroundWorker

    Public Sub New()
        ' This is the new "entry point" for you application
        ' Note that the app does NOT "die" after the constructor exits!
        ' (Explicitly call Application.Exit to shut the app down.)

        ' Icon (.ico) for Tray added via Project --> Properties --> Resources --> Add Existing File
        ' Change the "Persistence" Property of the Resource to "Embedded"
        Tray.Icon = My.Resources.Happy
        Tray.Visible = True

        Tray.ContextMenuStrip = CMS

        BGW.WorkerReportsProgress = True
    End Sub

    Private Sub BGW_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
        While True
            ' reset the "busy" flag
            Busy = False
            BGW.ReportProgress(0, "Sleeping")

            ' sleep until the next run time:
            System.Threading.Thread.Sleep((GetNextRun(RunTime) - DateTime.Now).TotalMilliseconds)

            ' toggle the "busy" flag
            Busy = True
            BGW.ReportProgress(0, "Working")

            ' perform the actual "work":
        End While
    End Sub

    Private Sub GenerateReport()
        System.Threading.Thread.Sleep(15000) ' simulated 15 second work

        ' *** remove the line above and place your report generation code in here ***
    End Sub

    Private Sub BGW_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BGW.ProgressChanged
        Tray.Text = CStr(e.UserState) ' change the current tooltip on the tray

        ' you can also make a balloon appear over your TrayIcon:
        Tray.ShowBalloonTip(TimeSpan.FromSeconds(10).TotalMilliseconds, "Balloon Example", CStr(e.UserState), ToolTipIcon.Info)
    End Sub

    Private Function GetNextRun(ByVal time As TimeSpan) As DateTime
        Dim dt As DateTime = DateTime.Today.Add(time)
        If DateTime.Now > dt Then
            dt = dt.AddDays(1)
        End If

        ' Optional -- If you want to skip Saturday and Sunday:
        While dt.DayOfWeek = DayOfWeek.Saturday OrElse dt.DayOfWeek = DayOfWeek.Sunday
            dt = dt.AddDays(1)
        End While

        Return dt
    End Function

    Private Sub CMS_Opening(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles CMS.Opening
        e.Cancel = Me.Busy ' keep user from seeing the exit menu while we are "working"
    End Sub

    Private Sub mnuExit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuExit.Click
        If Not Busy Then ' just in case the menu was open BEFORE we started and the user clicks on exit AFTER we begin processing
            Application.Exit() ' <-- this is how to close your application!
            Tray.ShowBalloonTip(TimeSpan.FromSeconds(10).TotalMilliseconds, "I'm Busy!", "Try again later please...", ToolTipIcon.Info)
        End If
    End Sub

    Private Sub MyContext_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.ThreadExit
        Tray.Visible = False
    End Sub

End Class

Open in new window

Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

Mike TomlinsonMiddle School Assistant TeacherCommented:
*I was testing with different times so this line (#28):

    Private RunTime As New TimeSpan(15, 34, 0) ' 6:00 am

Should be changed to:

    Private RunTime As New TimeSpan(0, 6, 0) ' 6:00 am
you can use NotifyIcon in
a contextmenustrip can be used for the visibility and hiding of forms.
initially make the form hidden.
then you can do that.


        private void Form2_Resize(object sender, EventArgs e)
            if (FormWindowState.Minimized == WindowState)

        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
            WindowState = FormWindowState.Normal;
Mike TomlinsonMiddle School Assistant TeacherCommented:
Not sure why it's not been suggested, but if you just want it to be in the system tray and not open to the user why not create a service?  You can use a timer / background worker to check the time, and it would run without any user intervention - and they wouldn't be able to close it.

Granted, they could stop the service, but if you ran it under a special user account and restricted access to services.msc then they couldnt.
slightlyoffAuthor Commented:
I should've been more clear, but wasn't sure on how to describe what i was hoping for.

If you look at AVG (or pretty much any anti-virus software), it runs in the system tray, but the user can click it and see the program.  

My program generates a report (hopefully automatically), so the user will need to open up the program to view the report.  The report takes a long time to run (about an hour), so I'd like it to be hidden until it's needed...  so I'd like the same concept applied to my program.

I could also do a system schedule for this program, but I'm eventually hoping to have it maintain inventory levels in real time - and i'd rather not schedule it every 20 or 30 minutes.

I think Idle_Mind is on the right track...I have to look the example to see if I can apply it to this project.

I really appreciate the help!!!
Todd GerbertIT ConsultantCommented:

What if the user logs off his computer, or Windows Updates causes it to reboot automatically overnight? Both highly likely (in my environment, anyway)...
slightlyoffAuthor Commented:
In this environment, the user has agreed not to logoff his computer, so that shouldn't be an issue (unless he forgets).  he doesn't shut it down since he logs in remotley from time to time.  The windows update issue might be a problem, from time to time it will shut down these computers.

Todd GerbertIT ConsultantCommented:
It may not be enough of an issue in your case to worry about such circumstances, just something to consider!

Ahh, well that makes more sense to me.  Certainly an idea to create an app in the system tray.

For the possibility of a shut down, you have could implement that and a service, which you can set to automatically start upon startup should it happen.  Of course, you can set a registry key to do the exact same with an application.  I only mention it because you could run the service on a machine that you control and know wont turn off (you can disable the win updates), and allow the service to process your data and the front end simply read that data from a datasource (SQL, Access, flat file, etc).
slightlyoffAuthor Commented:
Yeah, I appreciate it!  This programming task has grown in scope since I started it, it may not always reside on a user's machine.
Mike TomlinsonMiddle School Assistant TeacherCommented:
With the ApplicationContext approach you can still give a full blown GUI to the user when desired.  Simply display a form in response to one of the menu events.  It's nice since the app doesn't automatically exit when the form is closed.  You have to explicitly call Application.Exit from somewhere in code to make it shutdown.

Definitely lots of ways to go about this though!  =)

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
slightlyoffAuthor Commented:
Thanks for your help :)  I'm still working on it, but I've got the info I need.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.