在Windows 95任务条的右边有一个区域被称为通知区域,在其中可以显示一些应用程序的图标,用鼠标单击其中的图标一般能弹出应用程序的菜单,双击则能显示应用程序的完整窗口界面。时钟和音量控制是任务条通知区最常见的图标。任务条通知区编程可以通过Windows 95外壳编程接口函数Shell_NotifyIcon来实现,该函数在shellapi.h头文件中声明,其原型如下:
WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid);
dwMessage是对通知区图标进行操作的消息,主要有三中,如下表所示。
Shell_NotifyIcon使用的消息
消息说明
NIM_ADD
在任务条通知区插入一个图标
NIM_ DELETE
在任务条通知区删除一个图标
NIM_ MODIFY
对任务条通知区的图标进行修改
pnid传入一个NOTIFYICONDATA结构的指针。NOTIFYICONDATA结构声明及各域的意义表示如下:
typedef struct _NOTIFYICONDATA
{
// nid
DWORD cbSize; // NOTIFYICONDATA结构的字节数
HWND hWnd; // 处理通知区图标消息的窗口句柄
UINT uID; // 通知区图标的ID
UINT uFlags; // 表示下述三项是否有意义的标志
UINT uCallbackMessage; // 鼠标点击图标所发出消息的ID
HICON hIcon; // 图标句柄
char szTip[64]; // 当鼠标移到图标上时显示的提示信息
} NOTIFYICONDATA, *PNOTIFYICONDATA;
当用Shell_NotifyIcon在任务条通知区中放置一个图标时,同时也定义了一条回调消息,当用户用鼠标单击或双击图标时,NOTIFYICONDATA结构中指定的窗口句柄将接受到该消息。该消息的lParam参数将说明鼠标操作的方式。当应用程序退出时,应删除任务条中的图标。
下面的示例将说明如何使前述的椭圆窗口程序作为图标显示在任务条通知区中,当鼠标单击图标时,将弹出一个菜单,当双击时,椭圆窗口将完整显示。
1. 用资源编辑器在EllipseWnd项目的IDR_MENU_CONTEXT菜单中增加一个菜单项“在任务条中插入图标”(ID为IDM_INSERTICON)。
2. 用资源编辑器在EllipseWnd项目中增加一个菜单资源IDR_MENU_ICON ,在其中设定三个菜单项:
“激活椭圆窗口”(ID为IDM_ACTIVEWINDOW)
“关于...”(ID为IDM_ABOUTBOX)
“退出 Alt+F4”(ID为IDM_EXIT)
3. 在CEllipseWndDlg.h源文件中定义一个消息UM_ICONNOTIFY用以响应图标操作,并在CEllipseWndDlg类定义中增加响应该消息的处理函数OnIconNotify。用ClassWizard增加响应菜单命令IDM_INSERTICON和IDM_ACTIVEWINDOW的函数定义和模板。CEllipseWndDlg.h中的修改如下:
// 定义响应图标操作的消息
#define UM_ICONNOTIFY WM_USER+100
class CEllipseWndDlg : public CDialog
{
// Construction
public:
CEllipseWndDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CEllipseWndDlg)
enum { IDD = IDD_ELLIPSEWND_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CEllipseWndDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
CRgn m_rgnWnd;
// 处理图标的功能函数说明
BOOL AddIcon();
BOOL DeleteIcon();
// Generated message map functions
//{{AFX_MSG(CEllipseWndDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
afx_msg void OnAboutbox();
afx_msg void OnExit();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnInserticon();
afx_msg void OnActivewindow();
//}}AFX_MSG
// 图标消息的处理函数说明
afx_msg void OnIconNotify(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
4. 在CEllipseWndDlg.cpp中增加消息影射条目如下:
BEGIN_MESSAGE_MAP(CEllipseWndDlg, CDialog)
//{{AFX_MSG_MAP(CEllipseWndDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
ON_WM_CONTEXTMENU()
ON_COMMAND(IDM_ABOUTBOX, OnAboutbox)
ON_COMMAND(IDM_EXIT, OnExit)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_COMMAND(IDM_INSERTICON, OnInserticon)
ON_COMMAND(IDM_ACTIVEWINDOW, OnActivewindow)
//}}AFX_MSG_MAP
ON_MESSAGE(UM_ICONNOTIFY, OnIconNotify)
END_MESSAGE_MAP()
5. 在CEllipseWndDlg.cpp中增加如下的函数或代码:
void CEllipseWndDlg::OnDestroy()
{
CDialog::OnDestroy();
// remove main window tag
::RemoveProp(m_hWnd, AfxGetApp()->m_pszExeName);
// 应用程序退出时,删除任务条中图标
DeleteIcon();
}
BOOL CEllipseWndDlg::AddIcon()
{
// 在任务条中增加图标
NOTIFYICONDATA nid;
nid.cbSize = sizeof(nid);
nid.hWnd = m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
nid.uCallbackMessage = UM_ICONNOTIFY;
nid.hIcon = m_hIcon;
CString str = "椭圆窗口";
lstrcpyn(nid.szTip, (LPCSTR)str,
sizeof(nid.szTip) / sizeof(nid.szTip[0]));
return Shell_NotifyIcon(NIM_ADD, &nid);
}
BOOL CEllipseWndDlg::DeleteIcon()
{
// 删除任务条中的图标
NOTIFYICONDATA nid;
nid.cbSize = sizeof(nid);
nid.hWnd = m_hWnd;
nid.uID = IDR_MAINFRAME;
return Shell_NotifyIcon(NIM_DELETE, &nid);
}
// 响应图标消息处理函数
void CEllipseWndDlg::OnIconNotify(WPARAM wParam, LPARAM lParam)
{
switch ((UINT)lParam)
{
// 鼠标单击操作
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
{
// 装入图标操作菜单
CMenu menu;
menu.LoadMenu(IDR_MENU_ICON);
// 鼠标单击位置
CPoint point;
GetCursorPos(&point);
// 将背景窗口激活
SetForegroundWindow();
// 显示图标菜单
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
point.x, point.y, this, NULL);
// 增加一个额外消息,使菜单操作正确
PostMessage(WM_USER, 0, 0);
break;
}
// 鼠标双击操作
case WM_LBUTTONDBLCLK:
// 激活应用程序
OnActivewindow();
break;
}
}
// 插入图标到任务条通知区
void CEllipseWndDlg::OnInserticon()
{
// 先隐藏主窗
ShowWindow(SW_HIDE);
// 插入图标
AddIcon();
}
// 激活主窗
void CEllipseWndDlg::OnActivewindow()
{
// 先删除图标
DeleteIcon();
// 显示主窗
ShowWindow(SW_SHOW);
UpdateWindow();
}
WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid);
dwMessage是对通知区图标进行操作的消息,主要有三中,如下表所示。
Shell_NotifyIcon使用的消息
消息说明
NIM_ADD
在任务条通知区插入一个图标
NIM_ DELETE
在任务条通知区删除一个图标
NIM_ MODIFY
对任务条通知区的图标进行修改
pnid传入一个NOTIFYICONDATA结构的指针。NOTIFYICONDATA结构声明及各域的意义表示如下:
typedef struct _NOTIFYICONDATA
{
// nid
DWORD cbSize; // NOTIFYICONDATA结构的字节数
HWND hWnd; // 处理通知区图标消息的窗口句柄
UINT uID; // 通知区图标的ID
UINT uFlags; // 表示下述三项是否有意义的标志
UINT uCallbackMessage; // 鼠标点击图标所发出消息的ID
HICON hIcon; // 图标句柄
char szTip[64]; // 当鼠标移到图标上时显示的提示信息
} NOTIFYICONDATA, *PNOTIFYICONDATA;
当用Shell_NotifyIcon在任务条通知区中放置一个图标时,同时也定义了一条回调消息,当用户用鼠标单击或双击图标时,NOTIFYICONDATA结构中指定的窗口句柄将接受到该消息。该消息的lParam参数将说明鼠标操作的方式。当应用程序退出时,应删除任务条中的图标。
下面的示例将说明如何使前述的椭圆窗口程序作为图标显示在任务条通知区中,当鼠标单击图标时,将弹出一个菜单,当双击时,椭圆窗口将完整显示。
1. 用资源编辑器在EllipseWnd项目的IDR_MENU_CONTEXT菜单中增加一个菜单项“在任务条中插入图标”(ID为IDM_INSERTICON)。
2. 用资源编辑器在EllipseWnd项目中增加一个菜单资源IDR_MENU_ICON ,在其中设定三个菜单项:
“激活椭圆窗口”(ID为IDM_ACTIVEWINDOW)
“关于...”(ID为IDM_ABOUTBOX)
“退出 Alt+F4”(ID为IDM_EXIT)
3. 在CEllipseWndDlg.h源文件中定义一个消息UM_ICONNOTIFY用以响应图标操作,并在CEllipseWndDlg类定义中增加响应该消息的处理函数OnIconNotify。用ClassWizard增加响应菜单命令IDM_INSERTICON和IDM_ACTIVEWINDOW的函数定义和模板。CEllipseWndDlg.h中的修改如下:
// 定义响应图标操作的消息
#define UM_ICONNOTIFY WM_USER+100
class CEllipseWndDlg : public CDialog
{
// Construction
public:
CEllipseWndDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CEllipseWndDlg)
enum { IDD = IDD_ELLIPSEWND_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CEllipseWndDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
CRgn m_rgnWnd;
// 处理图标的功能函数说明
BOOL AddIcon();
BOOL DeleteIcon();
// Generated message map functions
//{{AFX_MSG(CEllipseWndDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
afx_msg void OnAboutbox();
afx_msg void OnExit();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnInserticon();
afx_msg void OnActivewindow();
//}}AFX_MSG
// 图标消息的处理函数说明
afx_msg void OnIconNotify(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
4. 在CEllipseWndDlg.cpp中增加消息影射条目如下:
BEGIN_MESSAGE_MAP(CEllipseWndDlg, CDialog)
//{{AFX_MSG_MAP(CEllipseWndDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
ON_WM_CONTEXTMENU()
ON_COMMAND(IDM_ABOUTBOX, OnAboutbox)
ON_COMMAND(IDM_EXIT, OnExit)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_COMMAND(IDM_INSERTICON, OnInserticon)
ON_COMMAND(IDM_ACTIVEWINDOW, OnActivewindow)
//}}AFX_MSG_MAP
ON_MESSAGE(UM_ICONNOTIFY, OnIconNotify)
END_MESSAGE_MAP()
5. 在CEllipseWndDlg.cpp中增加如下的函数或代码:
void CEllipseWndDlg::OnDestroy()
{
CDialog::OnDestroy();
// remove main window tag
::RemoveProp(m_hWnd, AfxGetApp()->m_pszExeName);
// 应用程序退出时,删除任务条中图标
DeleteIcon();
}
BOOL CEllipseWndDlg::AddIcon()
{
// 在任务条中增加图标
NOTIFYICONDATA nid;
nid.cbSize = sizeof(nid);
nid.hWnd = m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
nid.uCallbackMessage = UM_ICONNOTIFY;
nid.hIcon = m_hIcon;
CString str = "椭圆窗口";
lstrcpyn(nid.szTip, (LPCSTR)str,
sizeof(nid.szTip) / sizeof(nid.szTip[0]));
return Shell_NotifyIcon(NIM_ADD, &nid);
}
BOOL CEllipseWndDlg::DeleteIcon()
{
// 删除任务条中的图标
NOTIFYICONDATA nid;
nid.cbSize = sizeof(nid);
nid.hWnd = m_hWnd;
nid.uID = IDR_MAINFRAME;
return Shell_NotifyIcon(NIM_DELETE, &nid);
}
// 响应图标消息处理函数
void CEllipseWndDlg::OnIconNotify(WPARAM wParam, LPARAM lParam)
{
switch ((UINT)lParam)
{
// 鼠标单击操作
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
{
// 装入图标操作菜单
CMenu menu;
menu.LoadMenu(IDR_MENU_ICON);
// 鼠标单击位置
CPoint point;
GetCursorPos(&point);
// 将背景窗口激活
SetForegroundWindow();
// 显示图标菜单
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
point.x, point.y, this, NULL);
// 增加一个额外消息,使菜单操作正确
PostMessage(WM_USER, 0, 0);
break;
}
// 鼠标双击操作
case WM_LBUTTONDBLCLK:
// 激活应用程序
OnActivewindow();
break;
}
}
// 插入图标到任务条通知区
void CEllipseWndDlg::OnInserticon()
{
// 先隐藏主窗
ShowWindow(SW_HIDE);
// 插入图标
AddIcon();
}
// 激活主窗
void CEllipseWndDlg::OnActivewindow()
{
// 先删除图标
DeleteIcon();
// 显示主窗
ShowWindow(SW_SHOW);
UpdateWindow();
}