Click here to Skip to main content
11,640,788 members (60,553 online)
Click here to Skip to main content

Displaying a Notify Icon's Balloon Tool Tip

, 29 Mar 2002 374.7K 7.9K 82
Rate this:
Please Sign up or sign in to vote.
Displaying a balloon tool tip for a notification icon.
<!-- Download Links --> <!-- Article image -->

Sample Image - NotifyBalloon.png

<!-- Add the rest of your HTML here -->

Introduction

This article shows one approach to displaying a balloon tool tip for a notify icon created using the FCL's NotifyIcon class. This relatively new feature of notification icons is not supported by the NotifyIcon class and adding this feature to my own code was not immediately obvious without some creative coding. This is why I am presenting it here. The other reason is that I am hoping somebody can tell me that I'm doing it all wrong and that there is a much more 'correct' solution.

This article also serves as an example of the use of the platform invoke facility. It shows how to create a data structure required by a Win32 API function and how to pass that structure to the API function.

The way I have accomplished the task involves the following two steps:

  1. Using the Win32 API get the handle to the hidden FCL created notify message window.
  2. 2. Use the Win32 API to send the 'balloon tip' message to the notify icon.

A Little Background

Notification icons communicate with their parent applications by sending windows messages to a window supplied when the notify icon is created. The FCL NotifyIcon class does not supply any information about this window (one of the disadvantages of working at a higher level of abstraction). The FCL creates a hidden window for a NotifyIcon and converts the windows messages sent to it into .NET consumable events.

In order to use the Win32 API to communicate with the notification icon you must obtain the Win32 window handle of the window receiving the messages, and also the numeric ID of the icon.

The Solution

Using Spy++ I determined the class name of the hidden window created by the FCL. I then used the Win32 API to find the handle of that window (looking only at the windows owned by my thread). The ID was determined by trial and error! I found that if you have one notify icon created by your app the ID will be 1 (not 0). Once I have the window handle I then call Shell_NotifyIcon() to send it the 'balloon' message. The only trick to this part is defining the data structure required to be sent to this API function.

The Caveats

This solution is a basically a hack for a few reasons. Here are the assumptions I made that may not always be true.

  1. I assumed that calling the Win32 API function GetCurrentThreadId() would return me the correct thread ID.
  2. I assume the name of the window class created by the FCL is fixed. Of course this may not be true in the future.
  3. I assume that the ID of the icon is 1 for the first created icon.
  4. Part of the reason I am posting this code is to maybe get some feedback on how I can reduce the number of assumptions that are made. So let me know if you come up with anything.

Here is the code for the NotifyIcon class that shows the balloon.

public class NotifyIcon
{
    [StructLayout(LayoutKind.Sequential)]
        public struct NotifyIconData
    {
        public System.UInt32 cbSize; // DWORD
        public System.IntPtr hWnd; // HWND
        public System.UInt32 uID; // UINT
        public NotifyFlags uFlags; // UINT
        public System.UInt32 uCallbackMessage; // UINT
        public System.IntPtr hIcon; // HICON
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
        public System.String szTip; // char[128]
        public System.UInt32 dwState; // DWORD
        public System.UInt32 dwStateMask; // DWORD
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
        public System.String szInfo; // char[256]
        public System.UInt32 uTimeoutOrVersion; // UINT
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
        public System.String szInfoTitle; // char[64]
        public System.UInt32 dwInfoFlags; // DWORD
        //GUID guidItem; > IE 6
    }

    public enum NotifyCommand {Add = 0, Modify = 1, Delete = 2, SetFocus = 3, 
                               SetVersion = 4}
    public enum NotifyFlags {Message = 1, Icon = 2, Tip = 4, State = 8, Info = 16, 
                             Guid = 32}

    [DllImport("shell32.Dll")]
    public static extern System.Int32 Shell_NotifyIcon(NotifyCommand cmd, 
                                                       ref NotifyIconData data);

    [DllImport("Kernel32.Dll")]
    public static extern System.UInt32 GetCurrentThreadId();

    public delegate System.Int32 EnumThreadWndProc(System.IntPtr hWnd, 
                                                   System.UInt32 lParam);

    [DllImport("user32.Dll")]
    public static extern System.Int32 EnumThreadWindows(System.UInt32 threadId, 
                                        EnumThreadWndProc callback, 
                                        System.UInt32 param);

    [DllImport("user32.Dll")]
    public static extern System.Int32 GetClassName(System.IntPtr hWnd, 
                                                  System.Text.StringBuilder className,
                                                  System.Int32 maxCount);

    private System.IntPtr m_notifyWindow;
    private bool m_foundNotifyWindow;

