Windows 托盘区域显示图标 - xiaoheike

时间:2024-02-22 08:05:10

Windows 托盘区域显示图标

NOTIFYICONDATA structure

这个结构体包含了向通知区域(底部任务栏右下角区域,下面都称为托盘)显示的信息。需要使用函数Shell_NotifyIcon

结构体成员

 1 typedef struct _NOTIFYICONDATA {
 2   DWORD cbSize;
 3   HWND  hWnd;
 4   UINT  uID;
 5   UINT  uFlags;
 6   UINT  uCallbackMessage;
 7   HICON hIcon;
 8   TCHAR szTip[64];
 9   DWORD dwState;
10   DWORD dwStateMask;
11   TCHAR szInfo[256];
12   union {
13     UINT uTimeout;
14     UINT uVersion;
15   };
16   TCHAR szInfoTitle[64];
17   DWORD dwInfoFlags;
18   GUID  guidItem;
19   HICON hBalloonIcon;
20 } NOTIFYICONDATA, *PNOTIFYICONDATA;

结构体成员介绍

cbSize

Type: DWORD

结构体的大小,以bytes 为单位。(sizeof(NOTIFYICONDATA))

hWnd

Type: HWND

指向窗口的句柄用于获得任务栏区域关联的图标的消息。

uID

Type: UINT

显示在任务栏的图标的资源ID 号。The application-defined identifier of the taskbar icon. The Shell uses either (hWnd plus uID) or guidItem to identify which icon to operate on whenShell_NotifyIcon is invoked. You can have multiple icons associated with a single hWnd by assigning each a different uID. If guidItem is specified, uID is ignored.

uFlags

Type: UINT

这是个旗帜用于表明任务栏图标显示的提示信息包含在这个结构体或者提供额外的信息。这个成员变量可以是以下值的组合:

NIF_MESSAGE (0x00000001):成员变量uCallbackMessage 是有效的

NIF_ICON (0x00000002):成员变量hIcon 是有效的

NIF_TIP (0x00000004):成员变量szTip 是有效的

NIF_STATE (0x00000008):成员变量dwStatedwStateMask 是有效的

NIF_INFO (0x00000010):显示一个气泡通知。成员变量szInfoszInfoTitledwInfoFlagsuTimeout 是有效的。需要注意的是成员变量uTimeout 只有在Windows 2000 和 Windows XP系统下有效

  • 为了显示气泡通知需要指定NIF_INFO 标志并且气泡的文本信息在成员变量szInfo 中
  • 为了移除气泡通知需要指定NIF_INFO 标志并且通过成员变量szInfo  指定一个空的字符串
  • 只是为了在任务栏添加一个通知的图标而不显示通知不要设置NIF_INFO 标示

NIF_GUID (0x00000020)

  • Windows 7 and later: 成员变量 guidItem 有效
  • Windows Vista and earlier: 保留

NIF_REALTIME (0x00000040):Windows Vista and later 如果气泡通知不能够立即显示则丢弃它。使用这:个标志表示如果实时的信息延迟显示将是无意义或误导的。例如,一个信息“Your telephone is ringing. ” NIF_REALTIME 这个标志是有意义的只有当它联合NIF_INFO 标志。

NIF_SHOWTIP (0x00000080): Windows Vista and later 使用标准的工具提示。正常情况下,当uVersion 被设置为NOTIFYICON_VERSION_4,这个标准的工具提示将被application-drawn 和弹出UI取代。如果这个应用程序想要使用NOTIFYICON_VERSION_4 去展示标准工具信息,那么需要指定NIF_SHOWTIP

uCallbackMessage

Type: UINT

一个应用程序定义的消息标识(指向一个函数的地址)。系统使用这个标识去发送通知消息给hWnd句柄指定的窗口 。鼠标事件或鼠标在任务栏图标的矩形边框上徘徊或任务栏图标被选择或被键盘激活或这些动作触发气泡通知,这些通知消息将会被发送给窗口。当成员变量uVersion 是0 或NOTIFYICON_VERSION,当事件发生那么消息的参数wParam 会包含任务栏图标的ID,这个标识可以是32 bits 长。参数lParam 中保存与事件相关的鼠标或键盘的消息。例如,当这个指针在任务栏图标上移过,参数lParam 将被设置为WM_MOUSEMOVE

