前言:
这是在网上找到的一篇博客,内容链接已经失效,但还好能看到百度快照的内容,所以有了这篇搬运
原文地址http://blog.csdn.net/franzhong/article/details/6322886
作者 franzhong
程序都要实现系统托盘功能,最小化到托盘是不是很酷,像QQ等等软件
还有的程序只允许运行一个,再次运行时会提示已经运行,是不是很友好
下面就实现这两个功能:[思路来源与Visual C++实效编程280例]
一:实现实例唯一
托盘一般只用在类testApp中设置一个互斥对象就可以满足
首先在App类中添加一个成员变量HANDLE m_hMutex;并在构造中初始化m_hMutex = NULL;
在InitInstance()中把代码替换成如下代码就可达到目的
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
m_hMutex = ::CreateMutex(NULL, FALSE, _T("abc"));//创建互斥对象
//判断互斥量是否存在
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
AfxMessageBox("应用程序已经运行。");
return FALSE;
}
AfxEnableControlContainer();
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
CTestTrayDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
}
else if (nResponse == IDCANCEL)
{
}
return FALSE;
二:实现托盘功能
手盘功能比较麻烦,首先在Dlg中定义变量
NOTIFYICONDATA m_Nid;也初化为NULL
//OnInitDlg中添加
m_Nid.cbSize = sizeof(NOTIFYICONDATA);
m_Nid.hWnd = m_hWnd;
m_Nid.uID = 100;
m_Nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
m_Nid.uCallbackMessage = WM_NOTIFYICON;
m_Nid.hIcon = (HICON)LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 16, 16, NULL);
StrCpy(m_Nid.szTip, _T("TrayName"));
对话框上添加按纽IDC_TEST,双击添加事件改名叫OnTest添加如下代码
ShowWindow(SW_HIDE);
//在任务栏中添加图标
Shell_NotifyIcon(NIM_ADD, &m_Nid);
在头上定义
#define WM_NOTIFYICON WM_USER+1 定义一个常量,呆会映射到响应函数上
把下面代码与原消息映射比较添加
BEGIN_MESSAGE_MAP(CDemoDlg, CDialog)
//{{AFX_MSG_MAP(CDemoDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_TEST, OnTest)
ON_MESSAGE(WM_NOTIFYICON, OnNotifyIcon)//响应托盘点击响应函数
ON_COMMAND(ID_SHOW, OnShow)//显示
ON_COMMAND(ID_EXIT, OnExit)//退出
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//下面afx_msg知道添加在哪不,在.h的声明文件里,你会发现有类似这样的地方就添进去就行了(其实定义函数也一样,afx_msg只是让向导用的,对编译器来说没太大的意义,上下两步很重要,不然你会收到明明定义的却说没定义)
afx_msg void OnTest();
afx_msg void OnNotifyIcon(WPARAM wParam, LPARAM lParam);
afx_msg void OnShow();
afx_msg void OnExit();
三个小函数的实现
void CDemoDlg::OnTest() //点击界面按纽时触发
{ //隐藏窗口
ShowWindow(SW_HIDE);
//在任务栏中添加图标
Shell_NotifyIcon(NIM_ADD, &m_Nid);
}
void CDemoDlg::OnShow()//点击显示后显示
{
//删除任务栏中的图标
Shell_NotifyIcon(NIM_DELETE , &m_Nid);
//显示窗口
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
}
void CDemoDlg::OnExit()//点右下角退出后退出
{
//删除任务栏中的图标
Shell_NotifyIcon(NIM_DELETE, &m_Nid);
//关闭窗口
SendMessage(WM_CLOSE);
}
最后添加一个托盘响应函数
void CtestDlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam)//CtestDlg改成你相同的名字
{
if (wParam == 100) //初始化时已经把ID设为100了
{
if (lParam == WM_LBUTTONDBLCLK)
{
//删除任务栏中的图标
Shell_NotifyIcon(NIM_DELETE, &m_Nid);
//显示窗口
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
}
else if ((lParam == WM_LBUTTONDOWN) || (lParam == WM_RBUTTONDOWN))//左右键都能弹出菜单
{
//显示快捷子菜单
CMenu menu;
if (!menu.LoadMenu(IDR_MENU)) //去资源里添加个IDR_MENU
{ //添加两个项,显示,退出ID为ID_EXIT and ID_SHOW
return;
}
CPoint point;
GetCursorPos(&point);
SetForegroundWindow();
CMenu* pSubMenu = menu.GetSubMenu(0);
if (pSubMenu == NULL)
{
return;
}
pSubMenu->TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
point.x, point.y, this, NULL);
// PostMessage(WM_NULL, 0, 0); //这句空消息可发可不发
}
}
}