[手工搬运][程序系统托盘与运行实例唯一实现]

来源:互联网 发布:上海安畅网络 编辑:程序博客网 时间:2024/06/05 08:58

前言:

这是在网上找到的一篇博客,内容链接已经失效,但还好能看到百度快照的内容,所以有了这篇搬运

原文地址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); //这句空消息可发可不发

}

}

}

0 0