当成员变量uVersion 被设置为NOTIFYICON_VERSION_4,则成员变量uCallbackMessage 指向的函数将继续获得通知消息,但是参数 lParamwParam将会被改变为以下的值:

  • LOWORD(lParam) 包含通知事件,例如NIN_BALLOONSHOW, NIN_POPUPOPEN或 WM_CONTEXTMENU.
  • HIWORD(lParam) 包含图标的ID。图标ID 仅限于一个16 bits 的长度
  • GET_X_LPARAM(wParam) 返回通知事件NIN_POPUPOPEN, NIN_SELECT, NIN_KEYSELECT和所有的在WM_MOUSEFIRST 和 WM_MOUSELAST之间的鼠标消息的X 坐标。如果任何的这些消息是被键盘生成的那么wParam 被设为任务栏图标的左上角。对于其他的所有消息,wParam 没有被定义
  • GET_Y_LPARAM(wParam) 返回通知事件与消息的Y 坐标,定义与GET_X_LPARAM(wParam)相同

hIcon

Type: HICON

被添加或被修改或被删除的图标的句柄。Windows XP和之后的系统支持32 BPP的图标。

如果仅仅提供一个16x16 像素的图标,它将被系统缩放到一个高dpi 的值,这将导致不美观的结果。建议在你的资源文件中提供一个16x16 和一个32x32 的图标。使用LoadIconMetric 去确保图标被正确的加载与恰当的缩放。备注中有代码示例

szTip

Type: TCHAR[64]

一个空终止字符串文件的提示信息。包括结束符’\0’它最大能够包含64个字符。

对于Windows 2000 和之后的系统,szTip 包括结束符’\0’它最大能够包含128个字符

dwState

Type: DWORD

Windows 2000 and later. 图标的状态,可以以下值其中的一个或两个:

  • NIS_HIDDEN (0x00000001):图标被隐藏
  • NIS_SHAREDICON (0x00000002):图标资源在多图标中被共享

dwStateMask

Type: DWORD

Windows 2000 and later. 一个值指定成员变量dwState 是被修改还是检索,可能的值和dwState 是一样的。例如,设置此成员nis_hidden只能隐藏的项目状态,图标共享点被忽略不管它的值改性

szInfo

Type: TCHAR[256]

Windows 2000 and later. 一个空终止字符串指定气泡通知显示的文本包括终止符’\0’最大可以包含256个字符,但是如果用于容纳定位则应该限制在200个英文字符。如果想要移除气泡通知可以删除图标(使用NIM_DELETE)或者设置 uFlags 的的标志为NIF_INFO并且设置szInfo 为空字符串

uTimeout

Type: UINT

Windows 2000 and later.注意这个成员变量在Windows Vista 中是过时的。通知的显示时间是基于系统的可达性设置

uVersion 一起使用。对于通知超时的时间是以毫秒为单位的。系统增大最大与最小的超时时间的值。如果指定的值太大将会被设置为最大值,如果这个值太小则被设置为最小值。系统目前默认的最小值与最大值是10s 和30s。查看备注获得对uTimeout 的进一步了解

uVersion

Type: UINT

Windows 2000 and later.与uTimeout (在Windows Vista中是过时的)联合使用。它指定了使用的通知图标的接口。想要进一步了解不同版本的不同请看Shell_NotifyIcon。这个成员变量被使用当且公当使用Shell_NotifyIcon 发送一个NIM_SETVERSION 消息。

  • 0:在Windows 2000 之前将这个值设置为
  • NOTIFYICON_VERSION:使用Windows 2000 的行为。Windows 2000以之后的系统的应用程序可以使用这个值
  • NOTIFYICON_VERSION_4:使用当前的行为。Windows Vista 和之后的系统的应用程序可以使用这个值

