Win32 中 Shell_NotifyIcon 的基本用法






4.82/5 (50投票s)
2003年8月16日
3分钟阅读

481196

16306
在系统托盘上最小化启动您的应用程序。
引言
最近,我在浏览 CodeProject,寻找一个如何管理系统托盘图标的简单例子。 哎呀,对不起,我不应该称它们为托盘图标,正如 MSDN 文档如此仔细地指出
"任务栏通知区域有时会错误地称为托盘。"
尽管如此,我还是会坚持把铲子叫做铲子,并将“任务栏通知区域”称为“托盘”,“任务栏通知区域图标”称为“托盘图标”。 无论如何,回到正题,为什么还要写一篇关于托盘图标的文章呢?
- 我以前从未写过 Code Project 文章,这似乎很容易。
- 这不是另一个封装器,而是一个简单的直接的
Shell_NotifyIcon
示例,代码量最少。 - 我想要一个用纯 Win32 代码编写的例子。
- 我想解决我在其他关于该主题的文章中看到的一些常见问题。
基础知识
添加、修改、隐藏和删除托盘图标分两步完成
- 初始化
NOTIFYICONDATA
结构 - 调用
Shell_NotifyIcon
初始化 NOTIFYICONDATA 结构
// zero the structure - note: Some Windows funtions // require this but I can't be bothered to remember // which ones do and which ones don't. NOTIFYICONDATA niData; ZeroMemory(&niData,sizeof(NOTIFYICONDATA)); // get Shell32 version number and set the size of the // structure note: the MSDN documentation about this is // a little dubious(see bolow) and I'm not at all sure // if the code bellow is correct ULONGLONG ullVersion = GetDllVersion(_T("Shell32.dll")); if(ullVersion >= MAKEDLLVERULL(6,0,0,0)) niData.cbSize = sizeof(NOTIFYICONDATA); else if(ullVersion >= MAKEDLLVERULL(5,0,0,0)) niData.cbSize = NOTIFYICONDATA_V2_SIZE; else niData.cbSize = NOTIFYICONDATA_V1_SIZE; // the ID number can be any UINT you choose and will // be used to identify your icon in later calls to // Shell_NotifyIcon niData.uID = MY_TRAY_ICON_ID; // state which structure members are valid // here you can also choose the style of tooltip // window if any - specifying a balloon window: // NIF_INFO is a little more complicated niData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP; // load the icon note: you should destroy the icon // after the call to Shell_NotifyIcon niData.hIcon = (HICON)LoadImage( hInstance, MAKEINTRESOURCE(IDI_MY_ICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); // set the window you want to recieve event messages niData.hWnd = hWnd; // set the message to send // note: the message value should be in the // range of WM_APP through 0xBFFF niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE;
调用 Shell_NotifyIcon
// NIM_ADD adds a new tray icon
Shell_NotifyIcon(NIM_ADD,&niData);
隐形对话框
我看到很多帖子问如何最小化对话框应用程序到系统托盘开始,因此得名 Stealth Dialog。 这可以通过首先创建一个非模态对话框来实现
HWND hWnd = CreateDialog( hInstance, MAKEINTRESOURCE(MY_DIALOG), NULL, (DLGPROC)MyDlgProc );
然后使用上面显示的 Shell_NotifyIcon
将您的图标添加到托盘。 不要调用 ShowWindow
。
菜单和消息
来自托盘的消息将发送到由 NOTIFYICONDATA
struct
的 hWnd
成员指定的窗口,消息 ID 由 uCallbackMessage
成员指定(见上文)。 具体消息在 LPARAM
中。
INT_PTR CALLBACK MyDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case MY_TRAY_ICON_MESSAGE: switch(lParam) { case WM_LBUTTONDBLCLK: ShowWindow(hWnd, SW_RESTORE); break; case WM_RBUTTONDOWN: case WM_CONTEXTMENU: ShowContextMenu(hWnd); } break; case...
如果您实现上下文菜单,则通过 WM_COMMAND
接收消息,菜单项 ID 包含在 WPARAM
的低位字中。
case WM_COMMAND: switch (LOWORD(wParam)) { case MY_MENU_MSG1: ... break; case MY_MENU_MSG2: ...
重要提示:如果您实现了上下文菜单,那么在调用 TrackPopupMenu
之前,务必将窗口设置为前台,以确保菜单正确关闭。
void ShowContextMenu(HWND hWnd) { ... HMENU hMenu; // create or load a menu ... SetForegroundWindow(hWnd); TrackPopupMenu(hMenu, ...
清理
在您的应用程序关闭之前,您应该使用 NIM_DELETE
标志调用 Shell_NotifyIcon
来删除您的托盘图标。
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE,&niData);
注释
MSDN 文档中关于 NOTIFYICONDATA
结构的 cbSize
成员的说明
"您可以通过适当地设置 NOTIFYICONDATA
结构的大小,使您的应用程序与所有 Shell32.dll 版本兼容,同时仍然使用当前的头文件。在初始化该结构之前,使用 DllGetVersion
函数来确定系统上安装了哪个 Shell32.dll 版本。 如果它是 5.0 或更高版本,请使用以下代码初始化 cbSize
成员:
nid.cbSize = sizeof(NOTIFYICONDATA);
将 cbSize
设置为此值会启用所有 5.0 和 6.0 版本的增强功能。 对于早期版本,pre-6.0 结构的大小由 NOTIFYICONDATA_V2_SIZE
常量给出,pre-5.0 结构的大小由 NOTIFYICONDATA_V1_SIZE
常量给出。 使用以下代码初始化 cbSize
成员:
nid.cbSize = NOTIFYICONDATA_V2_SIZE;
将此值用于 cbSize
可以使您的应用程序使用具有早期 Shell32.dll 版本的 NOTIFYICONDATA
,尽管没有 6.0 版本的增强功能:"
现在也许是我的邻居的土耳其烟草,或者我只是没有抓住重点,但“5.0 或更高版本”和“pre-6.0”之间似乎存在重叠冲突。
无论如何,如果有人可以对此或其他他们想阐明的事情有所启发,请阐明。