SoFunction
Updated on 2025-03-06

C# Example code for WinForm calling Shell_NotifyIcon

public class InnerClass: Form
 {
  private Shell_NotifyIconEx servicesClass = null; // Accept the instance handle of the main CLASS  internal InnerClass(Shell_NotifyIconEx _servicesClass)
  {
   servicesClass = _servicesClass;
  }

  private const int WM_LBUTTONDOWN = 0x0201; // Left button  private const int WM_RBUTTONDOWN = 0x204; // Right click  private const int WM_MBUTTONDOWN = 0x207; // Medium key
  [DllImport("", EntryPoint = "TrackPopupMenu")]
  private static extern int TrackPopupMenu( // c# and seems to be no longer popup anywhere, just ask it to take action   IntPtr hMenu,
   int wFlags,
   int x,
   int y,
   int nReserved,
   IntPtr hwnd,
   ref RECT lprc
   );

  [StructLayout()]
  private struct RECT
  { // The structure used above indicates the range size available for the pop-up menu in the front (usually, it is used on the entire screen, so that friends who are engaged in games or video conversations can specify the range available for the menu)   internal int Left;
   internal int Top;
   internal int Right;
   internal int Bottom;
  }

  protected override void WndProc(ref Message msg)
  {
   if ( == servicesClass.WM_NOTIFY_TRAY)
   { // If the message matches    if ((int) == )
    { // And the WParam of the message matches     MouseButtons mb =;
     if ((int) == WM_LBUTTONDOWN)
     { //If the left button is clicked      mb =;
     }
     else if ((int) == WM_MBUTTONDOWN)
     { //Medium key      mb =;
     }
     else if ((int) == WM_RBUTTONDOWN)
     { //Right click      if ( != )
      { //If there is a definition of menu association       RECT r = new RECT();
        = ;
        =;
        =;
        =;

       TrackPopupMenu(
        ,
        2,
       ,
       ,
        0,
        ,
        ref r
        );
      }
      else
      { //If the menu association has not been defined       mb =;
      }
     }

     if (mb != && servicesClass._delegateOfCallBack != null)
     {
      servicesClass._delegateOfCallBack(mb); // Execute callback      return;
     }
    }
   }

   (ref msg);
  }
 }