szInfoTitle

Type: TCHAR[64]

Windows 2000 and later. 气泡通知的标题是一个空终止的字符串。这个标题将会以更大的字体在文本上显示。包括终止符’\0’最大能够有64个字符,但是如果用于容纳定位那么应该被限制为48个英文字母

dwInfoFlags

Type: DWORD

Windows 2000 and later.气泡通知显示方式的旗帜。图标在标题的左边显示。如果成员变量szInfoTitle 长度为0,那么图标将不会被显示

NIIF_NONE (0x00000000):无图标

NIIF_INFO (0x00000001):一个信息图标

NIIF_WARNING (0x00000002):一个警告图标

NIIF_ERROR (0x00000003):一个错误图标

NIIF_USER (0x00000004):Windows XP SP2 and later.

  • Windows XP: 使用句柄hIcon  指定的图标作为气泡通知标题的图标
  • Windows Vista and later: 使用hBalloonIcon  的图标标识作为气泡通知标题的图标

NIIF_NOSOUND (0x00000010): Windows XP and later.不会播放关联的声音。被设置仅仅用于通知

NIIF_LARGE_ICON (0x00000020):Windows Vista and later. 在版本的图标将被作为通知图标。这相当SM_CXICON x SM_CYICON 的尺寸。如果这个标志没有被设置,这个图标的尺寸XM_CXSMICON x SM_CYSMICON 将被使用

  • 这个标志可以与所有的stock icons 一起使用
  • 应用程序使用老的自定义图标(hIcon 指定的NIIF_USER)必须提供一个新的SM_CXICON x SM_CYICON 版本在托盘图标中(hIcon)。这些图标将被显示在系统的托盘或者系统的控制区(SCA)
  • 新的自定义图标(NIIF_USER with hBalloonIcon)必须提供一个SM_CXICON x SM_CYICON 的版本在提供的图标中(hBalloonIcon

NIIF_RESPECT_QUIET_TIME (0x00000080):Windows 7 and later. 不会显示气泡通知如果当前的使用者处于“quiet time”,也就是一个新用户第一次登录他(她)的账号的第一个小时,多数的通知将不会被发送或显示。这使新用户能够在不受打扰的情况下熟悉新的电脑系统 。当用户为系统更新或卸载时也会激活“quiet time”。不处于“quiet time”则通知将会被发送。驳回不显示是很简单的。应用程序之后能够重新发送通知如果这它仍然可用

因为一个应用程序能够预测什么时候进入“quiet time”所以我们建议这个标志在任何的应用程序中的恰当通知中被设置,为了新生“quiet time”

在“quiet time”期间,一个通知应该仍然被发送因为他们用户希望得到反馈,例如插入一个USB 设备或者打印一个文件

如果当前的用户不处于“quiet time”,则这个标志没有效果

NIIF_ICON_MASK (0x0000000F):Windows XP and later. 保留

guidItem

Type: GUID

Windows XP and later.

  • Windows 7 and later: 一个注册的GUID 指定一个图标。这个值重写uID 并且这是建议重定义图标的方法。在成员变量uFlags 必须设定NIF_GUID 标志
  • Windows XP and Windows Vista: 保留。必须被设置为0

如果你的应用程序打算在Windows 7 或者Windows Vista 上运行,那么检查系统的版本是非常必要的。如果系统是Windows 7 or later 则guidItem 必须为非零值。如果你识别出拥有GUID 的图标调用了函数Shell_NotifyIcon 那么你必须使用同样的GUID 去识别后来被函数Shell_NotifyIcon处理的图标

为了给这个成员函数产生一个使用的GUID,可以使用GUID 产生的工具,例如Guidgen.exe

hBalloonIcon

Type: HICON

Windows Vista and later. 应用程序提供的自定义图标的句柄在通知区域的图标应该被独立使用。如果这个成员变量是非空的并且在成员变量dwInfoFlags 中设置了NIIF_USER 标志,那么这个图标作为通知图标。如果这个成员变量是NULL,那么默认的行为将被实行

备注

在Windows User Experience Interaction Guidelines 的notification UI 和 content best practices模块查看更多关于 Notifications 的信息

如果成员变量uFlags 的值为 NIF_INFO,那么气泡样式的通知被使用。请查看Balloon tooltips 获得更加关于这些通知的讨论

在任务栏不能同时显示超过一个的气泡信息。如果应用程序的一个通知已经显示此时你试图再去显示另外一个通知,那么第二个通知将会排在第一个通知之后直到第一个通知显示结束才会显示第二个通知。如果是Windows Vista 之前的系统那么第二个通知将会在第一个通知被显示系统默认的最小时间长度之后显示而不管第一个通知被设定的时间是值的大小。如果用户不使用计算机,系统不算上这一次超时。

Windows 2000 and later 之后的系统将不支持这个结构体的多个成员变量,如果想要使用这些成员需要添加以下头文件:

 1 // Windows Vista and later:
 2 
 3 #define NTDDI_VERSION NTDDI_WIN2K
 4 
 5 #define NTDDI_VERSION NTDDI_WINXP
 6 
 7 #define NTDDI_VERSION NTDDI_VISTA
 8 
 9 // Windows XP and earlier:
10 
11 #define _WIN32_IE 0x0500

注意你必须使用这个结构体的大小去初始化这个结构体。如果你使用当前定义的结构体的大小,这个应用程序在早期的Shell32.dll 中很可能不会运行,因为它需要一个更小的结构体。你可以在早期的Shell32.dll 中运行你的应用程序通过定义恰当的版本号(请看Shell and Common Controls Versions)。但是如果你想要在最新的系统上运行很可能会导致问题

你可以让当前的应用程序与Shell32.dll 的版本兼容同时仍然使用当前的头文件通过设置NOTIFYICONDATA 结构体的大小。在你初始化结构体之前,使用DllGetVersion 去确定在你的系统上Shell32.dll 使用的是哪个版本并且使用以下的值初始化 cbSize

Shell32.dll Version

cbSize

6.0.6 or higher (Windows Vista and later)

sizeof(NOTIFYICONDATA)

6.0 (Windows XP)

NOTIFYICONDATA_V3_SIZE

5.0 (Windows 2000)

NOTIFYICONDATA_V2_SIZE

Versions lower than 5.0

NOTIFYICONDATA_V1_SIZE

表01

cbSize 使用以上表格的值将允许你的应用程序在早期的Shell32.dll版本中去使用NOTIFYICONDATA

以下的代码展示了通过版本检查使成员变量guidItem 能够在Windows Vista 和 Windows 7 上运行。在Windows 7 系统下将会返回TRUE。guiditem成员必须设置为0,除非该成员的返回TRUE。

注意:此代码是特定于Windows 7的版本号。可以预期的是,Windows和Windows server的未来版本将支持成员变量guiditem,同时这个代码也必须更新去识别之后的版本

 1 BOOL IsWin7OrLater()
 2 
 3 {
 4 
 5 // 初始化OSVERSIONINFOEX structure.
 6 
 7 OSVERSIONINFOEX osvi;
 8 
 9 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
10 
11 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
12 
13 osvi.dwMajorVersion = 6;
14 
15 osvi.dwMinorVersion = 1;
16 
17 // Initialize the condition mask.
18 
19 DWORDLONG dwlConditionMask = 0;
20 
21 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
22 
23 VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
24 
25 // 执行测试.
26 
27 return VerifyVersionInfo(&osvi,
28 
29 VER_MAJORVERSION | VER_MINORVERSION,
30 
31 dwlConditionMask);
32 
33 }

以下代码例子显示使用LoadIconMetric 加载高DPI的图标

 1 // 定义 NOTIFYICONDATA 细节.
 2 
 3 // 错误处理是这里省略简洁。不要在你的代码忽略它
 4 
 5 NOTIFYICONDATA nid = {};
 6 
 7 nid.cbSize = sizeof(nid);
 8 
 9 nid.hWnd = hWnd;
10 
11 nid.uFlags = NIF_ICON | NIF_TIP | NIF_GUID;
12 
13 // 注:这是一个例子,而不应只使用GUID.
14 
15 // 通常情况下,你应该使用一个GUID生成工具提供的值
16 
17 // 给guiditem赋值
18 
19 static const GUID myGUID =
20 
21 {0x23977b55, 0x10e0, 0x4041, {0xb8, 0x62, 0xb1, 0x95, 0x41, 0x96, 0x36, 0x69}};
22 
23 nid.guidItem = myGUID;
24 
25 // 以下文本将作为工具提示的显示文本
26 
27 StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), L"Test application");
28 
29 // 加载一个高DPI 的图标
30 
31 LoadIconMetric(hInst, MAKEINTRESOURCE(IDI_SMALL), LIM_SMALL, &(nid.hIcon));
32 
33 // 显示通知
34 
35 Shell_NotifyIcon(NIM_ADD, &nid) ? S_OK : E_FAIL;

