Win32程序添加托盘图标

⌚Time: 2023-01-19 23:10:12

👨‍💻Author: Jack Ge

notifyICONDATAA 结构

包含系统需要在通知区域中显示通知的信息。 由 Shell_NotifyIcon使用


typedef struct _NOTIFYICONDATAA {

  DWORD cbSize;

  HWND  hWnd;

  UINT  uID;

  UINT  uFlags;

  UINT  uCallbackMessage;

  HICON hIcon;

#if ...

  CHAR  szTip[64];

#else

  CHAR  szTip[128];

#endif

  DWORD dwState;

  DWORD dwStateMask;

  CHAR  szInfo[256];

  union {

    UINT uTimeout;

    UINT uVersion;

  } DUMMYUNIONNAME;

  CHAR  szInfoTitle[64];

  DWORD dwInfoFlags;

  GUID  guidItem;

  HICON hBalloonIcon;

} NOTIFYICONDATAA, *PNOTIFYICONDATAA;



成员

cbSize



类型:DWORD



此结构的大小(以字节为单位)。



hWnd



类型:HWND



一个窗口句柄,用于接收与通知区域中的图标关联的通知。



uID



类型: UINT



任务栏图标的应用程序定义标识符。 Shell 使用 (hWnd 加上 uID) 或 guidItem 来标识调用 Shell_NotifyIcon 时要操作的图标。 可以通过为每个不同的 uID 分配多个图标来关联单个 hWnd。 如果指定 guidItem ,则忽略 uID 。



uFlags



类型: UINT



指示结构中哪些其他成员包含有效数据的标志,或向工具提示提供有关其显示方式的其他信息。 此成员可以是以下值的组合:



NIF_MESSAGE (0x00000001)

0x00000001。 uCallbackMessage 成员有效。



NIF_ICON (0x00000002)

0x00000002。 hIcon 成员有效。



NIF_TIP (0x00000004)

0x00000004。 szTip 成员有效。



NIF_STATE (0x00000008)

0x00000008。 dwState 和 dwStateMask 成员有效。



NIF_INFO (0x00000010)

0x00000010。 显示气球通知。 szInfo、szInfoTitle、dwInfoFlags 和 uTimeout 成员有效。 请注意, uTimeout 仅在 Windows 2000 和 Windows XP 中有效。



若要显示气球通知,请指定NIF_INFO并在 szInfo 中提供文本。

若要删除气球通知,请指定NIF_INFO并通过 szInfo 提供空字符串。

若要添加通知区域图标而不显示通知,请不要设置NIF_INFO标志。

NIF_GUID (0x00000020)

0x00000020



Windows 7 及更高版本: guidItem 有效。

Windows Vista 和更早版本:保留。

NIF_REALTIME (0x00000040)

0x00000040。 Windows Vista 及更高版本。 如果气球通知无法立即显示,请放弃它。 将此标志用于表示实时信息的通知,如果稍后显示这些信息是毫无意义的或误导性的。 例如,一条消息指出“你的电话正在响铃”。仅当与NIF_INFO标志结合使用时,NIF_REALTIME才有意义。



NIF_SHOWTIP (0x00000080)

0x00000080。 Windows Vista 及更高版本。 使用标准工具提示。 通常, 当 uVersion 设置为NOTIFYICON_VERSION_4时,标准工具提示将被抑制,并且可以由应用程序绘制的弹出 UI 替换。 如果应用程序想要使用 NOTIFYICON_VERSION_4 显示标准工具提示,则可以指定NIF_SHOWTIP来指示仍应显示标准工具提示。



uCallbackMessage



类型: UINT



应用程序定义的消息标识符。 系统使用此标识符将通知消息发送到 hWnd 中标识的窗口。 当鼠标事件或悬停在图标的边界矩形中、使用键盘选择或激活图标或当这些操作发生在气球通知中时,将发送这些通知消息。



当 uVersion 成员为 0 或 NOTIFYICON_VERSION时,消息的 wParam 参数包含发生事件的任务栏图标的标识符。 此标识符的长度可以为 32 位。 lParam 参数保存与事件关联的鼠标或键盘消息。 例如,当指针移动到任务栏图标上时, lParam 设置为 WM_MOUSEMOVE。



当 uVersion 成员NOTIFYICON_VERSION_4时,应用程序会继续通过 uCallbackMessage 成员以应用程序定义消息的形式接收通知事件,但该消息的 lParam 和 wParam 参数的解释如下:



LOWORD (lParam) 包含通知事件,例如NIN_BALLOONSHOW、NIN_POPUPOPEN或WM_CONTEXTMENU。

HIWORD (lParam) 包含图标 ID。 图标 ID 限制为 16 位。

