现在的位置: 首页 > 综合 > 正文

一个封装的VC++应用程序托盘动态连接

2012年01月07日 ⁄ 综合 ⁄ 共 15645字 ⁄ 字号 评论关闭

 

一个封装的VC++应用程序托盘动态连接库

用VC++编写自己的应用程序托盘类,将与托盘相关的功能全部封装在一个DLL里面,我们选择的连接库类型为MFC扩展动态连接库,因为这个类需要继承MFC的CWnd类,编译后的名字为SanXiaTray.Dll。

这个类的内部调用了Shell_NotifyIcon(NIM_ADD,NOTIFYICONDATA*) API,需要传递两个参数,一个是动作,一个是OTIFYICONDATA数据结构,关于这个API这里就不详细解释了,请自己查看MSDN Library。

下面说说这个类要实现的功能:
1。创建静态托盘,在系统任务栏区域添加自定义托盘图标。
2。创建动画托盘(启动,停止动画,以及从某一个指定范围开始动画)
3。动态修改托盘图标提示文字
4。跟踪鼠标右击显示上下文菜单

SanXiaTray.Dll的.h源文件如下:
/*||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

#pragma once

#ifndef __SANXIATRAYLIB_H__
#define __SANXIATRAYLIB_H__

#ifdef _SANXIATRAYEXPORT
#define SANXIATRAYEXPORT_CLS _declspec(dllexport)
#else
#define SANXIATRAYEXPORT_CLS _declspec(dllimport)
#endif // (!_SANXIATRAYEXPORT)

#ifndef _SANXIATRAYEXPORT
#pragma comment(lib, "SanXiaTray.lib")
#endif // (!_SANXIATRAYEXPORT)

namespace SanXia
{
 namespace Components
 {

  /*
  **********************************************************************************************
  *Description:在系统任务栏区域添加自定义托盘图标
  *    支持动画效果,动画效果封装在SystemTray类内部.
  *      支持窗口隐藏以及同时在任务栏自动隐藏
  *    支持鼠标右键呼出上下文菜单
  *
  *Example Calling:
  *
  * 声明(.h源文件中):
  * static const UINT WM_NOTIFYMESSAGE = WM_USER+101; //自定义消息
  * static const UINT MAX_NOTIFYICON = 5 ; //最大图标数
  * SystemTray *m_pSystemTray ; //系统托盘类
  * HICON *m_pNotifyIcons ; //托盘区动画图标指针
  * CMenu *m_pMenu ; //托盘区右键菜单
  *
  * 消息映射(.h源文件中):
  * afx_msg LRESULT OnNotifyMessage(WPARAM,LPARAM);
  *
  * 初始化(.cpp文件中):
  * m_pTray = new SanXiaTrayLib();
  * m_pNotifyIcons = new HICON[MAX_NOTIFYICON] ;
  *
  * 开始调用(.cpp文件中):
  * m_pmTray->Create(this,IDI_ICON_NOTIFY_DEFAULT,WM_NOTIFYMESSAGE,CString("SanXia Notify Tray Icon Test"),m_pNotifyIcons,m_pMenu);
  * m_pTray->ShowWindow(FALSE,FALSE); //主窗体隐藏同时在任务栏也不可见
  *
  * 自定义消息接受函数:
  * LRESULT OnNotifyMessage(WPARAM wParam, LPARAM lParam)
  * {
  *  return m_pSystemTray->OnNotifyMessage(wParam,lParam) ; //重新给回调过去
  * }
  *
  * 定时器产生动画效果:
  * void OnTimer(UINT_PTR nIDEvent)
  * {
  *  m_pSystemTray->SetIcon(MAX_NOTIFYICON) ; //重置图标
  * }
  *Author:CHONGCHONG2008-天真的好蓝
  *MSN:chongchong2008@msn.com
  Dates:2007-04-10
  *LastModifiedData:2007-05-02
  **********************************************************************************************
  */
  
  static UINT m_nNotifyIconIndex ;
  class SANXIATRAYEXPORT_CLS SanXiaTrayLib:public CWnd
  {
   public :
    DECLARE_DYNAMIC(SanXiaTrayLib)

   private :
    BOOL m_bIsAnimation ; //当前是否是动画图标

    UINT m_uId ; //任务栏区NotifyIcon的Id
    UINT m_uMessage ; //自定义的消息

    LPCTSTR m_lpszToolTipText ; //鼠标放在NotifyIcon上的提示文字
    HICON m_hIcon ; //默认静态图标
    HICON *m_pNotifyIcons ; //NotifyIcon指针,用来显示动画图标
    CMenu *m_pContextMenu ; //NotifyIcon的右键弹出菜单
    CWnd *m_pWnd ; //NotifyIcon的父窗体

    UINT_PTR m_nIDEvent ; //计时器的系统识别ID,方便删除时候使用

    NOTIFYICONDATA notifyData ; //NotifyData数据结构 

   public:
    SanXiaTrayLib();

    void Create( CWnd *pWnd, UINT uId , UINT uMessage ,LPCTSTR lpszToolTipText , HICON hIcon);
    void Create( CWnd *pWnd, UINT uId , UINT uMessage ,LPCTSTR lpszToolTipText , HICON *hIcon , CMenu *pContextMenu);

    void SetToolTipText(LPCTSTR lpszToolTipText);

    void SetIcon(HICON hIcon);
    void SetIcon(UINT uMaxNotifyIconIndex);
    void SetIcon(UINT uStartIconIndex,UINT uEndIconIndex);
    void RemoveIcon();

    BOOL IsAnimation();
    void ShowWindow( BOOL bIsShow = TRUE , BOOL bIsShowInTaskBar = TRUE , BOOL bIsDeleteIcon = FALSE );

    void StartTimer(UINT uId,UINT uTimer);
    void StopTimer();

    LRESULT OnNotifyMessage(WPARAM wParam,LPARAM lParam);

    virtual ~SanXiaTrayLib();

   private: 
    void NotifyIcon(); 
    
   public:
    DECLARE_MESSAGE_MAP()
  };

 }
}