故障处理

如果你使用成员变量guidItem 去识别你的图标但是这个图标不被看见或者调用Shell_NotifyIcon 失败,以下可能就是原因:

  1. Shell_NotifyIcon使用这个NIF_GUID 标志没有被设置。如果你识别出拥有GUID 的图标调用了函数Shell_NotifyIcon 那么你必须使用同样的GUID 去识别后来被函数Shell_NotifyIcon处理的图标
  2. 二进制文件中包含的图标被移除。这个二进制文件的路径包含了图标GUID 的注册信息并且这个注册信息是不能被改变的。与图标关联的设置被保存仅当文件路径和GUID是不变的。如果文件的路径必须被改变那么应用程序必须移除所有图标注册时添加的GUID 信息。一旦所有的信息被移除你就可以移动二进制文件到新的位置并且注册一个新的GUID。任何的与原始注册的GUID 关联的设置将会丢失

这也是一个并排安装时发生。当处理一个并排安装,新版本的应用程序需要更新的二进制文件的GUID。

注意:一种移动文件的唯一的例外发生是原有的移动二进制文件都由同一家公司签署的Authenticode。在这种情况下,设置是通过移动保留。

必要条件

Minimum supported client

Windows XP [desktop apps only]

Minimum supported server

Windows 2000 Server [desktop apps only]