    // Win32 Callback Function
    private System.Int32 FindNotifyWindowCallback(System.IntPtr hWnd, 
                                                  System.UInt32 lParam)
    {
        System.Text.StringBuilder buffer = new System.Text.StringBuilder(256);
        GetClassName(hWnd, buffer, buffer.Capacity);

		// but what if this changes?  - anybody got a better idea?
        if(buffer.ToString() == "WindowsForms10.Window.0.app1") 
        {
            m_notifyWindow = hWnd;
            m_foundNotifyWindow = true;
            return 0; // stop searching
        }
        return 1;
    }

    public void ShowBalloon(uint iconId, string title, string text, uint timeout)
    {
        // find notify window
        uint threadId = GetCurrentThreadId();
        EnumThreadWndProc cb = new EnumThreadWndProc(FindNotifyWindowCallback);
        m_foundNotifyWindow = false;
        EnumThreadWindows(threadId, cb, 0);
        if(m_foundNotifyWindow)
        {
            // show the balloon
            NotifyIconData data = new NotifyIconData();
            data.cbSize = (System.UInt32)
                          System.Runtime.InteropServices.Marshal.SizeOf(
                                                                typeof(NotifyIconData));
            data.hWnd = m_notifyWindow;
            data.uID = iconId;
            data.uFlags = NotifyFlags.Info;
            data.uTimeoutOrVersion = 15000;
            data.szInfo = text;
            data.szInfoTitle = title;
            Shell_NotifyIcon(NotifyCommand.Modify, ref data);
        }
    }
}

Here is the code that shows the usage of the class.

private void OnShowBalloon(object sender, System.EventArgs e)
{
    NotifyBalloonDemo.NotifyIcon notifyIcon = new NotifyBalloonDemo.NotifyIcon();
    notifyIcon.ShowBalloon(1, "My Title", "My Text", 15000);
}

So come on people, show me how to do this correctly.

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

Share

About the Author


You may also be interested in...

