Attribute VB_Name = "modIcon"
Option Explicit

Private Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
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

'Declare a Form Global Variable for the SysTray Icon Data
Private udtNI As NOTIFYICONDATA
Const NIM_ADD = &H0
Const NIM_DELETE = &H2
Const NIM_MODIFY = &H1
Const NIF_ICON = &H2
Const NIF_MESSAGE = &H1
Const NIF_TIP = &H4
' These are the call back messages
Public Const WM_MOUSEMOVE = &H200
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_RBUTTONDOWN = &H204
Public Const WM_LBUTTONDBLCLK = &H203

' This is to restore the icon when it needs adding again
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Const GWL_WNDPROC        As Long = (-4)
Private lOrigWndProc As Long
Private lCurHwnd As Long

Public Function AddIcon() As Boolean

    With udtNI
        'Image to appear in Tray
        .hIcon = frmServer.Icon
        'Handle of Object to recieve Tray Icon Events
        .hWnd = frmServer.pctSys.hWnd
        'Caption for Tray Icon, Must End with Chr(0), otherwise you'll
        'get a long tooltip
        .szTip = App.Title & Chr(0)
        'Event Triggered
        .uCallbackMessage = WM_MOUSEMOVE
        .uFlags = NIF_ICON Or NIF_MESSAGE Or NIF_TIP
        .uID = 1
        'Size of this udt.
        .cbSize = Len(udtNI)
    End With
        
    'Add the Icon to the SysTray
    Shell_NotifyIcon NIM_ADD, udtNI
    
    Call SubClassForm(frmServer.hWnd)
End Function

Public Function DeleteIcon() As Boolean
    
    ' un-subclass the form, before deleting the icon,
    ' so if explorer crashes and re-opens, it wont re-add the icon
    Call UnSubClassForm
    
    ' Loose the Systray Icon
    Shell_NotifyIcon NIM_DELETE, udtNI
    
End Function

Private Function UpdateIcon() As Boolean

    If udtNI.szTip <> Empty Then
        ' Loose the Systray Icon
        UpdateIcon = Shell_NotifyIcon(NIM_DELETE, udtNI)
        
        ' if it failed to update the icon, then add the icon
        If UpdateIcon = False Then UpdateIcon = Shell_NotifyIcon(NIM_ADD, udtNI)
        
    Else
        UpdateIcon = False
    End If
    
End Function

Private Sub SubClassForm(lHwnd As Long)
    If lHwnd <> 0 Then
        lOrigWndProc = SetWindowLong(lHwnd, GWL_WNDPROC, AddressOf FormWndProc)
        lCurHwnd = lHwnd
    End If
End Sub

Private Sub UnSubClassForm()
    Call SetWindowLong(lCurHwnd, GWL_WNDPROC, lOrigWndProc)
    lCurHwnd = 0
    lOrigWndProc = 0
End Sub


Private Function FormWndProc(ByVal hwndMsg As Long, ByVal uMsg As Long, _
                             ByVal wParam As Long, ByVal lParam As Long) As Long
On Error Resume Next

        ' I've worked out that the uMsg 49252 is sent when
        ' the windows systray restores after an explorer crash
        If uMsg = 49252 And lCurHwnd = hwndMsg Then Call UpdateIcon
        
        'pass to original message handler
        FormWndProc = CallWindowProc(lOrigWndProc, hwndMsg, uMsg, wParam, lParam)
        
End Function



