65.9K
CodeProject is changing. Read more.
Home

Shell_NotifyIconEx with Balloon Tooltip

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.07/5 (24 votes)

Sep 12, 2003

viewsIcon

83773

downloadIcon

2109

Balloon Tooltip NotifyIcon with SHELL32.dll

Sample Image - Shell_NotifyIconEx.gif

Introduction

the .net framework nofityicon can't support Balloon Tooltip, try use this, u can:

  • MS windows classical Balloon Tooltip, becase from System API, update follow System
  • multi-notifyicon
  • animation icon
  • callback of mouseclick
  • contextMenu support
  • and ... talk with my tooo bad english.

ClassBody

1) Const, STRONG by version 5

  #region API_Consts
  internal readonly int WM_NOTIFY_TRAY = 0x0400 + 2001;
  internal readonly int uID = 5000;
  // see shellapi.h
  private const int NIIF_NONE = 0x00;
  private const int NIIF_INFO = 0x01;
  private const int NIIF_WARNING = 0x02;
  private const int NIIF_ERROR = 0x03;
  private const int NIF_MESSAGE = 0x01;
  private const int NIF_ICON = 0x02;
  private const int NIF_TIP = 0x04;
  private const int NIF_STATE = 0x08;
  private const int NIF_INFO = 0x10;
  private const int NIM_ADD = 0x00;
  private const int NIM_MODIFY = 0x01;
  private const int NIM_DELETE = 0x02;
  private const int NIM_SETFOCUS = 0x03;
  private const int NIM_SETVERSION = 0x04;
  private const int NIS_HIDDEN = 0x01;
  private const int NIS_SHAREDICON = 0x02;
  private const int NOTIFYICON_OLDVERSION = 0x00;
  private const int NOTIFYICON_VERSION = 0x03;
  [DllImport("shell32.dll", EntryPoint="Shell_NotifyIcon")]
  private static extern bool Shell_NotifyIcon ( // o, this's master
   int dwMessage,
   ref NOTIFYICONDATA lpData
   );
   [StructLayout(LayoutKind.Sequential)]
   private struct NOTIFYICONDATA {
   internal int cbSize;
   internal IntPtr hwnd;
   internal int uID;
   internal int uFlags;
   internal int uCallbackMessage;
   internal IntPtr hIcon;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=0x80)]
   internal string szTip;
   internal int dwState;
   internal int dwStateMask;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=0xFF)]
   internal string szInfo;
   internal int uTimeoutAndVersion;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=0x40)]
   internal string szInfoTitle;
   internal int dwInfoFlags;
  }
  #endregion

2) Create new struct of NOTIFYICONDATA

/// <summary>
  /// new struct of NOTIFYICONDATA
  /// </summary>
  private NOTIFYICONDATA GetNOTIFYICONDATA(IntPtr iconHwnd, string sTip, string boxTitle, string boxText) {
   NOTIFYICONDATA nData = new NOTIFYICONDATA();

   nData.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(nData); // struct size
   nData.hwnd = formTmpHwnd; // WndProc form
   nData.uID = uID; // message WParam, for callback
   nData.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP|NIF_INFO; // Flags
   nData.uCallbackMessage = WM_NOTIFY_TRAY; // message ID, for call back
   nData.hIcon = iconHwnd; // icon handle, for animation icon if u need
   nData.uTimeoutAndVersion = 10 * 1000 | NOTIFYICON_VERSION; // "Balloon Tooltip" timeout
   nData.dwInfoFlags = NIIF_INFO; // info type Flag, u can try waring, error, info

   nData.szTip = sTip; // tooltip message
   nData.szInfoTitle = boxTitle; // "Balloon Tooltip" title
   nData.szInfo = boxText; // "Balloon Tooltip" body

   return nData;
  }