#endif // (!__SANXIATRAYLIB_H__)

/*||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

 

 

SanXiaTray.Dll的.cpp实现文件如下:
/*||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

#include "stdafx.h"
#include "../Inc/SanXiaTrayLib.h"

namespace SanXia
{
 namespace Components
 {
  /*
  ***************************************************************************************
  *Description: SanXiaTrayLib动态创建实现声明宏*/
  ***************************************************************************************
  */
  IMPLEMENT_DYNAMIC(SanXiaTrayLib, CWnd)

  /*
  ***************************************************************************************
  *Description:构造函数
  ***************************************************************************************
  */
  SanXiaTrayLib::SanXiaTrayLib()
  {
   m_bIsAnimation = FALSE ;

   m_nNotifyIconIndex = 0 ;
   m_uId = 0 ;
   m_pWnd = NULL;
   m_lpszToolTipText = L"";
   m_hIcon = NULL;
   m_pNotifyIcons = NULL;
   m_pContextMenu = NULL;
   m_pWnd = NULL ;
   m_nIDEvent = NULL ;
  }

  /*
  ***************************************************************************************
  *Description:创建系统托盘图标重载一
  ***************************************************************************************
  */
  void SanXiaTrayLib::Create( CWnd *pWnd, UINT uId ,UINT uMessage ,LPCTSTR lpszToolTipText , HICON hIcon)
  {
   Create( pWnd, uId , uMessage ,lpszToolTipText , &hIcon , NULL);
  }

  /*
  ***************************************************************************************
  *Description:创建系统托盘图标重载二
  ***************************************************************************************
  */
  void SanXiaTrayLib::Create( CWnd *pWnd, UINT uId , UINT uMessage ,LPCTSTR lpszToolTipText , HICON *pNotifyIcons , CMenu *pContextMenu)
  {
   m_pWnd = pWnd;
   m_uId = uId ;
   m_uMessage = uMessage;
   m_lpszToolTipText = lpszToolTipText;
   m_hIcon = pNotifyIcons[0];
   m_pNotifyIcons = pNotifyIcons;
   m_pContextMenu = pContextMenu;

   NotifyIcon();
  }

  /*
  ***************************************************************************************
  *Description:NotifyIcon动画定时器启动
  ***************************************************************************************
  */
  void SanXiaTrayLib::StartTimer(UINT_PTR nIDEvent,UINT uElapse)
  {
   m_bIsAnimation = TRUE;
   m_nIDEvent = nIDEvent ;
   ::SetTimer(m_pWnd->m_hWnd,m_nIDEvent,uElapse,NULL);
  }

  /*
  ***************************************************************************************
  *Description:NotifyIcon动画定时器停止
  ***************************************************************************************
  */
  void SanXiaTrayLib::StopTimer()
  {   
   m_bIsAnimation = FALSE;
   ::KillTimer(m_pWnd->m_hWnd,m_nIDEvent);
  }

  /*
  ***************************************************************************************
  *Description:由ParentWindow回调的消息通知函数
  ***************************************************************************************
  */
  LRESULT SanXiaTrayLib::OnNotifyMessage(WPARAM wParam,LPARAM lParam)
  {
   UINT uIconID;//发出该消息的图标的ID
   UINT uMessage;//鼠标动作
   POINT point;
   uIconID =(UINT) wParam;
   uMessage =(UINT) lParam;

   if(uMessage==WM_RBUTTONDOWN)//如果是单击右键
   {
    GetCursorPos(&point);
    if(m_pContextMenu)
    {
     m_pContextMenu->GetSubMenu(0)->TrackPopupMenu(TPM_LEFTBUTTON,point.x,point.y,AfxGetMainWnd());
    }
   }
   else if(uMessage==WM_LBUTTONDBLCLK)
   {
     ShowWindow(TRUE,FALSE);
   }
   return NULL ;
  }

  /*
  ***************************************************************************************
  *Description:设置任务栏区的NotifyIcon的提示文字
  ***************************************************************************************
  */
  void SanXiaTrayLib::SetToolTipText(LPCTSTR lpszToolTipText)
  {
   lstrcpy(notifyData.szTip,lpszToolTipText);
   Shell_NotifyIcon(NIM_MODIFY,&notifyData);
  }

  /*
  ***************************************************************************************
  *Description:设置任务栏区的NotifyIcon
  ***************************************************************************************
  */
  void SanXiaTrayLib::SetIcon(HICON hIcon)
  {
   m_hIcon = hIcon ;
   notifyData.hIcon=m_hIcon;
   Shell_NotifyIcon(NIM_MODIFY,&notifyData);
  }

  /*
  ***************************************************************************************
  *Description:动画显示除默认NotifyIcon以外所有的NotifyIcon
  ***************************************************************************************
  */
  void SanXiaTrayLib::SetIcon(UINT uMaxNotifyIconIndex)
  {
   if(m_nNotifyIconIndex>uMaxNotifyIconIndex)
   {
    m_nNotifyIconIndex=1;//跳过默认静态NotifyIcon
   }
   SetIcon(m_pNotifyIcons[m_nNotifyIconIndex++]) ; //动画显示NotifyIcon
  }

  /*
  ***************************************************************************************
  *Description:动画显示一定范围内的NotifyIcon
  ***************************************************************************************
  */
  void SanXiaTrayLib::SetIcon(UINT uStartIconIndex,UINT uEndIconIndex)
  {
   if(m_nNotifyIconIndex>uEndIconIndex)
   {
    m_nNotifyIconIndex=uStartIconIndex;
   }
   SetIcon(m_pNotifyIcons[m_nNotifyIconIndex++]) ; //动画显示NotifyIcon
  }

  /*
  ***************************************************************************************
  *Description:从任务栏区移除NotifyIcon图标
  ***************************************************************************************
  */
  void SanXiaTrayLib::RemoveIcon()
  {
   Shell_NotifyIcon(NIM_DELETE,&notifyData);
  }

  /*
  ***************************************************************************************
  *Description:判断当前状态是否是动态托盘
  ***************************************************************************************
  */
  BOOL SanXiaTrayLib::IsAnimation()
  {
   return m_bIsAnimation;
  }

  /*
  ***************************************************************************************
  *Description:显示或者隐藏窗体以及是否同时在任务栏中也隐藏
  ***************************************************************************************
  */
  void SanXiaTrayLib::ShowWindow( BOOL isShowWindow , BOOL isShowWindowInTaskBar , BOOL isRemoveIcon )
  {
   if(isRemoveIcon) //删除托盘
   {
    if(isShowWindow) //显示窗口
    {    
     if(isShowWindowInTaskBar) //在任务栏显示
     {
      m_pWnd->ModifyStyleEx(WS_EX_TOOLWINDOW,0);//在TaskBar显示
     }
     else
     {
      m_pWnd->ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);//在TaskBar隐藏
     }
      m_pWnd->ShowWindow(SW_SHOW) ; //显示窗体     
    }
    else
    {
     if(isShowWindowInTaskBar)
     {
      m_pWnd->ModifyStyleEx(WS_EX_TOOLWINDOW,0);//在TaskBar显示
     }
     else
     {
      m_pWnd->ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);//在TaskBar隐藏
     }
     m_pWnd->ShowWindow(SW_HIDE) ; //隐藏窗口
    }
    RemoveIcon(); 
   }
   else
   {  
    if(isShowWindow)
    {
     if(isShowWindowInTaskBar)
     {
      m_pWnd->ModifyStyleEx(WS_EX_TOOLWINDOW,0);//在TaskBar显示
     }
     else
     {
      m_pWnd->ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);//在TaskBar隐藏
     }

     m_pWnd->ShowWindow(SW_SHOW) ; //显示窗体

    }
    else
    {
     m_pWnd->ShowWindow(SW_HIDE) ; //隐藏窗口
    }

   }   
  }

  /*
  ***************************************************************************************
  *Description:设置NotifyIcon图标
  ***************************************************************************************
  */
  void SanXiaTrayLib::NotifyIcon()
  {
   notifyData.cbSize=sizeof(NOTIFYICONDATA);
   notifyData.hWnd = m_pWnd->m_hWnd;
   notifyData.uID = m_uId;
   notifyData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
   notifyData.uCallbackMessage = m_uMessage;
   notifyData.hIcon = m_hIcon ;
   lstrcpy(notifyData.szTip,m_lpszToolTipText);
   Shell_NotifyIcon(NIM_ADD,&notifyData);
  }

  /*
  ***************************************************************************************
  *Description:析构函数
  ***************************************************************************************
  */
  SanXiaTrayLib::~SanXiaTrayLib()
  {
   if(m_bIsAnimation) //如果当前是动画托盘
   {
    StopTimer();//清除定时器
   }

   if(m_hIcon)
   {
    ::DestroyIcon(m_hIcon);
   }

   if(m_pNotifyIcons)
   {
    delete [] m_pNotifyIcons ;
   }

   if(m_pContextMenu)
   {
    delete m_pContextMenu;
    m_pContextMenu = NULL ;
   }

   if(m_pWnd)
   {
    delete m_pWnd;
   }
  }

  /*
  ***************************************************************************************
  *Description: SystemTray消息映射宏
  ***************************************************************************************
  */
  BEGIN_MESSAGE_MAP(SanXiaTrayLib, CWnd)
  END_MESSAGE_MAP()

 }
}

