最近突然想到一个很熟悉的功能,像QQ一样将窗体隐藏到任务栏状态条(taskbar status area),很多软件都有这样的功能,但是从来都没有亲自实现过,今天我就来亲自实现这样的功能。
主要涉及到的函数有:
WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA pnid
);
Sends a message to the system to add, modify, or delete an icon from the taskbar status area.
- Returns nonzero if successful, or zero otherwise.
-
dwMessage
-
Message value to send. This parameter can be one of these values:
NIM_ADD Adds an icon to the status area. 添加图标到任务栏的状态区 NIM_DELETE Deletes an icon from the status area. 从任务栏的状态区删除图标 NIM_MODIFY Modifies an icon in the status area. 修改任务栏状态区的图标
pnid
- Address of a NOTIFYICONDATA structure. The content of the structure depends on the value of dwMessage.
NOTIFYICONDATA结构体
typedef struct _NOTIFYICONDATA { DWORD cbSize; HWND hWnd; UINT uID; UINT uFlags; UINT uCallbackMessage; HICON hIcon; char szTip[64]; } NOTIFYICONDATA, *PNOTIFYICONDATA;
Contains information that the system needs to process taskbar status area messages.
-
cbSize
- Size of this structure, in bytes. 结构体的空间大小,之所以有这个变量的原因是为以后若增加结构体变量成员时保持代码尽可能小的修改。 hWnd
- Handle to the window that will receive notification messages associated with an icon in the taskbar status area. 任务栏状态区中图标所对应的窗口句柄,如果你的窗体是一个Dialog,那么应传入的参数是this->m_hWnd. uID
- Application-defined identifier of the taskbar icon. 图标的资源ID uFlags
-
Array of flags that indicate which of the other members contain valid data. This member can be a combination of the following:
NIF_ICON The hIcon member is valid. NIF_MESSAGE The uCallbackMessage member is valid. NIF_TIP The szTip member is valid. - 这个参数需要我们说明是这三种值之间是可以进行“或”运算的,如果进行了或运算例如NIF_ICON|NIF_MESSAGE|NIF_TIP
- 那么说明这个结构体中的变量hIcon,uCallbackMessage,szTip三个都是有效的变量,当然你也可以指定一个,或者其中的任意两个,这时候没有指定标签的那个变量在结构体中是无效的。 uCallbackMessage
- Application-defined message identifier. The system uses this identifier for notification messages that it sends to the window identified in hWnd. These notifications are sent when a mouse event occurs in the bounding rectangle of the icon.
- 这是一个自定义的消息ID值,比如你可以#define WM_CLICKICON 0x11,那么这里的nCAllbackMessage就是WM_CLICKICON了。 hIcon
- Handle to the icon to add, modify, or delete. 图标句柄,通过 HICON LoadIcon( HINSTANCE Instance , LPCTSTR lpIconName );函数获得,如果你的窗体是一个Cdialog类型的窗体,hInstance获得的方法是AfxGetInstanceHandle(),lpIconName通过MAKEINTERSOURCE(resourceID)获得。
szTip
- Tooltip text to display for the icon.
- 这是提示文字。
有了以上的说明之后我们基本上就可以实现最小化窗体到任务栏状态区中了。我将步骤简单描述如下:
1 ,建立一个CDialog类型的窗体,我们在vc 6.0中只要不断的click,click就OK了。
2 ,在这个窗体上放置一个button,我们也只需要简单的click就ok了
3 ,添加button的WM_LBUTTONDOWN事件,然后开始在这个事件中编辑代码了,如下
void CTestboxDlg::OnBtntonotify()
{
// TODO: Add your control notification handler code here
NOTIFYICONDATA nid;
nid.cbSize=sizeof(nid);
nid.hWnd=this->m_hWnd;
nid.uID=IDR_MAINFRAME;
nid.uFlags=NIF_TIP|NIF_ICON|NIF_MESSAGE;
nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
nid.uCallbackMessage=WM_CLICKICON;
strcpy(nid.szTip,_T("fyzh Notify/0"));
//when I move the mouse to the notification icon ,the hWnd will receive message WM_CLICKICON.
//But,How can i process message WM_CLICKICON.What does the parameters(WPARAM,LPARAM)means for ?
//WPARAM means for the IDR_MAINFRAME and the LPARAM means for mouse events(click ,move or double click...);
//Where can I get the document that explain it?
::Shell_NotifyIcon(NIM_ADD,&nid);
//hide the window so,you only can see the icon at task tar status area
ShowWindow(SW_HIDE);
}
当我们点击这个button的时候,在任务栏状态区就可以看到图标了,随着showWindow(SW_HIDE)的执行,窗口就被隐藏了。
4 ,接下来我们要处理的就是WM_CLICKICON消息了,这个消息是我们自定义的消息,MFC在进行消息循环的时候,通过DECLARE_MESAGE_MAP ,BEGIN_MESSAGE_MAP,END_MESSAGE_MAP这三个宏来实现,候俊杰出版的《深入浅出MFC》这本书中将MFC的消息循环阐释的很清楚了,这里我就不做赘述。
由于这里是我们自定消息,所以在对待这个消息的时候会与常规消息有些不一样。
在类的声明中声明一个消息处理函数,例如afx_msg void OnClickIcon(WPARAM wParam,LPARAM lParam);
ON_MESSAGE宏定义如下:
在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间,加入ON_MESSAGE(WM_CLICKICON,OnClickIcon)
#define ON_MESSAGE(message, memberFxn) /
{ message, 0, 0, 0, AfxSig_lwl, /
(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&memberFxn },
其中AfxSig_lwl, // 被注释为LRESULT (WPARAM, LPARAM),这也是我们的消息处理函数之所以要带两个参数WPARAM和LPARAM参数的原因了,那么这两个参数分别有什么含义呢?
5,void CTestboxDlg::OnClickIcon(WPARAM wParam,LPARAM lParam){
TRACE("%d,%d/n",wParam,lParam);
//WPARAM responds for ICON resource ID
//LPARAM responds for mouse events
if (wParam==IDR_MAINFRAME)
{
if (lParam==WM_LBUTTONDOWN)
{
TRACE("Left Button dwon.");
}
if (lParam==WM_RBUTTONDOWN)
{
TRACE("Right button down");
}
if (lParam==WM_LBUTTONDBLCLK)
{
ShowWindow(SW_NORMAL);
}
}
}
至于这两个参数WPARAM和LPARAM参数的含义只有查找windows的消息处理才知道了。
6,当你杀掉你的窗体的时候,要调用Shell_NotifyIcon()函数将任务栏状态区的图标删掉。
void CTestboxDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
NOTIFYICONDATA nid;
nid.cbSize=sizeof(nid);
nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
nid.uFlags=NIF_ICON;//这里我们只要指定一个参数有效就可以了,因为他即将被杀掉。
nid.uID=IDR_MAINFRAME;
nid.hWnd=this->m_hWnd;
Shell_NotifyIcon(NIM_DELETE,&nid);//这里第一个参数为NIM_DELETE
}
7,就这样你的程序就已经基本具备了最小化窗体到任务栏状态区的功能了。
以上是我的一点体会,如有不足,错误之处,还望高手指点。