3) Check Shell32.dll Version >= 5
private int GetShell32VersionInfo() { // getversion of shell32
   FileInfo fi = new FileInfo(Path.Combine(System.Environment.SystemDirectory,"shell32.dll"));
   if (fi.Exists) {
    FileVersionInfo theVersion = FileVersionInfo.GetVersionInfo(fi.FullName);
    int i = theVersion.FileVersion.IndexOf('.');
    if (i > 0) {
     try {
      return int.Parse(theVersion.FileVersion.Substring(0,i));
     }
     catch{}
    }
   }
   return 0;
  }

4) methods

public int AddNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText) {
    ...
}
public int DelNotifyBox() {
    ...
}
// use this u can create "animation icon" or "Balloon Tooltip" again
public int ModiNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText) {
    ...
}

5) pop menu anywhere

  [DllImport("user32.dll", EntryPoint="TrackPopupMenu")]
  private static extern int TrackPopupMenu (
   IntPtr hMenu,
   int wFlags,
   int x,
   int y,
   int nReserved,
   IntPtr hwnd,
   ref RECT lprc
   );
  [StructLayout(LayoutKind.Sequential)]
   private struct RECT {
   internal int Left;
   internal int Top;
   internal int Right;
   internal int Bottom;
  }

6) process message from NotifyIcon

  protected override void WndProc(ref Message msg) {
   if (msg.Msg == servicesClass.WM_NOTIFY_TRAY) {
    if ((int)msg.WParam == servicesClass.uID) {
     System.Windows.Forms.MouseButtons mb = System.Windows.Forms.MouseButtons.None;
     if((int)msg.LParam == WM_LBUTTONDOWN) { // left click
      mb = System.Windows.Forms.MouseButtons.Left;
     }
     else if((int)msg.LParam == WM_MBUTTONDOWN) { // middle click 
      mb = System.Windows.Forms.MouseButtons.Middle;
     }
     else if((int)msg.LParam == WM_RBUTTONDOWN) { // right click
      if (servicesClass.contextMenuHwnd != IntPtr.Zero) { // if connect my menu exist.
       RECT r = new RECT();    
       r.Left = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Left;
       r.Right = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Right;
       r.Top = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Top;
       r.Bottom = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Right;
       TrackPopupMenu(	//popup the menu
        servicesClass.contextMenuHwnd,
        2,
        System.Windows.Forms.Cursor.Position.X,
        System.Windows.Forms.Cursor.Position.Y,
        0,
        servicesClass.formHwnd,
        ref r
        );
      }
      else { // else callback mousebuttons.right
       mb = System.Windows.Forms.MouseButtons.Right;
      }
     }
     if (mb != System.Windows.Forms.MouseButtons.None && servicesClass._delegateOfCallBack != null) {
      servicesClass._delegateOfCallBack(mb); // run delegate
      return;
     }
    }
   }
   base.WndProc(ref msg);
  }

Exemple

1) easy call

private void button3_Click(object sender, System.EventArgs e) {
   new ArLi.CommonPrj.Shell_NotifyIconEx().AddNotifyBox(this.Icon.Handle,this.Text,"hello","hello word!");
  }

2) use contextMenu with callback

private void GetPoc1(MouseButtons mb) { //delegate of callback
   if (mb == MouseButtons.Left) {
    MessageBox.Show("icon1");
   }
  }
  private ArLi.CommonPrj.Shell_NotifyIconEx o1 = new ArLi.CommonPrj.Shell_NotifyIconEx();
  private void button1_Click(object sender, System.EventArgs e) {
   o1.AddNotifyBox(this.Icon.Handle,this.Text,"icon1","click to start,click to startclick to start\rclick to start");
   o1.ConnectMyMenu(this.Handle,this.contextMenu1.Handle); // add mymenu
   o1._delegateOfCallBack = new ArLi.CommonPrj.Shell_NotifyIconEx.delegateOfCallBack(GetPoc1); //const callback
  }

3) version safe

if (! o1.VersionPass) { // if shell32.dll too old(ie 4.0 ?)
 //todo: use .net framework notifyicon
} 

reference