GET_X_LPARAM (wParam) 返回通知事件的 X 定位点坐标,NIN_POPUPOPEN、NIN_SELECT、NIN_KEYSELECT以及WM_MOUSEFIRST和WM_MOUSELAST之间的所有鼠标消息。 如果键盘生成了其中任一消息, 则 wParam 将设置为目标图标的左上角。 对于所有其他消息, wParam 未定义。

GET_Y_LPARAM (wParam) 返回为 X 定位点定义的通知事件和消息的 Y 定位点坐标。

hIcon



类型: HICON



要添加、修改或删除的图标的句柄。 Windows XP 及更高版本支持最多 32 BPP 的图标。



如果仅提供 16x16 像素图标,则会将其缩放为设置为高 dpi 值的系统中更大的大小。 这可能会导致无吸引力结果。 建议在资源文件中同时提供 16x16 像素图标和 32x32 图标。 使用 LoadIconMetric 确保正确加载并缩放正确的图标。 有关代码示例,请参阅“备注”。



szTip[64]



类型: TCHAR[64]



一个以 null 结尾的字符串,指定标准工具提示的文本。 最多可以有 64 个字符,包括终止 null 字符。



对于 Windows 2000 及更高版本, szTip 最多可以包含 128 个字符,包括终止 null 字符。



szTip[128]



类型: TCHAR[64]



一个以 null 结尾的字符串,指定标准工具提示的文本。 最多可以有 64 个字符,包括终止 null 字符。



对于 Windows 2000 及更高版本, szTip 最多可以包含 128 个字符,包括终止 null 字符。



dwState



类型:DWORD



Windows 2000 及更高版本。 图标的状态。 以下值之一或两个值:



NIS_HIDDEN (0x00000001)

0x00000001。 图标已隐藏。



NIS_SHAREDICON (0x00000002)

0x00000002。 图标资源在多个图标之间共享。



dwStateMask



类型:DWORD



Windows 2000 及更高版本。 一个值,该值指定检索或修改 dwState 成员的哪些位。 可能的值与 dwState 的值相同。 例如,将此成员设置为 NIS_HIDDEN 只会在忽略图标共享位时修改项的隐藏状态,而不考虑其值。



szInfo[256]



类型: TCHAR[256]



