1. 程式人生 > 程式設計 >C# WinForm呼叫Shell_NotifyIcon的示例程式碼

C# WinForm呼叫Shell_NotifyIcon的示例程式碼

public class InnerClass: Form
 {
  private Shell_NotifyIconEx servicesClass = null; // 接受主CLASS 的例項控制代碼
  internal InnerClass(Shell_NotifyIconEx _servicesClass)
  {
   servicesClass = _servicesClass;
  }

  private const int WM_LBUTTONDOWN = 0x0201; // 左鍵
  private const int WM_RBUTTONDOWN = 0x204; // 右鍵
  private const int WM_MBUTTONDOWN = 0x207; // 中鍵

  [DllImport("user32.dll",EntryPoint = "TrackPopupMenu")]
  private static extern int TrackPopupMenu( // c# 和vb.net 好象沒有了隨地popup 了,只要請它老人家出馬了
   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;
  }

  protected override void WndProc(ref Message msg)
  {
   if (msg.Msg == servicesClass.WM_NOTIFY_TRAY)
   { // 如果訊息相符
    if ((int)msg.WParam == servicesClass.uID)
    { // 並且訊息的WParam 相符
     MouseButtons mb =MouseButtons.None;
     if ((int)msg.LParam == WM_LBUTTONDOWN)
     { //如果點選的是左鍵
      mb =MouseButtons.Left;
     }
     else if ((int)msg.LParam == WM_MBUTTONDOWN)
     { //中鍵
      mb =MouseButtons.Middle;
     }
     else if ((int)msg.LParam == WM_RBUTTONDOWN)
     { //右鍵
      if (servicesClass.contextMenuHwnd != IntPtr.Zero)
      { //如果有定義過選單關聯
       RECT r = new RECT();
       r.Left = Screen.PrimaryScreen.WorkingArea.Left;
       r.Right =Screen.PrimaryScreen.WorkingArea.Right;
       r.Top =Screen.PrimaryScreen.WorkingArea.Top;
       r.Bottom =Screen.PrimaryScreen.WorkingArea.Right;

       TrackPopupMenu(
        servicesClass.contextMenuHwnd,2,Cursor.Position.X,Cursor.Position.Y,servicesClass.formHwnd,ref r
        );
      }
      else
      { //如果沒有定義過選單關聯
       mb =MouseButtons.Right;
      }
     }

     if (mb !=MouseButtons.None && servicesClass._delegateOfCallBack != null)
     {
      servicesClass._delegateOfCallBack(mb); // 執行回撥
      return;
     }
    }
   }

   base.WndProc(ref msg);
  }
 }