public class Shell_NotifyIconEx
 {
  /// <summary>
  /// ArLi, last fix: 2003.9.12, reference:  Lib @ /arli/
  /// </summary>
  public static readonly  myVersion = new (1, 2); // Version Statement
  private readonly InnerClass formTmp = null; // This is very important and cannot be placed in the construct, because it must be the same lifetime as this instance to not be aborted message loop  private readonly IntPtr formTmpHwnd = ; // This is the handle of the previous line  private readonly bool VersionOk = false; // This is a property returned by VersionPass, which allows developers to detect the current machine (maybe on win95 or unknown platform version) suitable for this group. If it does not match, use .net's own notifyicon  private bool forgetDelNotifyBox = false; // This is a private flag, which allows developers to automatically clear the icon when the program exits.
  internal IntPtr formHwnd = ; // This is the main window handle that calls this component (the current instance is valid, multiple icons can not conflict)  internal IntPtr contextMenuHwnd = ; // This is the handle to the menu (the current instance is valid, multiple icons can not conflict)
  internal delegate void delegateOfCallBack( mb);
  internal delegateOfCallBack _delegateOfCallBack = null;

  public Shell_NotifyIconEx() // Construct  {
   WM_NOTIFY_TRAY += 1; // Message ID +1 to avoid multiple ICON message processing conflicts   uID += 1; // Same as above   formTmp = new InnerClass(this); // A message loop for new instance   formTmpHwnd = ; // New instance handle   VersionOk = this.GetShell32VersionInfo() >= 5; // Is the version suitable? Since the focus of this component is on bubble prompts, it requires 5.0 (ie 5.0) or above  }

  ~Shell_NotifyIconEx()
  { // Destruction   if (forgetDelNotifyBox) (); // Clean up icon if the developer forgets  }

  #region API_Consts
  internal readonly int WM_NOTIFY_TRAY = 0x0400 + 2001; //readonly means that only the payable value is constructed  internal readonly int uID = 5000;

  // Constant definition, if you have VC, you can refer to  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("", EntryPoint = "Shell_NotifyIcon")]
  private static extern bool Shell_NotifyIcon( // This is the protagonist   int dwMessage,
   ref NOTIFYICONDATA lpData
  );

  /// <summary>
  /// The purpose of this API is to consider using it when () is invalid, and the effect is very good  /// </summary>
  /// <param name="hwnd">, current form handle</param>  [DllImport("", EntryPoint = "SetForegroundWindow")]
  public static extern int SetForegroundWindow(
   IntPtr hwnd
  );

  [StructLayout()]
  private struct NOTIFYICONDATA
  { // The structure used by the protagonist   internal int cbSize;
   internal IntPtr hwnd;
   internal int uID;
   internal int uFlags;
   internal int uCallbackMessage;
   internal IntPtr hIcon;
   [MarshalAs(, SizeConst = 0x80)]
   internal string szTip;
   internal int dwState; // Here are the following highlights of 5.0   internal int dwStateMask;
   [MarshalAs(, SizeConst = 0xFF)]
   internal string szInfo;
   internal int uTimeoutAndVersion;
   [MarshalAs(, SizeConst = 0x40)]
   internal string szInfoTitle;
   internal int dwInfoFlags;
  }
  #endregion

  /// &lt;summary&gt;
  /// Build a structure  /// &lt;/summary&gt;
  private NOTIFYICONDATA GetNOTIFYICONDATA(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
  {
   NOTIFYICONDATA nData = new NOTIFYICONDATA();

    = (nData); // Size of the structure    = formTmpHwnd; // The form handle that handles the message loop can be moved into the main form    = uID; // WParam of message, used during callback    = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO; // Logo, which means that it is composed of messages, icons, prompts, and information    = WM_NOTIFY_TRAY; // Message ID, callback    = iconHwnd; // The handle of the icon, if you are interested, you can change it regularly to an animation ICON    = 10 * 1000 | NOTIFYICON_VERSION; // prompted timeout value (it will disappear automatically in a few seconds) and version    = NIIF_INFO; // Type flags, including INFO, WARNING, ERROR. Changing this value will affect the icon type of the bubble prompt box
    = sTip; //Icon prompt message    = boxTitle; // Title of the bubble prompt box    = boxText; // The prompt content of the bubble prompt box
   return nData; // That's it.  .  .  }

  private int GetShell32VersionInfo()
  { // Return to the version of shell32   FileInfo fi = new FileInfo((, "")); //The future platform shell32 is not available at present, and it will be modified if it encounters   if ()
   {
    FileVersionInfo theVersion = ();
    int i = ('.');
    if (i &gt; 0)
    {
     try
     {
      return ((0, i));
     }
     catch { }
    }
   }
   return 0;
  }

  /// &lt;summary&gt;
  /// Add a new icon  /// &lt;/summary&gt;
  /// <param name="iconHwnd">Icon handle</param>  /// <param name="sTip">Tip, 5.0 Maximum: 128 char</param>  /// <param name="boxTitle">Bubble title, maximum: 64 char</param>  /// <param name="boxText">Bubbles content, maximum: 256 char</param>  /// <returns>Success, Failure or Error (-1)</returns>  public int AddNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
  {
   if (!) return -1;

   NOTIFYICONDATA nData = GetNOTIFYICONDATA(iconHwnd, sTip, boxTitle, boxText);
   if (Shell_NotifyIcon(NIM_ADD, ref nData))
   {
     = true;
    return 1;
   }
   else
   {
    return 0;
   }
  }

  /// &lt;summary&gt;
  /// It's similar to add, no repeating  /// &lt;/summary&gt;
  public int DelNotifyBox()
  {
   if (!) return -1;

   NOTIFYICONDATA nData = GetNOTIFYICONDATA(, null, null, null);
   if (Shell_NotifyIcon(NIM_DELETE, ref nData))
   {
     = false;
    return 1;
   }
   else
   {
    return 0;
   }
  }

  public int ModiNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
  {
   if (!) return -1;

   NOTIFYICONDATA nData = GetNOTIFYICONDATA(iconHwnd, sTip, boxTitle, boxText);
   return Shell_NotifyIcon(NIM_MODIFY, ref nData) ? 1 : 0;
  }

  #region Optional Module //Here is an optional method  /// &lt;summary&gt;
  /// Connect an existing contextMenu  /// &lt;/summary&gt;
  /// <param name="_formHwnd">Form handle, used to process menu messages</param>  /// <param name="_contextMenuHwnd">Handle of menu</param>  public void ConnectMyMenu(IntPtr _formHwnd, IntPtr _contextMenuHwnd)
  {
   formHwnd = _formHwnd;
   contextMenuHwnd = _contextMenuHwnd;
  }

  /// &lt;summary&gt;
  /// Clear out the icon, delegation and formtmp resources immediately (it seems that there is no resource, considering that the secondary development link might be opened)  /// &lt;/summary&gt;
  public void Dispose()
  {
   _delegateOfCallBack = null;
   ();
  }

  /// &lt;summary&gt;
  /// Version is suitable  /// &lt;/summary&gt;
  public bool VersionPass
  {
   get
   {
    return ;
   }
  }
  #endregion
 }

Usage example:

 private void button2_Click (object sender,  e) {
  Shell_NotifyIconEx ().AddNotifyBox (, , "This is the title", "Click here to start and I will take you to the API world");
 }
private void GetPoc1 (MouseButtons mb) { // Callback processing if (mb == ) {
   ("From Menu 1");
 }
}
privateShell_NotifyIconEx o1 = newShell_NotifyIconEx (); //This is used outsideprivate void button1_Click (object sender,  e) {
  (, , "Men 1", "Click here to start and I will take you to the API world");
  (, this.); // Hang up the menu, optional o1._delegateOfCallBack = newShell_NotifyIconEx.delegateOfCallBack (GetPoc1); //Define callback}
private void GetPoc1(MouseButtons mb) { // Callback processing if (mb == ) {
 ("From Menu 1");
 }
 }
 private Shell_NotifyIconEx o1 = new Shell_NotifyIconEx(); //This is used outside private void button1_Click(object sender,  e) {
 (,,"Men 1","Click here to start and I will take you to the API world"); 
 (,this.); // Hang up the menu, optional o1._delegateOfCallBack = new Shell_NotifyIconEx.delegateOfCallBack(GetPoc1); //Define callback }
 private void GetPoc2(MouseButtons mb) {
 if (mb == ) {
 ("From Menu 2");
 }
 }
 private Shell_NotifyIconEx o2 = new Shell_NotifyIconEx(); //The second nofityicon is the same as above private void button2_Click(object sender,  e) {
 (,,"Men 2","Click here to start and I will take you to the API world"); 
 (,this.);
 o2._delegateOfCallBack = new Shell_NotifyIconEx.delegateOfCallBack(GetPoc2);
 }

The above is the detailed content of the sample code of C# WinForm calling Shell_NotifyIcon. For more information about C# WinForm calling Shell_NotifyIcon, please follow my other related articles!