Click here to Skip to main content
15,889,116 members
Articles / Programming Languages / C#
Article

An Alternative Implementation of the NotifyIcon Class

Rate me:
Please Sign up or sign in to vote.
4.95/5 (59 votes)
12 Apr 20023 min read 431.5K   13K   143   115
A wrapper class for notification icons (tray icons) with support for balloon tips.

Sample Image - NotifyIconEx_img.png

Introduction

I recently wrote a Visual Source Safe sniper application. The purpose of this program is to wait patiently in the background for selected Visual Source Safe files to be checked in by fellow programmers. When the files become checked in the sniper checks these file out and notifies the user. This seemed like a perfect job for a notification icon. I was dismayed however to find out that the .NET class library's NotifyIcon class does not support balloon tips which are currently provided by the newer version of the common control library. This led to my CodeProject article 'Displaying a Notify Icon's Balloon Tool Tip'. However this approach was a hack at best and did not allow the application to receive notification when the balloon tip was clicked. So I decided to bite the bullet and write my own NotifyIcon class which would give me the ability to do everything I wanted.

Functionality

I have kept the functionality of this class to the minimum of what I think is useful. For example I do not handle mouse move messages over the notification icon as I can't think of any good use for these messages. However adding this functionality is quite easy.

List of Features

  • Fires the events 'Click', 'Double Click', 'Click Balloon'
  • Declares properties 'Visible', 'Icon', 'Text', 'Context Menu'
  • Removes icon from notification area when garbage collected (there you go Nish)
  • Re-adds icon if explorer restarts
  • Provides the method ShowBalloon(string title, string text, int timeout)

How It Works

My class uses a similar approach to the .NET class in that it creates a hidden window to receive messages from the notify icon. These messages are then forwarded to the main class NotifyIconEx where they are filtered according to the notification icon's numeric ID. My class can be used to add multiple notify icons and all messages are handled by the one hidden window. At this point I must admit that I used the 'Anakrino' decompiler to take a peek at some of the code used to implement .NET's NotifyIcon class. I mainly used this to figure out how to display the context menu at the correct location and how to make sure that when you click outside of the menu it closes for you.

Platform invoke methods are used quite extensively in this class which is unfortunate but necessary. Hopefully as .NET matures the class library will expand to allow more advanced manipulations of windows and system functions but until then it's either scrap the cool feature or fall back to the Win32 API.

Problems Encountered

I must admit that the documentation concerning the balloon tip does not seem to match the behaviour. The timeout value does not seem to work. I could not get the correct windows message when the balloon is closed by the 'x' button. I get the 'timeout' message whether the balloon times out or it is closed by the user. Let me know if I have done anything wrong in regards to these issues or if anybody gets different results than I did on my XP machine.

Watch Out

I must warn you that if you use my NotifyIconEx class at the same time as NotifyIcon strange things may happen. See if you can figure out why.

Sign Off

I think you will find that my class is as simple to use is that supplied by .NET, if not simpler (you do not have to explicitly remove my icon when your application exits). You should be able to add the class to the toolbox and drag and drop it using the form designer as you can with the built in class.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here



Comments and Discussions

 
GeneralRe: Balloonclick does not work Pin
Chris Porter14-Apr-04 10:15
Chris Porter14-Apr-04 10:15 
QuestionIs there a c++ version? Pin
Anonymous9-Oct-02 16:42
Anonymous9-Oct-02 16:42 
AnswerRe: Is there a c++ version? Pin
Joel Matthias10-Oct-02 4:43
Joel Matthias10-Oct-02 4:43 
GeneralProblem in NotifyIconEx.Create Pin
Ulrich14-Sep-02 2:47
Ulrich14-Sep-02 2:47 
GeneralRe: Problem in NotifyIconEx.Create Pin
Joel Matthias14-Sep-02 9:38
Joel Matthias14-Sep-02 9:38 
GeneralUnhandled Exception Pin
Rodney S. Foley18-Aug-02 16:22
Rodney S. Foley18-Aug-02 16:22 
GeneralRe: Unhandled Exception Pin
Joel Matthias18-Aug-02 18:33
Joel Matthias18-Aug-02 18:33 
GeneralRe: Unhandled Exception Pin
Rodney S. Foley18-Aug-02 20:44
Rodney S. Foley18-Aug-02 20:44 
Well the exact sequence of events are simple. I run the exe I downloaded and click the "Add" button, then BOOM, it blows up. That's all. When I download the source, and open the solution, I do a debug build, then run and click the "Add" button, then BOOM again.