Windows 2000 及更高版本。 一个以 null 结尾的字符串,指定要在气球通知中显示的文本。 它最多可以包含 256 个字符,包括终止 null 字符,但应限制为 200 个字符(英语)以适应本地化。 若要从 UI 中删除气球通知,请删除带有NIM_DELETE) 的图标 (,或在 uFlags 中设置NIF_INFO标志,并将 szInfo 设置为空字符串。



DUMMYUNIONNAME



DUMMYUNIONNAME.uTimeout



类型: UINT



Windows 2000 及更高版本。



注意 此成员已弃用到 Windows Vista。 现在通知显示时间是基于系统辅助功能设置。

 

与 uVersion 联合。 通知的超时值(以毫秒为单位)。 系统强制实施最小和最大超时值。 uTimeout 中指定的值太大,设置为最大值。 太小的值默认为最小值。 系统最小和最大超时值当前分别设置为 10 秒和 30 秒。 有关 uTimeout 的进一步讨论,请参阅“备注”。

DUMMYUNIONNAME.uVersion



类型: UINT



Windows 2000 及更高版本。 与 uTimeout (的联合已弃用到 Windows Vista) 。 指定应使用哪个版本的 Shell 通知图标接口。 有关这些版本差异的详细信息,请参阅 Shell_NotifyIcon。 仅当使用 Shell_NotifyIcon 发送 NIM_SETVERSION 消息时,才使用此成员。



szInfoTitle[64]



类型: TCHAR[64]



Windows 2000 及更高版本。 一个 null 终止的字符串,指定气球通知的标题。 此标题显示在文本上方的较大字体中。 它最多可以有 64 个字符,包括终止 null 字符,但应限制为 48 个字符(英语)以适应本地化。



dwInfoFlags



类型:DWORD



Windows 2000 及更高版本。 可以设置为修改气球通知的行为和外观的标志。 图标放置在标题左侧。 如果 szInfoTitle 成员长度为零,则不显示图标。



NIIF_NONE (0x00000000)

0x00000000。 无图标。



NIIF_INFO (0x00000001)

0x00000001。 信息图标。



NIIF_WARNING (0x00000002)

0x00000002。 警告图标。



NIIF_ERROR (0x00000003)

0x00000003。 错误图标。



NIIF_USER (0x00000004)

0x00000004。 Windows XP SP2 及更高版本。



Windows XP:使用 hIcon 中标识的图标作为通知气球的标题图标。

Windows Vista 及更高版本:使用 hBalloonIcon 中标识的图标作为通知气球的标题图标。

NIIF_NOSOUND (0x00000010)

0x00000010。 Windows XP 及更高版本。 请勿播放关联的声音。 仅适用于通知。



NIIF_LARGE_ICON (0x00000020)

0x00000020。 Windows Vista 及更高版本。 图标的大型版本应用作通知图标。 这对应于SM_CXICON x SM_CYICON维度的图标。 如果未设置此标志,则使用维度SM_CXSMICON x SM_CYSMICON的图标。



此标志可用于所有 库存图标。

在 hIcon) 中使用较旧的自定义 (NIIF_USER图标的应用程序必须在托盘图标 (hIcon) 中提供新的 SM_CXICON x SM_CYICON 版本。 当这些图标显示在系统托盘或系统控制区域 (SCA) 时,这些图标会缩减。

具有 hBalloonIcon) 的新自定义图标 (NIIF_USER必须在提供的图标 (hBalloonIcon) 中提供SM_CXICON x SM_CYICON 版本。

NIIF_RESPECT_QUIET_TIME (0x00000080)

0x00000080。 Windows 7 及更高版本。 如果当前用户处于“安静时间”,则不显示气球通知,这是新用户首次登录其帐户后的第一小时。 在此期间,不应发送或显示大多数通知。 这样,用户就习惯于新的计算机系统,而不会分散注意力。 操作系统升级或干净安装后,每个用户也会出现安静时间。 在安静时间使用此标志发送的通知未排队;它只是被解开了。 如果应用程序当时仍然有效,则应用程序稍后可以重新发送通知。



由于应用程序无法预测它何时可能会遇到静默时间,因此我们建议此标志始终由任何表示保持安静时间的应用程序在适当的通知上设置。



在安静时间,某些通知仍应发送,因为用户应将其作为响应用户操作的反馈,例如,当他或她插入 USB 设备或打印文档时。



如果当前用户不在安静时间,则此标志不起作用。



NIIF_ICON_MASK (0x0000000F)

0x0000000F。 Windows XP 及更高版本。 保留。



guidItem



类型: GUID



Windows XP 及更高版本。



Windows 7 及更高版本:标识图标的已注册 GUID。 此值替代 uID ,是标识图标的建议方法。 必须在 uFlags 成员中设置NIF_GUID标志。

Windows XP 和 Windows Vista:保留;必须设置为 0

如果应用程序旨在同时在 Windows Vista 和 Windows 7 上运行,则必须检查 Windows 版本,并且仅在 Windows 7 或更高版本上指定非零 guidItem 。

如果在一次调用 Shell_NotifyIcon中使用 GUID 标识通知图标,则必须使用同一 GUID 来标识处理同一图标的任何后续 Shell_NotifyIcon 调用中的图标。



若要生成用于此成员的 GUID,请使用 GUID 生成工具,例如Guidgen.exe。



hBalloonIcon



类型: HICON



Windows Vista 及更高版本。 应用程序提供的自定义通知图标的句柄,该图标应独立于通知区域图标使用。 如果此成员为非 NULL,并且 dwInfoFlags 成员中设置了NIIF_USER标志,则此图标用作通知图标。 如果此成员为 NULL,则执行旧行为。

定义NOTIFYICONDATA结构体变量


NOTIFYICONDATA nID = {};

在程序目录添加一个图标app.ico,通过设置NOTIFYICONDATA结构体中成员信息,设置托盘图标的信息


#define WM_ON_TRAY WM_USER + 0 //自定义消息 点击托盘消息

...

//设置图标

nID.hIcon = (HICON)LoadImage(NULL, "app.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);

//鼠标悬停提示信息

strncpy(nID.szTip,"我是一个托盘图标", sizeof("我是一个托盘图标"));

//接收通知的窗体

nID.hWnd = hwnd;

nID.uID = 1;//任务栏图标的应用程序定义标识符

//指示其它成员有效标志位

nID.uFlags = NIF_GUID | NIF_ICON | NIF_MESSAGE | NIF_TIP;

//事件标识符,当鼠标悬停或点击时会发送此消息

nID.uCallbackMessage = WM_ON_TRAY;

Shell_NotifyIcon函数


BOOL Shell_NotifyIconA(

  [in] DWORD            dwMessage,

  [in] PNOTIFYICONDATAA lpData

);

参数

[in] dwMessage



类型:DWORD



一个值,指定此函数要执行的操作。 可以具有以下一个值:



NIM_ADD (0x00000000)

0x00000000。 将图标添加到状态区域。 图标在 lpdata 指向的 NOTIFYICONDATA 结构中提供标识符,无论是通过它的 uID 还是 guidItem 成员。 此标识符用于后续调用 Shell_NotifyIcon 以对图标执行后续操作。



NIM_MODIFY (0x00000001)

0x00000001。 修改状态区域中的图标。 lpdata 指向的 NOTIFYICONDATA 结构使用最初分配给图标的 ID,将它添加到通知区域时 (NIM_ADD) 标识要修改的图标。



NIM_DELETE (0x00000002)

0x00000002。 从状态区域删除图标。 lpdata 指向的 NOTIFYICONDATA 结构在添加到通知区域时使用最初分配给图标的 ID, (NIM_ADD) 标识要删除的图标。



NIM_SETFOCUS (0x00000003)

0x00000003。 仅Shell32.dll版本 5.0 及更高版本。 将焦点返回到任务栏通知区域。 通知区域图标在完成 UI 操作后应使用此消息。 例如,如果图标显示快捷菜单,但用户按 ESC 将其取消,请使用 NIM_SETFOCUS 将焦点返回到通知区域。



NIM_SETVERSION (0x00000004)

0x00000004。 仅Shell32.dll版本 5.0 及更高版本。 指示通知区域根据 lpdata 指向的结构的 uVersion 成员中指定的版本号行事。 版本号指定识别哪些成员。



每次 (NIM_ADD) 添加通知区域图标时,都必须调用NIM_SETVERSION。 无需使用 NIM_MODIFY 调用它。 用户注销后,版本设置不会持久保存。



有关详细信息,请参见“备注”部分。



[in] lpData



类型: PNOTIFYICONDATA



指向 NOTIFYICONDATA 结构的指针。 结构的内容取决于 dwMessage 的值。 它可以定义一个图标以添加到通知区域,导致该图标显示通知,或标识要修改或删除的图标。



返回值

类型: BOOL



如果成功,则返回 TRUE ;否则返回 FALSE 。 如果 dwMessage 设置为NIM_SETVERSION,则函数在成功更改版本时返回 TRUE ;如果不支持所请求的版本,则返回 FALSE 。

通过Shell_NotifyIcon将消息发送到任务栏的状态区域,添加托盘图标


//添加托盘图标

Shell_NotifyIcon(NIM_ADD, &nID);

结果

如何实现托盘图标的点击响应?

程序中定义一个消息


#define WM_ON_TRAY WM_USER + 0 //自定义消息 点击托盘消息

并且将NOTIFYICONDATA 结构体中uCallbackMessage成员设置为WM_ON_TRAY


nID.hWnd = hwnd;

nID.uCallbackMessage = WM_ON_TRAY;

当鼠标悬浮、点击等事件发生,会向窗体hwnd发送WM_ON_TRAY这个消息,只需要在窗体过程函数中处理该消息就可以了

消息的 lParam 和 wParam 参数的解释如下:


LOWORD (lParam) 包含通知事件,例如NIN_BALLOONSHOW、NIN_POPUPOPEN或WM_CONTEXTMENU。

HIWORD (lParam) 包含图标 ID。 图标 ID 限制为 16 位。

GET_X_LPARAM (wParam) 返回通知事件的 X 定位点坐标,NIN_POPUPOPEN、NIN_SELECT、NIN_KEYSELECT以及WM_MOUSEFIRST和WM_MOUSELAST之间的所有鼠标消息。 如果键盘生成了其中任一消息, 则 wParam 将设置为目标图标的左上角。 对于所有其他消息, wParam 未定义。

GET_Y_LPARAM (wParam) 返回为 X 定位点定义的通知事件和消息的 Y 定位点坐标。

窗体消息处理,实现按键点击事件处理,右键弹出菜单


//定义菜单ID

#define ID_MENU_0 1000

#define ID_MENU_1 1001

...

    //窗体消息处理

    case WM_ON_TRAY://自定义的托盘图标消息

        {

            switch(LOWORD(lParam))//判断通知事件

            {

            case WM_MOUSEMOVE://鼠标在托盘区移动

                printf("鼠标在托盘悬停\n");

                break;

            case WM_LBUTTONDOWN://左键点击

                printf("鼠标左键点击了托盘\n");

                break;



            case WM_RBUTTONDOWN://右键点击

                {

                    //建立弹出菜单

                    HMENU hPopMenu = CreatePopupMenu();

                    AppendMenu(hPopMenu, MF_STRING, ID_MENU_0, "hello world");

                    AppendMenu(hPopMenu, MF_STRING, ID_MENU_1, "退出");

                    //获取点击时鼠标位置

                    POINT p;

                    GetCursorPos(&p);

                    //弹出菜单

                    TrackPopupMenu(hPopMenu,TPM_RIGHTBUTTON,p.x,p.y,0,hwnd,NULL);

                }

                break;

            }

        }

        return 0;

对于弹出菜单的点击响应,在窗体的WM_COMMAND消息中进行处理


case WM_COMMAND:

        switch(wParam){

        case ID_MENU_0://hello 菜单

            printf("hello world!\n");

            break;

        case ID_MENU_1://退出菜单

            //退出

            SendMessage(hwnd, WM_CLOSE, 0, 0);

            break;

        }

        return 0;

效果