/*||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

 

下面以一个对话框应用程序CSanXiaTrayTestDlg为例,简单阐述如何使用SanXiaTray.Dll托盘动态库

1.在VisualStudion解决方案管理器中点鼠标右键,选择属性,会显示CSanXiaTrayTestDlg应用程序属性页,导航到连接器->命令行->附加选项,在里面输入Lib文件路径:../debug/SanXiaTray.Lib

2.在CSanXiaTrayTestDlg.h源文件里加入:
 #include "SanXiaTray.h" //包含SanXiaTray.Dll的头文件
 using namespace SanXia::Components ; //引入SanXiaTray.dll的命名空间

3.定义自定义消息:
 const UINT wm_nNotityMessage = RegisterWindowMessage(L"NotityMessage") ; //注册自定义消息
 const UINT MAX_NOTIFYICON = 5 ; //最大托盘图标数

4.然后加入以下声名:
 SanXiaTrayLib *m_pTray ; //SanXiaTray对象指针
 CMenu *m_pMenu ; //托盘区右键菜单
 HICON *m_pNotifyIcons;//托盘区动画图标指针数组

5.消息映射
 afx_msg LRESULT OnNotifyMessage(WPARAM,LPARAM) ; //自定义消息映射
 afx_msg void OnTimer(UINT_PTR nIDEvent) ; //计时器消息映射

 afx_msg void OnLButtonDown(UINT nFlags , CPoint point) ; //窗体鼠标消息映射
 afx_msg void OnFileShow() ; //显示窗体
 afx_msg void OnFileAnimationTray() ; //启动动画托盘
 afx_msg void OnFileAnimationStop() ; //停止动画托盘
 afx_msg void OnFileExit() ; //退出

接下来在你的.cpp文件的构造函数中加入:
 CSanXiaTrayTestDlg::CSanXiaTrayTestDlg(CWnd* pParent /*=NULL*/)
  : CDialog(CSanXiaTrayTestDlg::IDD, pParent)
 {
  m_pTray = new SanXiaTrayLib(); //系统托盘类分配内存
  m_pMenu = new CMenu() ; //上下文菜单 

  m_pNotifyIcons = new HICON[MAX_NOTIFYICON] ; //托盘区图标指针 
  m_pNotifyIcons[0] = AfxGetApp()->LoadIcon(IDI_ICON_NOTIFY_DEFAULT); //这个做为静态托盘图标
  m_pNotifyIcons[1] = AfxGetApp()->LoadIcon(IDI_ICON_NOTIFY_01);
  m_pNotifyIcons[2] = AfxGetApp()->LoadIcon(IDI_ICON_NOTIFY_02);
  m_pNotifyIcons[3] = AfxGetApp()->LoadIcon(IDI_ICON_NOTIFY_03);
  m_pNotifyIcons[4] = AfxGetApp()->LoadIcon(IDI_ICON_NOTIFY_04);

  m_pMenu->DestroyMenu();
  m_pMenu->LoadMenu(IDR_MENU1);
 }

 BOOL CSanXiaTrayTestDlg::OnInitDialog()
 {
  CDialog::OnInitDialog();

  m_pTray->Create(this,IDI_ICON_NOTIFY_DEFAULT,wm_nNotityMessage,L"SanXia Notify Tray Icon Test",m_pNotifyIcons,m_pMenu);
  m_pTray->ShowWindow(TRUE,FALSE);

  return TRUE; 
 }