Header

Shellapi.h

表 02

Shell_NotifyIcon function

发送一个消息到任务栏状态区域

函数原型

BOOL Shell_NotifyIcon(

_In_  DWORD dwMessage,

_In_  PNOTIFYICONDATA lpdata

);

参数说明

dwMessage [in]

Type: DWORD

指定这个函数所采取的行动的值。它可以是以下的值:

NIM_ADD (0x00000000):在托盘区域添加一个图标。这个图标在结构体NOTIFYICONDATA 中被指出

NIM_MODIFY (0x00000001):修改在托盘区域的图标。需要修改的图标在结构体NOTIFYICONDATA中被指出

NIM_DELETE (0x00000002):删除在托盘区域的图标。需要删除的图标在结构体NOTIFYICONDATA中被指出

NIM_SETFOCUS (0x00000003):Shell32.dll version 5.0 and later only。通知区域应该使用这个消息当它们完成对UI 的操作后。例如,当图标显示一个快捷菜单而用户使用ESC 键去取消它,那么我们应该使用NIM_SETFOCUS 将焦点返回给通知区域

NIM_SETVERSION (0x00000004): Shell32.dll version 5.0 and later only。命令通知区域要根据结构体NOTIFYICONDATA 中指出的版本号去执行命令。这个版本号必须是正确有效的

当通知区域的图标被添加(NIM_ADD)时NIM_SETVERSION每次都必须被调用。并不需要调用NIM_MOFIDY。一旦用户退出这个版本并不会保持。更多的细节请看备注部分

lpdata [in]

