I've observed an odd behavior of NotifyIcon. It remains visible after application closes and stays visible untill mouse-hovered.
Note: My icon was created programaticaly (not placed as component on forms) and I haven't set its Container property.
For simple example I've created following console application. In console application it's quite easy to Dispose NotifyIncon before Main quits, but in real-world application I expect do Dispose resources used by NotifyInconHolder when it's being Disposed/Finalized. But in that point the noi variable is already disposed (you cannot set its Visible = False - it fails). And the Disposed event is not raised by noi.
Imports System.Windows.Forms
Module Module1
Sub Main()
Dim nh As New NotifyIconHolder
End Sub
End Module
Friend Class NotifyIconHolder
Implements IDisposable
Private noi As New NotifyIcon
Public Sub New()
noi.Icon = New Drawing.Icon("D:\Program Files\Microsoft Visual Studio 8\Common7\VS2005ImageLibrary\icons\Misc\Code_ClassCS.ico")
noi.Visible = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
noi.Dispose()
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Dispose()
MyBase.Finalize()
End Sub
End Class
The only workaround I was able to work out follows. It involver P/Inwoke to Win32 API and does what youser do to hide the icon: Finds the systray, shows hidden icons, moves mouse over systray.
Imports
System.Windows.Forms
Module
Module1
Sub Main()
Dim nh AsNew NotifyIconHolder
EndSub
End
Module
Friend
Class NotifyIconHolder
Implements IDisposable
Private noi AsNew NotifyIcon
PublicSubNew()
noi.Icon =
New Drawing.Icon("D:\Program Files\Microsoft Visual Studio 8\Common7\VS2005ImageLibrary\icons\Misc\Code_ClassCS.ico")
noi.Text =
"TestIcon"
noi.Visible =
True
EndSub
Private Disposed AsBoolean
PublicSub Dispose() Implements IDisposable.Dispose
noi.Dispose()
IfNot Disposed Then
Dim Shell_TrayWnd% = FindWindow("Shell_TrayWnd", Nothing)
If Shell_TrayWnd <> 0Then
Dim TrayNotifyWnd% = FindWindowEx(Shell_TrayWnd, 0, "TrayNotifyWnd", Nothing)
If TrayNotifyWnd <> 0Then
Dim SysPager% = FindWindowEx(TrayNotifyWnd, 0, "SysPager", Nothing)
If SysPager <> 0Then
Dim ToolbarWindow32% = FindWindowEx(SysPager, 0, "ToolbarWindow32", Nothing)
Dim Button% = FindWindowEx(TrayNotifyWnd, 0, "Button", Nothing)
If Button <> 0Then
SendMessage(Button, WM_LBUTTONDOWN, MK_LBUTTON,
0)
SendMessage(Button, WM_LBUTTONUP,
0, 0)
EndIf
If ToolbarWindow32 <> 0Then
Dim Rect AsNew RECT
GetWindowRect(ToolbarWindow32, Rect)
For i AsInteger = Rect.Left To Rect.Right Step8
SendMessage(ToolbarWindow32, WM_MOUSEMOVE,
0, i - Rect.Left Or8 << 16)
Next i
EndIf
EndIf
EndIf
EndIf
Disposed =
True
EndIf
GC.SuppressFinalize(
Me)
EndSub
ProtectedOverridesSub Finalize()
Dispose()
MyBase.Finalize()
EndSub
End
Class
Friend
Module API
PublicDeclareAutoFunction FindWindow Lib"user32.dll" (ByVal lpClassName AsString, ByVal lpWindowName AsString) As Int32
PublicDeclareAutoFunction FindWindowEx Lib"user32.dll" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 AsString, ByVal lpsz2 AsString) As Int32
PublicDeclareAutoFunction SendMessage Lib"user32.dll" (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As Int32
PublicConst WM_MOUSEMOVE As Int32 = &H200
PublicConst WM_LBUTTONDOWN As Int32 = &H201
PublicConst WM_LBUTTONUP As Int32 = &H202
PublicConst MK_LBUTTON As Int32 = &H1
PublicDeclareFunction GetWindowRect Lib"user32.dll" (ByVal hwnd As Int32, ByRef lpRect As RECT) As Int32
End
Module
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential)> _
Public
Structure RECT
Public Left As Int32
Public Top As Int32
Public Right As Int32
Public Bottom As Int32
End
Structure
Bug report at https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98317. MS is not going to fix this buggy behavior.