消息映射:

 BEGIN_MESSAGE_MAP(CSanXiaTrayTestDlg, CDialog)
  ON_WM_PAINT()
  ON_WM_TIMER()
  ON_WM_QUERYDRAGICON()

  ON_WM_LBUTTONDOWN()
  ON_REGISTERED_MESSAGE(wm_nNotityMessage,OnNotifyMessage)

  ON_COMMAND(ID_FILE_EXIT, &CSanXiaTrayTestDlg::OnFileExit)
  ON_COMMAND(ID_FILE_ANIMATIONTRAY, &CSanXiaTrayTestDlg::OnFileAnimationTray)
  ON_COMMAND(ID_FILE_ANIMATIONSTOP, &CSanXiaTrayTestDlg::OnFileAnimationStop)
  ON_COMMAND(ID_FILE_SHOW, &CSanXiaTrayTestDlg::OnFileShow)

  //}}AFX_MSG_MAP
 END_MESSAGE_MAP()

响应自定义消息:
 LRESULT OnNotifyMessage(WPARAM wParam, LPARAM lParam)
 {
  return m_pTray->OnNotifyMessage(wParam,lParam);
 }

计时器:
 void OnTimer(UINT_PTR nIDEvent)
 { 
  CDialog::OnTimer(nIDEvent);
  m_pTray->SetIcon(MAX_NOTIFYICON);
 }