Comments and Discussions

 
GeneralGood Pin
dxlee23-Oct-09 4:48
memberdxlee23-Oct-09 4:48 
GeneralFYI - balloon tips are now built into .net Pin
masonmccuskey5-Jan-09 10:24
membermasonmccuskey5-Jan-09 10:24 
GeneralNotify balloon background color Pin
Daanab25-Oct-08 1:24
memberDaanab25-Oct-08 1:24 
GeneralRe: Notify balloon background color Pin
ceekays24-Oct-11 3:25
memberceekays24-Oct-11 3:25 
GeneralThanks. Working. Pin
tmwinn1-Oct-08 21:01
membertmwinn1-Oct-08 21:01 
GeneralAdd Title Icon Pin
rbrooks4224-Oct-05 17:52
memberrbrooks4224-Oct-05 17:52 
GeneralOnClick Event Pin
Steve2514-Sep-05 3:40
memberSteve2514-Sep-05 3:40 
QuestionIt works....but Pin
lamlai4-Sep-05 20:25
memberlamlai4-Sep-05 20:25 
GeneralGood code, but u can safely remove ur assumptions Pin
naveedahmedsiddiqui2-Sep-05 3:03
membernaveedahmedsiddiqui2-Sep-05 3:03 
GeneralRe: Good code, but u can safely remove ur assumptions Pin
SGarratt13-Sep-05 8:59
memberSGarratt13-Sep-05 8:59 
Generaloops, forgot to add GetNotifyIconID() Pin
SGarratt13-Sep-05 9:10
memberSGarratt13-Sep-05 9:10 
GeneralDidn't work in XP Pin
rpires23-Aug-05 14:21
memberrpires23-Aug-05 14:21 
GeneralRe: Didn't work in XP Pin
tayspen21-Sep-05 9:55
membertayspen21-Sep-05 9:55 
GeneralRe: Didn't work in XP Pin
mmansf25-Nov-05 7:34
membermmansf25-Nov-05 7:34 
GeneralRe: Didn't work in XP Pin
calvinchang11-Jan-07 23:37
membercalvinchang11-Jan-07 23:37 
GeneralRe: Didn't work in XP Pin
sawo.9-Oct-07 12:20
membersawo.9-Oct-07 12:20 
GeneralGood Drop-in NotifyIcon Replacement with Balloon Text Pin
Goalstate17-Aug-05 19:01
memberGoalstate17-Aug-05 19:01 
Questionwhat if i want to make it a library Pin
Secrets6-Aug-05 11:33
memberSecrets6-Aug-05 11:33 
QuestionProblems with API calls ? Pin
Brett Swift18-Jul-05 7:43
memberBrett Swift18-Jul-05 7:43 
GeneralDoing the same thing in VB.Net Pin
Eek16-Sep-04 1:54
memberEek16-Sep-04 1:54 
GeneralRe: Doing the same thing in VB.Net Pin
josephxxv7-Dec-04 10:59
memberjosephxxv7-Dec-04 10:59 
GeneralRe: Doing the same thing in VB.Net Pin
kajus23-Dec-04 6:44
memberkajus23-Dec-04 6:44 
GeneralRe: Doing the same thing in VB.Net Pin
josephxxv23-Dec-04 10:49
memberjosephxxv23-Dec-04 10:49 
GeneralRe: Doing the same thing in VB.Net Pin
kajus27-Dec-04 0:25
memberkajus27-Dec-04 0:25 
GeneralRe: Doing the same thing in VB.Net Pin
josephxxv29-Dec-04 7:55
memberjosephxxv29-Dec-04 7:55 
GeneralRe: Doing the same thing in VB.Net Pin
Sven Rutten30-Jan-05 2:24
memberSven Rutten30-Jan-05 2:24 
GeneralRe: Doing the same thing in VB.Net Pin
Sven Rutten30-Jan-05 2:05
memberSven Rutten30-Jan-05 2:05 
GeneralRe: Doing the same thing in VB.Net Pin
Sven Rutten30-Jan-05 2:08
memberSven Rutten30-Jan-05 2:08 
GeneralEvents Pin
shaled30-Dec-03 1:10
membershaled30-Dec-03 1:10 
GeneralOne problem I had to overcome. Pin
Deadnick25-Aug-03 9:04
sussDeadnick25-Aug-03 9:04 
GeneralRe: One problem I had to overcome. Pin
Eek16-Sep-04 15:39
memberEek16-Sep-04 15:39 
GeneralRe: One problem I had to overcome. Pin
Shimms27-Dec-04 18:16
memberShimms27-Dec-04 18:16 
GeneralRe: One problem I had to overcome. Pin
rnan6-Jun-06 5:50
memberrnan6-Jun-06 5:50 
GeneralRe: One problem I had to overcome. Pin
rnan6-Jun-06 6:01
memberrnan6-Jun-06 6:01 
GeneralRe: One problem I had to overcome. Pin
prn_mouseman23-Dec-04 5:41
memberprn_mouseman23-Dec-04 5:41 
Generalwin2000 service pack 4 Pin
Subba Rao6-Jul-03 21:39
memberSubba Rao6-Jul-03 21:39 
GeneralCode does not work with VS 2003 Pin
hazem abolrous1-Jun-03 20:58
memberhazem abolrous1-Jun-03 20:58 
GeneralRe: Code does not work with VS 2003 Pin
RRRRyan12-May-04 9:31
memberRRRRyan12-May-04 9:31 
GeneralRe: Code does not work with VS 2003 Pin
lozanet6-Apr-05 8:44
memberlozanet6-Apr-05 8:44 
GeneralDisplaying balloon tooltip for hidden icon Pin
SLiDeR6-Nov-02 8:19
memberSLiDeR6-Nov-02 8:19 
GeneralRe: Displaying balloon tooltip for hidden icon Pin
Jon Rista9-Dec-02 21:02
memberJon Rista9-Dec-02 21:02 
GeneralRe: Displaying balloon tooltip for hidden icon Pin
SLiDeR10-Dec-02 8:13
memberSLiDeR10-Dec-02 8:13 
GeneralRe: Displaying balloon tooltip for hidden icon Pin
Jon Rista13-Dec-02 8:57
memberJon Rista13-Dec-02 8:57 
GeneralRe: Displaying balloon tooltip for hidden icon Pin
Eek16-Sep-04 15:37
memberEek16-Sep-04 15:37 
GeneralRe: Displaying balloon tooltip for hidden icon Pin
Eek16-Sep-04 15:42
memberEek16-Sep-04 15:42 
Generalbetter way Pin
Neil Cawse31-Mar-02 14:48
memberNeil Cawse31-Mar-02 14:48 
GeneralRe: better way Pin
Joel Matthias1-Apr-02 5:14
memberJoel Matthias1-Apr-02 5:14 
GeneralRe: better way Pin
Andy Smith1-Apr-02 6:57
memberAndy Smith1-Apr-02 6:57 
GeneralRe: better way Pin
Joel Matthias1-Apr-02 8:37
memberJoel Matthias1-Apr-02 8:37 
GeneralRe: better way Pin
Tim Smith1-Apr-02 8:57
memberTim Smith1-Apr-02 8:57 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150731.1 | Last Updated 30 Mar 2002
Article Copyright 2002 by Joel Matthias
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid