/*参考别人的做了细微修改*/
类似于QQ的托盘程序编写
1.首先我们新建一个MFC程序,在对话框Dlg类中添加一个NOTIFYICONDATA类型对象
NOTIFYICONDATA m_nid;
2.在stdafx.h头文件中定义一个自定义消息
#define WM_SYSTEMTRAY WM_USER+1001
3.在Dlg类中中定义一个线程函数
static DWORD WINAPI NotifyIconProc(LPVOID lpParameter);//呵呵,有人会问了这里的线程函数为什么是静态的呢??大家先思考一下!
4.在Dlg的OnInitDialog()代码中输入以下代码:
HICON m_hicon = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));//加载一个托盘图标
m_nid.cbSize = sizeof(NOTIFYICONDATA);
m_nid.hWnd = m_hWnd; //指定窗口句柄
m_nid.uID = IDR_MAINFRAME;
m_nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; //指定有效成员
m_nid.uCallbackMessage = WM_SYSTEMTRAY; //自定义消息
m_nid.hIcon = m_hicon; //指定托盘图标
wcscpy_s(m_nid.szTip, _T("我的托盘")); //添加气泡提示
::Shell_NotifyIcon(NIM_ADD, &m_nid); //在托盘区添加图标
HANDLE hNotifyTherad = CreateThread(NULL, 0, NotifyIconProc, (LPVOID)&m_nid, 0, NULL);//创建一个线程来更新托盘图标
CloseHandle(hNotifyTherad);
5.在线程里面处理托盘图标切换
DWORD WINAPI CMFCApplication1Dlg::NotifyIconProc(LPVOID lpParameter)
{
NOTIFYICONDATA *pnotifyicon = (NOTIFYICONDATA*)lpParameter;//把传递进来的指针转换
/先在工程里面调入几个图标
HICON m_hstateicon_1 = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));//加载4个图标
HICON m_hstateicon_2 = ::LoadIcon(AfxGetInstanceHandle(), NULL);//空图标
HICON m_hstateicon_3 = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
HICON m_hstateicon_4 = ::LoadIcon(AfxGetInstanceHandle(), NULL);
不断的切换托盘图标
while (true)
{
pnotifyicon->uFlags = NIF_ICON;
pnotifyicon->hIcon = m_hstateicon_1;
::Shell_NotifyIcon(NIM_MODIFY, pnotifyicon);
Sleep(400);//400ms切换一次
pnotifyicon->uFlags = NIF_ICON;
pnotifyicon->hIcon = m_hstateicon_2;
::Shell_NotifyIcon(NIM_MODIFY, pnotifyicon);
Sleep(400);//400ms切换一次
pnotifyicon->uFlags = NIF_ICON;
pnotifyicon->hIcon = m_hstateicon_3;
::Shell_NotifyIcon(NIM_MODIFY, pnotifyicon);
Sleep(400);//400ms切换一次
pnotifyicon->uFlags = NIF_ICON;
pnotifyicon->hIcon = m_hstateicon_4;
::Shell_NotifyIcon(NIM_MODIFY, pnotifyicon);
Sleep(400);//400ms切换一次
}
return 0;
}
6.处理自定义消息和实现托盘菜单(托盘的产生一般是在最小化的时候,有的程序一启动也产生托盘图标,看程序的需要)
首先我们重写一下WindowProc函数,然后在WindowProc函数里面处理我们的托盘消息:
LRESULT CMFCApplication1Dlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: 在此添加专用代码和/或调用基类
switch (message)
{
case WM_SYSCOMMAND:
if (wParam == SC_MINIMIZE)
{
CMFCApplication1Dlg *dlg = (CMFCApplication1Dlg*)AfxGetApp()->GetMainWnd();//获取窗口CWnd指针
HWND hwnd = dlg->m_hWnd;//获取h_hWnd指针
::ShowWindow(hwnd, 0);//隐藏界面
return TRUE;
}
if (wParam == SC_RESTORE)
{
}
break;
case WM_CLOSE:
Shell_NotifyIcon(NIM_DELETE, &m_nid);//关闭软件时卸载托盘图标
break;
case WM_SYSTEMTRAY:
{
if (wParam != IDR_MAINFRAME)
return 1;
switch (lParam)
{
case WM_RBUTTONUP://右键起来时弹出快捷菜单,这里只有一个"关闭"
{
CMenu menu;
LPPOINT lpoint = new tagPOINT;
::GetCursorPos(lpoint); // 得到鼠标位置
menu.CreatePopupMenu(); // 声明一个弹出式菜单
SetForegroundWindow();//如果点击弹出菜单的时候,菜单失去焦点让菜单自动关闭
menu.AppendMenu(MF_STRING, WM_DESTROY, _T("退出"));// 增加菜单项"关闭",点击则发送消息WM_DESTROY 给主窗口(已隐藏),将程序结束
//此类型的菜单需要自定义消息,做消息映射和相关的消息响应函数
menu.TrackPopupMenu(TPM_LEFTALIGN, lpoint->x, lpoint->y, this);// 确定弹出式菜单的位置
HMENU hmenu = menu.Detach();
menu.DestroyMenu();// 资源回收
delete lpoint;// 资源回收
break;
}
case WM_LBUTTONDBLCLK://双击左键的处理
{
this->ShowWindow(SW_SHOW);//简单的显示主窗口完事儿
break;
}
case WM_LBUTTONDOWN://单击左键的处理
{
this->ShowWindow(SW_SHOW);//简单的显示主窗口完事儿
break;
}
}
}
break;
}
return CDialogEx::WindowProc(message, wParam, lParam);
}
7.添加WM_DESTROY消息函数,为了响应menu.AppendMenu(MF_STRING, WM_DESTROY, _T("退出"));中的WM_DESTROY消息
void CMFCApplication1Dlg::OnDestroy()
{
CDialogEx::OnDestroy();
// TODO: 在此处添加消息处理程序代码
Shell_NotifyIcon(NIM_DELETE, &m_nid);//关闭软件时卸载托盘图标
}
别人写的
http://www.cnblogs.com/hudo/archive/2009/08/19/1549973.html
*****************************************欢迎提出BUG**********************************************