首页 > 代码库 > 玩转VC++系统托盘程序(WIN8)

玩转VC++系统托盘程序(WIN8)



        WINDOWS系统托盘是一个特殊区域,通常在桌面的右下角,也就是任务栏的右边。系统常驻在托盘的程序有时钟,音量控制,输入法,网络状态等。第三方应用如QQ程序也是一个典型的托盘程序,当最小化时企鹅会乖乖的待在屏幕右下角等待主人的呼唤。

    系统托盘的方便之处在于,程序在暂时不用时,将它放到托盘里,随用随叫,不必将其关闭。而QQ在接收到消息后,也会在托盘中闪动提示,十分人性化。

那么如何用VC++来开发托盘程序呢?下面会用一个例子来玩转WINDOWS托盘程序。

首先,定义一下需要的功能。(需求确定)

  1. 程序最小化到托盘。

  2. 右键点击,显示一个菜单。

  3. 鼠标左键双击托盘图标,打开程序。

  4. 程序中点击一个按钮,改变托盘图标。

好了,就这么简单的Demo,下面看看如何实现。

其次,归纳一下用到的技术点。

  1. 托盘相关API

  2. MFC对鼠标操作消息的接收

先来说说托盘相关的APIMFC并没有直接提高便利的类来支持系统托盘编程,我们需要用到SHELLAPI中的Shell_NotifyIcon函数。原型为:

BOOL Shell_NotifyIcon(
    DWORD dwMessage,
    PNOTIFYICONDATA lpdata
);

函数很简单清晰,只有两个参数。参数一dwMessage用来指定托盘的动作,这是一个四字节的值。如下:

  1. NIM_ADD(0X00000000):添加一个系统托盘

  2. NIM_MODIFY(0X00000001):系统托盘的修改

  3. NIM_DELETE(0X00000002):系统托盘的删除

  4. NIM_SETFOCUS(0X00000003):令系统托盘获得焦点

  5. NIM_SETVERSION(0X00000004):系统托盘设置版本

参数二PNOTIFYICONDATA是专门为此服务的结构体。原型如下:

typedef struct _NOTIFYICONDATA {
  DWORD cbSize;//结构体的大小,单位是字节
  HWND  hWnd;//此托盘程序的句柄
  UINT  uID;// 系统为托盘区域每个图标分配的ID
  UINT  uFlags;//简单的说,就是一个标示
  UINT  uCallbackMessage;//回调消息。需要自定义一个消息,用来接收鼠标滑过或点击等消息。
  HICON hIcon;//图标
  TCHAR szTip[64];//提示文字的大小
  DWORD dwState;//图标的状态
  DWORD dwStateMask;//与上面类似
  TCHAR szInfo[256];//显示在气泡通知中的文本
  union {
    UINT uTimeout;
    UINT uVersion;
  };
  TCHAR szInfoTitle[64];//气泡通知的标题
  DWORD dwInfoFlags;//修改气泡通知相关的标示
  GUID  guidItem;//图标的GUID
  HICON hBalloonIcon;//气泡通知的图标
} NOTIFYICONDATA, *PNOTIFYICONDATA;

再来说说MFC中对鼠标操作信息的接收。

其实上面的调查结果一出,这个问题也就迎刃而解了。关键在uCallbackMessage。我们会自定义一个消息,比如就叫做WM_ICON_NOTIFY,当此托盘图标有鼠标滑过,悬停或点击,键盘操作时回调这个接收自定义消息的函数来处理。这一切都被安排好了,我们照着做就可以了。

第三、功能的实现

1.最小化到托盘

创建托盘的函数ToTray

	m_tnd.cbSize = sizeof(NOTIFYICONDATA);
	m_tnd.hWnd	 = pWnd->GetSafeHwnd();
	m_tnd.uID	 = uID;
	m_tnd.hIcon  = icon;
	m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
	m_tnd.uCallbackMessage = uCallbackMessage;
	strcpy (m_tnd.szTip, szToolTip);
	// Set the tray icon
	Shell_NotifyIcon(NIM_ADD, &m_tnd);

窗口最小化在OnSysCommand中判断:

    else if (nID == SC_MINIMIZE)
    {
        ToTray();
	ShowWindow(SW_HIDE);//隐藏窗口
}

23功能都可以在获得托盘事件函数处理:

LRESULT CTrayIcon::OnTrayNotification(UINT wParam, LONG lParam) 
{
	//Return quickly if its not for this tray icon
	if (wParam != m_tnd.uID)
		return 0L;

	// Clicking with right or left button brings up a context menu
	if (LOWORD(lParam) == WM_RBUTTONUP /*|| LOWORD(lParam) == WM_LBUTTONUP*/)
	{	
		//TODO:WHEN RIGHT CLICK,YOUR MENU SHOW HERE
	} 
	else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) 
	{
		//TODO:DOUBLE LEFT CLICK,SHOW MAIN WINDOW
	}

	return 1;
}

4.修改图标

这个就比较容易了,直接修改参数即可:

	m_tnd.uFlags = NIF_ICON;
	m_tnd.hIcon = hIcon;

	Shell_NotifyIcon(NIM_MODIFY, &m_tnd);

完整的例子请下载demo代码,借用了网上比较流行的封装好的TrayIcon类。

参考:

MSDN上的详细解释:http://msdn.microsoft.com/en-us/library/bb762159(VS.85).aspx

Vckbase:http://www.vckbase.com/index.php/cv/122