public class Shell_NotifyIconEx
 {
  /// <summary>
  /// ArLi,last fix: 2003.9.12,reference: ArLi.CommonPrj Lib @ http://zpcity.com/arli/
  /// </summary>
  public static readonly System.Version myVersion = new System.Version(1,2); //版本宣告

  private readonly InnerClass formTmp = null; // 這個很重要,不能放在構造裡,因為它必須和此例項同等生存期才不會被中止訊息迴圈
  private readonly IntPtr formTmpHwnd = IntPtr.Zero; // 這是上一行的控制代碼
  private readonly bool VersionOk = false; // 這是一個由VersionPass 返回的屬性,它允許開發者檢測當前機子的Shell32.dll(可能在win95 或未知平臺上版本) 合適此組,不符則用.net 自己的notifyicon
  private bool forgetDelNotifyBox = false; // 這是一個私有標誌,它允許開發者在程式退出時忘記呼叫DelNotifyBox 來清除圖示時會自動在析構裡清掉它。

  internal IntPtr formHwnd = IntPtr.Zero; // 這是呼叫此元件的主視窗控制代碼(當前例項有效,可多個icon 不衝突)
  internal IntPtr contextMenuHwnd = IntPtr.Zero; // 這是選單的控制代碼(當前例項有效,可多個icon 不衝突)

  internal delegate void delegateOfCallBack(System.Windows.Forms.MouseButtons mb);
  internal delegateOfCallBack _delegateOfCallBack = null;

  public Shell_NotifyIconEx() // 構造
  {
   WM_NOTIFY_TRAY += 1; // 訊息ID +1,避免多個ICON 訊息處理衝突
   uID += 1; // 同上
   formTmp = new InnerClass(this); // 新例項一個訊息迴圈
   formTmpHwnd = formTmp.Handle; // 新例項控制代碼
   VersionOk = this.GetShell32VersionInfo() >= 5; // 版本是否合適,此元件由於重點在氣泡提示,它要求Shell32.dll 5.0(ie 5.0) 以上
  }

  ~Shell_NotifyIconEx()
  { // 析構
   if (forgetDelNotifyBox) this.DelNotifyBox(); //如果開發者忘記則清理icon
  }

  #region API_Consts
  internal readonly int WM_NOTIFY_TRAY = 0x0400 + 2001; //readonly 表示只在構造可付值
  internal readonly int uID = 5000;

  // 常數定義,有VC 的可以參見 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( // 這位是主角
   int dwMessage,ref NOTIFYICONDATA lpData
  );

  /// <summary>
  /// 此API 的作用是當 this.focus() 無效時可以考慮使用,效果很好
  /// </summary>
  /// <param name="hwnd">this.Handle,當前窗體控制代碼</param>
  [DllImport("user32.dll",EntryPoint = "SetForegroundWindow")]
  public static extern int SetForegroundWindow(
   IntPtr hwnd
  );

  [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; // 這裡往下幾個是 5.0 的精華
   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

  /// <summary>
  /// 建一個結構
  /// </summary>
  private NOTIFYICONDATA GetNOTIFYICONDATA(IntPtr iconHwnd,string sTip,string boxTitle,string boxText)
  {
   NOTIFYICONDATA nData = new NOTIFYICONDATA();

   nData.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(nData); // 結構的大小
   nData.hwnd = formTmpHwnd; // 處理訊息迴圈的窗體控制代碼,可以移成主窗體
   nData.uID = uID; // 訊息的 WParam,回撥時用
   nData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO; // 標誌,表示由訊息、圖示、提示、資訊組成
   nData.uCallbackMessage = WM_NOTIFY_TRAY; // 訊息ID,回撥用
   nData.hIcon = iconHwnd; // 圖示的控制代碼,有興趣的話可以定時改變它變成動畫ICON
   nData.uTimeoutAndVersion = 10 * 1000 | NOTIFYICON_VERSION; // 提示的超時值(幾秒後自動消失)和版本
   nData.dwInfoFlags = NIIF_INFO; // 型別標誌,有INFO、WARNING、ERROR,更改此值將影響氣泡提示框的圖示型別

   nData.szTip = sTip; // 圖示的提示資訊
   nData.szInfoTitle = boxTitle; // 氣泡提示框的標題
   nData.szInfo = boxText; // 氣泡提示框的提示內容

   return nData; // 這個嘛。。。
  }

  private int GetShell32VersionInfo()
  { // 返回shell32 的版本
   FileInfo fi = new FileInfo(Path.Combine(System.Environment.SystemDirectory,"shell32.dll")); //將來的平臺shell32 放哪目前不得而知,碰到再改
   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;
  }

  /// <summary>
  /// 加一個新圖示
  /// </summary>
  /// <param name="iconHwnd">圖示控制代碼</param>
  /// <param name="sTip">提示,5.0 最大: 128 char</param>
  /// <param name="boxTitle">氣泡標題,最大: 64 char</param>
  /// <param name="boxText">氣泡內容,最大: 256 char</param>
  /// <returns>成功、失敗或錯誤(-1)</returns>
  public int AddNotifyBox(IntPtr iconHwnd,string boxText)
  {
   if (!this.VersionOk) return -1;

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

  /// <summary>
  /// 和add 差不多,不重複了
  /// </summary>
  public int DelNotifyBox()
  {
   if (!this.VersionOk) return -1;

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

  public int ModiNotifyBox(IntPtr iconHwnd,boxText);
   return Shell_NotifyIcon(NIM_MODIFY,ref nData) ? 1 : 0;
  }

  #region Optional Module //這裡是可選方法
  /// <summary>
  /// 連線一個已存在的 contextMenu
  /// </summary>
  /// <param name="_formHwnd">窗體控制代碼,用來處理選單的訊息</param>
  /// <param name="_contextMenuHwnd">選單的控制代碼</param>
  public void ConnectMyMenu(IntPtr _formHwnd,IntPtr _contextMenuHwnd)
  {
   formHwnd = _formHwnd;
   contextMenuHwnd = _contextMenuHwnd;
  }

  /// <summary>
  /// 立即清理掉圖示、委託和formtmp 資源(好象沒什麼資源,考慮到可能二次開發掛接就開了這個東東)
  /// </summary>
  public void Dispose()
  {
   _delegateOfCallBack = null;
   this.formTmp.Dispose();
  }

  /// <summary>
  /// 版本適合
  /// </summary>
  public bool VersionPass
  {
   get
   {
    return this.VersionOk;
   }
  }
  #endregion
 }

用法示例:

 private void button2_Click (object sender,System.EventArgs e) {
  Shell_NotifyIconEx ().AddNotifyBox (this.Icon.Handle,this.Text,"這是標題","單擊這裡開始,我將帶你暢遊API 世界");
 }
private void GetPoc1 (MouseButtons mb) { // 回撥處理
 if (mb == MouseButtons.Left) {
  MessageBox.Show ("來自選單1");
 }
}
privateShell_NotifyIconEx o1 = newShell_NotifyIconEx (); //這個放外面是用在 o.DelNotifyBox
private void button1_Click (object sender,System.EventArgs e) {
 o1.AddNotifyBox (this.Icon.Handle,"選單1","單擊這裡開始,我將帶你暢遊API 世界");
 o1.ConnectMyMenu (this.Handle,this.contextMenu1.Handle); // 掛上選單,可選
 o1._delegateOfCallBack = newShell_NotifyIconEx.delegateOfCallBack (GetPoc1); //定義回撥
}
private void GetPoc1(MouseButtons mb) { // 回撥處理
 if (mb == MouseButtons.Left) {
 MessageBox.Show("來自選單1");
 }
 }
 private Shell_NotifyIconEx o1 = new Shell_NotifyIconEx(); //這個放外面是用在 o.DelNotifyBox
 private void button1_Click(object sender,System.EventArgs e) {
 o1.AddNotifyBox(this.Icon.Handle,"單擊這裡開始,我將帶你暢遊API 世界"); 
 o1.ConnectMyMenu(this.Handle,this.contextMenu1.Handle); // 掛上選單,可選
 o1._delegateOfCallBack = new Shell_NotifyIconEx.delegateOfCallBack(GetPoc1); //定義回撥
 }
 private void GetPoc2(MouseButtons mb) {
 if (mb == MouseButtons.Left) {
 MessageBox.Show("來自選單2");
 }
 }
 private Shell_NotifyIconEx o2 = new Shell_NotifyIconEx(); //第二個nofityicon 和上面一樣
 private void button2_Click(object sender,System.EventArgs e) {
 o2.AddNotifyBox(this.Icon.Handle,"選單2","單擊這裡開始,我將帶你暢遊API 世界"); 
 o2.ConnectMyMenu(this.Handle,this.contextMenu2.Handle);
 o2._delegateOfCallBack = new Shell_NotifyIconEx.delegateOfCallBack(GetPoc2);
 }

以上就是C# WinForm呼叫Shell_NotifyIcon的示例程式碼的詳細內容,更多關於C# WinForm呼叫Shell_NotifyIcon的資料請關注我們其它相關文章!