What's New
Q & A
Tip Jar
C# Helper...
Follow VBHelper on Twitter
MSDN Visual Basic Community
TitleDisplay a form in the system tray with no other icon
Keywordssystem tray, icon, taskbar
CategoriesSoftware Engineering, Windows, API

Note that my book Custom Controls Library includes a control that manipulates the system tray and another that animates a system tray icon.

Set ShowInTaskBar = False so the form's icon doesn't appear in the task bar. Give the form an appropriate icon.

When the program starts, it calls AddToTray to add itself to the system tray. It then calls SetTrayTip to give its system tray icon a tooltip.

Public LastState As Integer

Private Sub Form_Load()
    If WindowState = vbMinimized Then
        LastState = vbNormal
        LastState = WindowState
    End If

    AddToTray Me, mnuTray
    SetTrayTip "VB Helper tray icon program"
End Sub
Subroutine AddToTray gives the form a new WindowProc so it can look for tray events. It then uses the Shell_NotifyIcon API function to make the tray icon. Note that the data structure sets .hIcon = frm.Icon.Handle so the tray icon uses the form's icon.
' Add the form's icon to the tray.
Public Sub AddToTray(frm As Form, mnu As Menu)
    ' ShowInTaskbar must be set to False at
    ' design time because it is read-only at
    ' run time.

    ' Save the form and menu for later use.
    Set TheForm = frm
    Set TheMenu = mnu
    ' Install the new WindowProc.
    OldWindowProc = SetWindowLong(frm.hwnd, _
        GWL_WNDPROC, AddressOf NewWindowProc)
    ' Install the form's icon in the tray.
    With TheData
        .uID = 0
        .hwnd = frm.hwnd
        .cbSize = Len(TheData)
        .hIcon = frm.Icon.Handle
        .uFlags = NIF_ICON
        .uCallbackMessage = TRAY_CALLBACK
        .uFlags = .uFlags Or NIF_MESSAGE
        .cbSize = Len(TheData)
    End With
    Shell_NotifyIcon NIM_ADD, TheData
End Sub
Subroutine SetTrayTip uses Shell_NotifyIcon to set the tray icon's tooltip.
' Set a new tray tip.
Public Sub SetTrayTip(tip As String)
    With TheData
        .szTip = tip & vbNullChar
        .uFlags = NIF_TIP
    End With
    Shell_NotifyIcon NIM_MODIFY, TheData
End Sub
When the new WindowProc sees the WM_NCDESTROY message, it calls RemoveFromTray to remove the tray icon and restore the original WindowProc. If you do not remove the tray icon, it remains in the tray but doesn't work properly.

If the new WindowProc sees a TRAY_CALLBACK message, it checks the event in more detail. If the user left clicked the tray icon, the program shows the form. If the user right clicked the icon, the program displays a popup menu that contains such commands as Restore, Minimize, Maximize, and Close. Those menu commands do pretty much what you would expect.

If the new WindowProc sees a minimize command, it hides the form instead. If it sees a restore command, it displays the form if it is hidden.

' The replacement window proc.
Public Function NewWindowProc(ByVal hwnd As Long, ByVal Msg _
    As Long, ByVal wParam As Long, ByVal lParam As Long) As _
Const SC_MAXIMIZE = &HF030&
Const SC_MINIMIZE = &HF020&
Const SC_RESTORE = &HF120&

    ' If we're being destroyed, remove the tray icon
    ' and restore the original WindowProc.
    If Msg = WM_NCDESTROY Then
    ElseIf Msg = TRAY_CALLBACK Then
        ' The user clicked on the tray icon.
        ' Look for click events.
        If lParam = WM_LBUTTONUP Then
            ' On left click, show the form.
            If TheForm.WindowState = vbMinimized Then _
                TheForm.WindowState = TheForm.LastState
            Exit Function
        End If
        If lParam = WM_RBUTTONUP Then
            ' On right click, show the menu.
            SetForegroundWindow TheForm.hwnd
            TheForm.PopupMenu TheMenu
            If Not (TheForm Is Nothing) Then
                PostMessage TheForm.hwnd, WM_NULL, ByVal _
                    0&, ByVal 0&
            End If
            Exit Function
        End If
    End If

    If Msg = WM_SYSCOMMAND Then
        If wParam = SC_MINIMIZE Then
            TheForm.SetTrayMenuItems vbMinimized
            Exit Function
        ElseIf wParam = SC_RESTORE Then
            If Not TheForm.Visible Then
                TheForm.SetTrayMenuItems vbNormal
                Exit Function
            End If
        End If
    End If

    ' Send other messages to the original
    ' window proc.
    NewWindowProc = CallWindowProc( _
        OldWindowProc, hwnd, Msg, _
        wParam, lParam)
End Function
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.