响应鼠标左键单击窗体:
 void CSanXiaTrayTestDlg::OnLButtonDown(UINT nFlags , CPoint point)
 {
  if(m_pTray)
  {
   m_pTray->ShowWindow(FALSE,FALSE);
   m_pTray->SetToolTipText(L"你点击了窗体把窗体隐藏了");
  } 
 }

响应鼠标右键菜单中的退出菜单条目
 void CSanXiaTrayTestDlg::OnFileExit()
  {
  if(MessageBox(L"你确认要退出吗?",L"SanXia",MB_OKCANCEL+MB_ICONINFORMATION) == IDOK )
  {
   if(m_pTray)
   {
   m_pTray->RemoveIcon();//关闭窗口时删除通知区图标,否则主程序窗体关闭后图标还在通知区。
   }
   PostMessage(WM_QUIT,0L,0L);
  }
  }

响应鼠标右键菜单中的动画菜单条目
 void CSanXiaTrayTestDlg::OnFileAnimationTray()
  {
  if(m_pTray)
  {
   if(!m_pTray->IsAnimation())
   {
    m_pTray->StartTimer(1,100); //计时ID,间隔毫秒数
    m_pTray->SetToolTipText(L"托盘处于动画模式了");
   }
  }
  }

响应鼠标右键菜单中的停止动画菜单条目
 void CSanXiaTrayTestDlg::OnFileAnimationStop()
  {
   if(m_pTray->IsAnimation())
   {
    m_pTray->StopTimer();
    m_pTray->SetToolTipText(L"托盘动画被停止了");
   }
  }

