• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 277
  • Last Modified:

System tray - deleting icon?

If you use the Win32 API's SHELL_NOTIFY_ICON to place the icon for an app in the system tray after the app terminates the icon stubbornly refuses to remove itself from the systray. If however you place the mouse pointer over it it then disappears.

Is there some code that you can put some code into the Form_Unload event to delete the icon.

It looks particularly bad if the user opens the app half a dozen times and there's a row of icons stacked up...

I'm already using the DELETE function but this simply doesn't work

TIA

Derek.
0
derek_noonan
Asked:
derek_noonan
1 Solution
 
VbmasterCommented:
One might wonder how ya DELETE function looks like? Do you have the NOTIFYICONDATA structure declared as a public/private variable, so it aint declared inside the procedure i mean... ?
0
 
JuiletteCommented:
compare notes....'add a picture box with propery of invisible = true
'mouse down in this example restores and minimizes the form
'provisions for extra code are there ( Case Select Mouse Move )
'set show in taskbar = true
'
Option Explicit
'
Private Type NOTIFYICONDATA
  cbSize As Long
  hwnd As Long
  uID As Long
  uFlags As Long
  uCallbackMessage As Long
  hIcon As Long
  szTip As String * 64
End Type

Private Const NIF_ICON = &H2
Private Const NIF_MESSAGE = &H1
Private Const NIF_TIP = &H4
Private Const NIM_ADD = &H0
Private Const NIM_DELETE = &H2
Option Explicit

Private Type NOTIFYICONDATA
  cbSize As Long
  hwnd As Long
  uID As Long
  uFlags As Long
  uCallbackMessage As Long
  hIcon As Long
  szTip As String * 64
End Type

Private Const NIF_ICON = &H2
Private Const NIF_MESSAGE = &H1
Private Const NIF_TIP = &H4
Private Const NIM_ADD = &H0
Private Const NIM_DELETE = &H2
Private Const NIM_MODIFY = &H1
Private Const WM_MOUSEMOVE = &H200

Private frmSysTrayIcon As NOTIFYICONDATA

Private Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long

Private Sub picSysTray_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
   
  Select Case Right(Hex(X), 2)
    Case "00"  ' Mouse Move
      '<<< Put Your Code Here >>>
    Case "0F"  ' Left Mouse Down
      '<<< Put Your Code Here >>>
        'If the Window is Minimized, Restore it,
        'Else Minimize it.
        WindowState = IIf(WindowState = vbNormal, vbMinimized, vbNormal)
    Case "1E"  ' Left Mouse Up
      '<<< Put Your Code Here >>>
    Case "3C"  ' Right Mouse Down
      '<<< Put Your Code Here >>>
    Case "4B"  ' Right Mouse Up
      '<<< Put Your Code Here >>>
    Case "2D"  ' Double Left Click
      '<<< Put Your Code Here >>>
    Case "5A"  ' Double Right Click
      '<<< Put Your Code Here >>>
  End Select
   
End Sub
   
Private Sub Form_Load()
   
  Dim SysTrayToolTip As String
   
  SysTrayToolTip = "System Tray Icon"
   
  '----- Setup the icon in the SysTray -----
   
  'Image to appear in SysTray
  frmSysTrayIcon.hIcon = picSysTray.Picture
  'Handle of Object to recieve SysTray icon events
  frmSysTrayIcon.hwnd = picSysTray.hwnd
  'ToolTipText for SysTray icon [Must end with Chr(0)]
  frmSysTrayIcon.szTip = SysTrayToolTip & Chr(0)
  'Event triggered when interacting with SysTray icon
  frmSysTrayIcon.uCallbackMessage = WM_MOUSEMOVE
  'Parts of SysTray icon we want to setup
  frmSysTrayIcon.uFlags = NIF_ICON Or NIF_MESSAGE Or NIF_TIP
  'Unique identifier
  frmSysTrayIcon.uID = 1
  'Size of this variable in bytes
  frmSysTrayIcon.cbSize = Len(frmSysTrayIcon)
   
  '----- Add the icon to the SysTray -----
   
  Shell_NotifyIcon NIM_ADD, frmSysTrayIcon
   
End Sub

Private Sub Form_Unload(Cancel As Integer)
   
  ' Remove Icon from System Tray
  Shell_NotifyIcon NIM_DELETE, frmSysTrayIcon
   
End Sub


0
 
derek_noonanAuthor Commented:
Juilette & VBMaster

Juilette,
There's only two things that are different in my code (if you wish I'll send you the appropriate modules)and that is that I use the app icon for the systray icon instead of a picture box and I have the app invisible in taskbar

The code appeared in MSDN ages ago and I simply copied and pasted it and altered it where appropriate (added a new tooltip, changed the icon and other various mickey-mouse things)