Type: PNOTIFYICONDATA

指向结构体 NOTIFYICONDATA 的指针。这个结构的内容取决于dwmessage 的值。它可以定义一个图标添加到通知区域,使图标显示一个通知,或识别一个图标修改或删除。

Return value

Type: BOOL

如果成功返回TRUE,否则返回 FALSE。如果dwmessage设置为NIM_SETVERSION且版本已成功更改,函数返回TRUE,如果请求的版本不支持则返回FALSE。

备注

Windows 2000 ( Shell32.dll version 5.0)系统下,如果你设置结构体 NOTIFYICONDATA 的成员变量 uVersion NOTIFYICON_VERSION_4 或者更高,那么Shell_NotifyIcon 的鼠标与键盘消息事件的处理与早些版本的Windows 是不同的。具体的不同如下所示:

  • 如果用户使用键盘的SPACEBAR 或者 ENTER 键去选择通知图标那么如果程序的版本是6.0,那么将会发送一个NIN_KEYSELECT 通知。早期版本将会发送WM_RBUTTONDOWNWM_RBUTTONUP 消息
  • 如果用户使用鼠标去选择通知图标而使用键盘的Enter 键去激活它,那么程序会发送NIN_SELECT 通知。早期版本将会发送WM_RBUTTONDOWNWM_RBUTTONUP 消息

对于Windows XP ( Shell32.dll version 6.0)系统,如果用户如果用户将鼠标指针放在其中一个气球通知相关的图标,shell发送以下信息:

  • NIN_BALLOONSHOW:气泡显示的发送(气泡被排序)
  • NIN_BALLOONHIDE:气泡消息的时候发送。例如,当一个图标被删除,这个消息不会被发送如果气泡被因为超时或者鼠标点击被驳回

在Windows 7系统上,NIN_BALLOONHIDE会被发送当被设置了NIIF_RESPECT_QUIET_TIME 标志的通知试图在“quiet time”(用户在新电脑上的第1个小时)时显示,在这种情况下,这个气泡将不会被使用。

  • NIN_BALLOONTIMEOUT:当气泡因为超时被驳回的时候发送
  • NIN_BALLOONUSERCLICK.:当气泡因为鼠标点击被驳回的时候

在Windows Vista (Shell32.dll version 6.0.6)上,如果用户将鼠标指针放在其中一个气球通知相关的图标,Windows Vista外壳还增加了以下信息:

  • NIN_POPUPOPEN:当用户在图标上悬浮表明一个丰富的弹出式UI应该被使用而不是文本工具提示,此时这个消息会被发送
  • NIN_POPUPCLOSE:当鼠标不在图标上悬浮表明弹出菜单应该被关闭,此时这个消息被发送

不管是什么操作系统的版本,你可以选择Shell 的运行方式通过调用函数Shell_NotifyIcon 并设置dwMessage 的值为NIM_SETVERSION。给结构体 NOTIFYICONDATA 的成员变量uVersion 合适的赋值来表明你希望使用Windows 2000, Windows Vista, 或者 pre-version 5.0 (Windows 95) 的操作

以上并没有商量自定义的Windows 消息。当调用函数Shell_NotifyIcon 并将dwMessage设定为NIM_ADD 那么自定义的消息将会被发送给NOTIFYICONDATA 结构体中的uCallbackMessage 指定的函数进行处理

在 Windows XP Service Pack 2 (SP2)系统上,一个自定义的图标能够在通知气泡上显示。这允许呼叫处理定制通知以外的信息,警告,以前可用的选项和错误,并区别于其他类型的用户的通知。

必要条件

Minimum supported client

Windows XP [desktop apps only]

Minimum supported server

Windows 2000 Server [desktop apps only]

Header

Shellapi.h

Library

Shell32.lib

DLL

Shell32.dll (version 4.0 or later)

Unicode and ANSI names

Shell_NotifyIconW (Unicode) and Shell_NotifyIconA (ANSI)

表 03

具体实例