响应鼠标右键菜单中的显示窗体菜单条目
 void CSanXiaTrayTestDlg::OnFileShow()
 {
  if(m_pTray)
  {
   m_pTray->ShowWindow(TRUE,FALSE);
   m_pTray->SetToolTipText(L"窗体显示出来了");
  }
 }

析构函数
 CSanXiaTrayTestDlg::~ CSanXiaTrayTestDlg()
 {
  if(m_pTray)
  {
   m_pTray->RemoveIcon();//关闭窗口时删除通知区图标,否则主程序窗体关闭后图标还在通知区。
   delete m_pTray; //然后释放资源
   m_pTray=NULL;
  }

  if(m_pNotifyIcons)
  {
   DeleteObject(m_pNotifyIcons);
  }

  if(m_pMenu)
  {
   delete m_pMenu;
  }
 }

需要说明一下的是关于SanXiaTray.Dll里的void ShowWindow( BOOL bIsShow = TRUE , BOOL bIsShowInTaskBar = TRUE , BOOL bIsDeleteIcon = FALSE )方法参数德望一些说明

bIsShow:控制当前应用程序的窗体是否显示
bIsShowInTaskBar:控制当前应用程序的窗体是否显示在任务栏中
bIsDeleteIcon:是否删除掉任务栏区的托盘图标

大家可以自己传递不同的参数以满足自己需要的效果,如若有Bug,请朋友们指正。

效果图:

源代码下载:
http://files.cnblogs.com/CHONGCHONG2008/SanXiaTray.rar

 

 

抱歉!评论已关闭.