I have only a top level understanding of how the code works as the finer points of the Win32 API escape me from time to time

I don't wish to be difficult but there doesn't appear to be any substantive difference between your code and mine...

VbMaster,
In response to VBMaster the NOTIFYICONDATA is declared at module level - not prcedure level
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
JuiletteCommented:
Ok..paste your type declarations and your unload code

I just realized I posted my type declarations twice..that wouldn't work real time...
after the second Option Explicit there is a type dec...
Then with this line I am transfering the type into a varaible to be used
in the unload event..

Private frmSysTrayIcon As NOTIFYICONDATA

'then I am deleting the icon on exit

Private Sub Form_Unload(Cancel As Integer)
   
  ' Remove Icon from System Tray
  Shell_NotifyIcon NIM_DELETE, frmSysTrayIcon
   
End Sub

If you can't get it post your code and I'll copy it iton an app and see where it needs to be tweeked..if I can

Wayne



0
 
Erick37Commented:
Place a breakpoint at the line:
Shell_NotifyIcon NIM_DELETE, ...
to be sure your code actually reaches it.

Make sure you do not have an End statement somewhere in your code that terminates the program before the Unload event is reached.
0
 
derek_noonanAuthor Commented:
Okay here's the code in three parts..

============================================
First the module: (modSysTrayStuff):

' User defined type required by Shell_NotifyIcon API call
      Public Type NOTIFYICONDATA
       cbSize As Long
       hwnd As Long
       uId As Long
       uFlags As Long
       uCallBackMessage As Long
       hIcon As Long
       szTip As String * 64
      End Type

' Constants required by Shell_NotifyIcon API call
      Public Const NIM_ADD = &H0
      Public Const NIM_MODIFY = &H1
      Public Const NIM_DELETE = &H2
      Public Const NIF_MESSAGE = &H1
      Public Const NIF_ICON = &H2
      Public Const NIF_TIP = &H4
      Public Const WM_MOUSEMOVE = &H200
      Public Const WM_LBUTTONDOWN = &H201     'Button down
      Public Const WM_LBUTTONUP = &H202       'Button up
      Public Const WM_LBUTTONDBLCLK = &H203   'Double-click
      Public Const WM_RBUTTONDOWN = &H204     'Button down
      Public Const WM_RBUTTONUP = &H205       'Button up
      Public Const WM_RBUTTONDBLCLK = &H206   'Double-click

      Public Declare Function SetForegroundWindow Lib "user32" _
      (ByVal hwnd As Long) As Long
      Public Declare Function Shell_NotifyIcon Lib "shell32" _
      Alias "Shell_NotifyIconA" _
      (ByVal dwMessage As Long, pnid As NOTIFYICONDATA) As Boolean

      Public nid As NOTIFYICONDATA

============================================
Now Form_Load() - the part that's relevant

Me.Show
       Me.Refresh
       With nid
        .cbSize = Len(nid)
        .hwnd = Me.hwnd
        .uId = vbNull
        .uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE
        .uCallBackMessage = WM_MOUSEMOVE
        .hIcon = Me.Icon
        .szTip = App.ProductName & " " & App.Major & "." & App.Minor & ", Build " & App.Revision & vbNullChar
       End With
       Shell_NotifyIcon NIM_ADD, nid
============================================

Finally Form_Unload() - again relevant bits only

 ' This removes the icon from the system tray (or at least it should)
       Shell_NotifyIcon NIM_DELETE, nid
             
         ' Unload all the forms that may be resident in memory...
         Dim frmTemp As Form
         For Each frmTemp In Forms
            Unload frmTemp
         Next frmTemp
     
' Put it in twice to make sure it does it...
      Shell_NotifyIcon NIM_DELETE, nid
0
 
JuiletteCommented:
Take your bas module code out of  the bas module and put it in the form's general declarations...it has to be local to the form involved

Change all the public to private

tested it and it works.

Wayne
0
 
JuiletteCommented:
PS...my code...Private...your code Public....that's the difference.
0
 
JuiletteCommented:
Thanks,
I forgot..the extra code in mine and the pic box allows the form to be sent to and from the desktop and icon tray by clicking on the icon...useful if you have an app that stays on top and you want to get it out of the way momentarily.

Signing off
Wayne
0
 
derek_noonanAuthor Commented:
All,

I'm revisiting this issue after a break - as the song goes "I can see clearly now the rain has gone..."

If you create a form with all the above code in it and save as, say frmSysTray then you can instantiate another frmSysTray from another form as follows:

 Set m_frmSysTray = New frmSysTray

The form then behaves itself...

Thanks to all who contributed...
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now