This is the details from the EXE:

See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
System.TypeInitializationException: The type initializer for "JCMLib.NotifyIconEx" threw an exception. ---> System.Security.SecurityException: Request for the permission of type System.Security.Permissions.SecurityPermission, mscorlib, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.
at JCMLib.NotifyIconEx..cctor()
--- End of inner exception stack trace ---
at JCMLib.NotifyIconEx..ctor()
at NotifyIconTest.Form1.OnClickCreate(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Loaded Assemblies **************
mscorlib
Assembly Version: 1.0.3300.0
Win32 Version: 1.0.3705.288
CodeBase: file:///c:/windows/microsoft.net/framework/v1.0.3705/mscorlib.dll
----------------------------------------
NotifyIconTest
Assembly Version: 1.0.831.37168
Win32 Version: 1.0.831.37168
CodeBase: file:///S:/Applications/C%23%20Source%20Code/NotifyIcon%20Class%20Wrapper%20Example/NotifyIconTest.exe
----------------------------------------
System.Windows.Forms
Assembly Version: 1.0.3300.0
Win32 Version: 1.0.3705.288
CodeBase: file:///c:/windows/assembly/gac/system.windows.forms/1.0.3300.0__b77a5c561934e089/system.windows.forms.dll
----------------------------------------
System
Assembly Version: 1.0.3300.0
Win32 Version: 1.0.3705.288
CodeBase: file:///c:/windows/assembly/gac/system/1.0.3300.0__b77a5c561934e089/system.dll
----------------------------------------
System.Drawing
Assembly Version: 1.0.3300.0
Win32 Version: 1.0.3705.288
CodeBase: file:///c:/windows/assembly/gac/system.drawing/1.0.3300.0__b03f5f7f11d50a3a/system.drawing.dll
----------------------------------------

************** JIT Debugging **************
To enable just in time (JIT) debugging, the config file for this
application or machine (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.

For example:

<configuration>
<system.windows.forms jitDebugging="true" />
</configuration>

When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the machine
rather than being handled by this dialog.


This is the error info from running in debug mode:

::Call Stack Window::

> NotifyIconTest.exe!NotifyIconTest.Form1.OnClickCreate(System.Object sender = {Text="Add"}, System.EventArgs e = {System.EventArgs}) Line 219 + 0x14 bytes C#
system.windows.forms.dll!System.Windows.Forms.Control::OnClick(System.EventArgs e = {System.EventArgs}) + 0x63 bytes
system.windows.forms.dll!System.Windows.Forms.Button::OnClick(System.EventArgs e = {System.EventArgs}) + 0x38 bytes
system.windows.forms.dll!System.Windows.Forms.Button::OnMouseUp(System.Windows.Forms.MouseEventArgs mevent = {X=107 Y=11 Button=Left}) + 0x11c bytes
system.windows.forms.dll!System.Windows.Forms.Control::WmMouseUp(System.Windows.Forms.Message m = {System.Windows.Forms.Message}, System.Windows.Forms.MouseButtons button = Left, __int32 clicks = 1) + 0x235 bytes
system.windows.forms.dll!System.Windows.Forms.Control::WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x481 bytes
system.windows.forms.dll!System.Windows.Forms.ButtonBase::WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x11a bytes
system.windows.forms.dll!System.Windows.Forms.Button::WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x8d bytes
system.windows.forms.dll!ControlNativeWindow::OnMessage(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x19 bytes
system.windows.forms.dll!ControlNativeWindow::WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0xda bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow::DebuggableCallback(__int32 hWnd = 1247558, __int32 msg = 514, __int32 wparam = 0, __int32 lparam = 721003) + 0x39 bytes
system.windows.forms.dll!System.Windows.Forms.Application::ComponentManagerSystem.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(__int32 dwComponentID = 1, __int32 reason = -1, __int32 pvLoopData = 0) + 0x2c1 bytes
system.windows.forms.dll!ThreadContext::RunMessageLoop(__int32 reason = -1, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.ApplicationContext}) + 0x1c5 bytes
system.windows.forms.dll!System.Windows.Forms.Application::Run(System.Windows.Forms.Form mainForm = {NotifyIconTest.Form1}) + 0x37 bytes
NotifyIconTest.exe!NotifyIconTest.Form1.Main() Line 207 C#


::Output Window::

'DefaultDomain': Loaded 'c:\windows\microsoft.net\framework\v1.0.3705\mscorlib.dll', No symbols loaded.
'NotifyIconTest': Loaded 'S:\Applications\C# Source Code\NotifyIcon Class Wrapper Example\NotifyIconTest\bin\Debug\NotifyIconTest.exe', Symbols loaded.
'NotifyIconTest.exe': Loaded 'c:\windows\assembly\gac\system.windows.forms\1.0.3300.0__b77a5c561934e089\system.windows.forms.dll', No symbols loaded.
'NotifyIconTest.exe': Loaded 'c:\windows\assembly\gac\system\1.0.3300.0__b77a5c561934e089\system.dll', No symbols loaded.
'NotifyIconTest.exe': Loaded 'c:\windows\assembly\gac\system.drawing\1.0.3300.0__b03f5f7f11d50a3a\system.drawing.dll', No symbols loaded.
'NotifyIconTest.exe': Loaded 'c:\windows\assembly\gac\accessibility\1.0.3300.0__b03f5f7f11d50a3a\accessibility.dll', No symbols loaded.
An unhandled exception of type 'System.Security.SecurityException' occurred in NotifyIconTest.exe

Additional information: Request for the permission of type System.Security.Permissions.SecurityPermission, mscorlib, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.

I hope this helps, I am still at a loss also.
GeneralRe: Unhandled Exception Pin
Joel Matthias20-Aug-02 5:17
Joel Matthias20-Aug-02 5:17 
GeneralRe: Unhandled Exception Pin
Rodney S. Foley20-Aug-02 12:41
Rodney S. Foley20-Aug-02 12:41 
GeneralRe: Unhandled Exception Pin
Rodney S. Foley23-Aug-02 14:13
Rodney S. Foley23-Aug-02 14:13 
GeneralRe: Unhandled Exception Pin
Joel Matthias23-Aug-02 17:40
Joel Matthias23-Aug-02 17:40 
GeneralRe: Unhandled Exception Pin
Rodney S. Foley23-Aug-02 18:36
Rodney S. Foley23-Aug-02 18:36 
GeneralRe: Unhandled Exception Pin
Rodney S. Foley24-Aug-02 12:08
Rodney S. Foley24-Aug-02 12:08 
GeneralRe: Unhandled Exception Pin
Rodney S. Foley24-Aug-02 12:48
Rodney S. Foley24-Aug-02 12:48 
GeneralRe: Unhandled Exception Pin
Joel Matthias24-Aug-02 14:47
Joel Matthias24-Aug-02 14:47 
GeneralVB.NET Pin
8-Jun-02 19:32
suss8-Jun-02 19:32 
Questionpotential threading issue? Pin
Andy Smith15-Apr-02 8:01
Andy Smith15-Apr-02 8:01 
AnswerRe: potential threading issue? Pin
Joel Matthias15-Apr-02 9:44
Joel Matthias15-Apr-02 9:44 
QuestionHow to send message to notification icon from other program? Pin
12-Apr-02 11:27
suss12-Apr-02 11:27 
AnswerRe: How to send message to notification icon from other program? Pin
Joel Matthias12-Apr-02 19:03
Joel Matthias12-Apr-02 19:03 
GeneralRe: How to send message to notification icon from other program? Pin
Paul A. Howes14-Apr-02 3:02
Paul A. Howes14-Apr-02 3:02 
GeneralIdeas to improve code Pin
Andy Smith12-Apr-02 10:42
Andy Smith12-Apr-02 10:42 
GeneralRe: Ideas to improve code Pin
Joel Matthias12-Apr-02 11:23
Joel Matthias12-Apr-02 11:23 
GeneralRe: Ideas to improve code Pin
Andy Smith12-Apr-02 13:37
Andy Smith12-Apr-02 13:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.