一个封装的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,¬ifyData);
}
/*
***************************************************************************************
*Description:设置任务栏区的NotifyIcon
***************************************************************************************
*/
void SanXiaTrayLib::SetIcon(HICON hIcon)
{
m_hIcon = hIcon ;
notifyData.hIcon=m_hIcon;
Shell_NotifyIcon(NIM_MODIFY,¬ifyData);
}
/*
***************************************************************************************
*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,¬ifyData);
}
/*
***************************************************************************************
*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,¬ifyData);
}
/*
***************************************************************************************
*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