在CStudentDlg.h 文件中添加如下代码:

 1 #define WM_SHOWTASKICON WM_USER + 4
 2 #define IDM_SHOW_WINDOW WM_USER + 5
 3 // CStudentDlg 对话框
 4 class CStudentDlg : public CDialogEx
 5 {
 6 protected:
 7     // 添加托盘消息响应
 8     afx_msg LRESULT OnShowTaskIcon(WPARAM wParam, LPARAM lParam);
 9     // 菜单项单击"显示"响应函数
10     afx_msg void OnShowDlg();
11 private:
12     // 添加一个类成员变量
13     NOTIFYICONDATA m_notifyIconData; // 托盘
14 }    

在CStudentDlg.cpp 的BEGIN_MESSAGE_MAP 下添加如下代码:

1 BEGIN_MESSAGE_MAP(CStudentDlg, CDialogEx)
2     ON_MESSAGE(WM_SHOWTASKICON, &CStudentDlg::OnShowTaskIcon)
3     ON_COMMAND(IDM_SHOW_WINDOW, &CStudentDlg::OnShowDlg)
4 END_MESSAGE_MAP()

在CStudentDlg.cpp 文件下添加如下函数:

 1 // 初始化NOTIFYICONDATA 结构体
 2 void CStudentDlg::InitPrompt(void)
 3 {
 4     // 设置托盘图标
 5     m_notifyIconData.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
 6     m_notifyIconData.hWnd = m_hWnd;
 7     // 你添加的图标的属性ID
 8     m_notifyIconData.uID = IDR_MAINFRAME;
 9     m_notifyIconData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
10     m_notifyIconData.uCallbackMessage = WM_SHOWTASKICON; // 自定义托盘菜单消息
11     // 加载资源icon
12     m_notifyIconData.hIcon = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
13     wcscpy(m_notifyIconData.szTip, _T("*****系统"));
14     Shell_NotifyIcon(NIM_ADD, &m_notifyIconData); // 在托盘区添加图标
15 }
16 
17 // 托盘菜单消息函数
18 LRESULT CStudentDlg::OnShowTaskIcon(WPARAM wParam, LPARAM lParam)
19 {
20     if(wParam != IDR_MAINFRAME) // 判断图标ID是否相符
21         return 1;
22     switch(lParam)
23     {
24     case WM_RBUTTONUP: 
25         {// 按鼠标右键
26             CPoint point;
27             GetCursorPos(&point);
28             CMenu menu;
29             menu.CreatePopupMenu();
30             menu.AppendMenu(MF_STRING, IDM_SHOW_WINDOW, _T("显示")); 
31             menu.AppendMenu(MF_STRING, WM_DESTROY, _T("退出"));
32             SetForegroundWindow();  // 解决菜单失去焦点不消失的BUG
33             menu.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this);
34             menu.DestroyMenu(); 
35         }
36         break;
37     case WM_LBUTTONDBLCLK: // 双击鼠标左键
38         OnShowDlg();
39         break;
40     }
41     return 0;
42 }
43 
44 // 托盘菜单"显示"响应函数
45 void CStudentDlg::OnShowDlg()
46 {
47     if(IsWindowVisible())
48         SendMessage(WM_SYSCOMMAND, SC_RESTORE, (LPARAM)m_hWnd);
49     else
50         ShowWindow(SW_SHOW);
51 }
52 
53 // 重写窗口消息处理函数,来拦截MFC窗口“最小化”按钮点击消息响应让程序最小化到托盘
54 LRESULT CStudentDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
55 {
56     // TODO: 在此添加专用代码和/或调用基类
57 
58     // 单击最小化按钮
59     if (message == WM_SYSCOMMAND && 
60         wParam == SC_MINIMIZE)
61     {
62         //AfxMessageBox(_T("是否最小化窗口到托盘"));
63         ShowWindow(SW_HIDE); // 隐藏主窗口
64         return 0;
65     }
66     return CDialog::DefWindowProc(message, wParam, lParam);
67 }

2015-04-21     17:02:48