一种确保系统托盘图标被删除的方法…保证

有没有办法保证您的系统托盘图标被删除?

要添加系统托盘图标,请执行以下操作:

Shell_NotifyIcon(NIM_ADD, &m_tnd); 

要删除系统托盘图标,请执行以下操作:

 Shell_NotifyIcon(NIM_DELETE, &m_tnd); 

我想知道的是:如果你的应用程序崩溃? 该图标保留在系统托盘中,直到您将鼠标hover为止。 有没有办法保证图标将被删除,即使应用程序崩溃? 我宁愿不使用结构化的exception处理由于各种原因。

我想处理的另一个案例是当这个进程被杀死,但不一定会崩溃。

Solutions Collecting From Web of "一种确保系统托盘图标被删除的方法…保证"

大多数程序员忘记检查的另一件事是如果浏览器重新启动/崩溃。 它很好,如果应用程序处理这个并重新创建自己的图标。

只需检查消息WM_TASKBARCREATED并重新创建图标。

你可以有一个单独的,更简单的(因此可能更强大)程序来监视你的应用程序。 这个程序实际上可以启动你的程序,然后监视过程。 是的,这是一个非常难看的解决方案。

我个人会使用向量异常处理程序。 是的,它基于SEH,但是你不必处理你可能需要放松的所有不同的堆栈。

TerminateProcess()必须更具破坏性。 你真的无法保护自己, 当它发生你的过程已经死了。 没有ore指令被处理,所以你的应用程序中的代码是没有关系的。

外部应用程序不会真的帮助,是吗? 它也可能会崩溃或被杀死。

嗯,你可以总是有一个外部的监视器进程调用SendMessage和WM_PAINT消息到系统托盘窗口(你必须根据窗口的类来做)。 这应该删除不再有效的图标。

您必须在应用程序崩溃时处理应用程序,否则图标不会消失。

检查这一点,如果它可以是任何帮助: http : //www.codeproject.com/KB/shell/ashsystray.aspx

您可以使用SetUnhandledExceptionFilter来捕获崩溃。 我通常使用它创建一个崩溃转储文件,以便可以调试崩溃,但没有理由不能像清除托盘图标那样进行一些简单的清理。

有很多方法可以确保调用Shell_NotifyIcon(NIM_DELETE, &m_tnd); 在C ++中用于应用程序crhashing的情况; 在你使用的NOTIFYICONDATA使用RAII封装将会完成这个工作,例如:

 struct NID { NID() : icon_data() { icon_data.cbSize = sizeof(icon_data); } ~NID() { Shell_NotifyIcon(NIM_DELETE, &icon_data); } void Show(HWND w) { icon_data.hWnd = w; Shell_NotifyIcon(NIM_ADD, &icon_data); } NOTIFYICONDATA icon_data; }; 

这是一个简化版本的包装,但它将说明主要思想:如果您在静态存储中创建一个NID实例,它将在WinMainmain调用之前初始化,并且它的析构函数将在程序清理中被调用,即使这清理是由于异常终止。

所以,我们可以这样使用这个包含在struct NID NOTIFYICONDATA资源:

 NID nid; // <--- automatic storage duration, cleared after WinMain return // even if it returns normal or abnormally int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { try { // GetMessage(&message, NULL, 0, 0) loop ... // ... // use nid.icon_data as you please } catch (...) { // something bad happened... } return 0; } 

上面的例子调用~NID()当程序终止时(在异常之后或关闭程序之后),析构函数将调用Shell_NotifyIcon(NIM_DELETE, &icon_data); 并从通知区域中删除图标; 这个代码覆盖了正常的终止和异常终止,你可以在NPE的 这个好的答案中阅读更多关于这个话题的内容:

至于杀死进程的情况下,没有简单的方法来做到这一点。

我已经测试过std::atexitstd::at_quick_exit函数没有通过任务管理器杀死程序后调用,所以我想你必须钩住终止调用…这似乎是一个非常复杂的任务,但解释在BSH的 这个答案中 :

当一个进程被终止(不关闭)时,除非你开始做一些钩子,否则不能做任何事情,要么在任务管理器进程中挂接TerminateProcessNtTerminateProcess

希望它有帮助(虽然是6年后的回答大声笑)

不直接解决您的问题,但是这对我来说是一个非常有帮助的工作:

我想避免混淆系统托盘状态。 所以对我来说,在启动时“刷新”通知盘就足够了。 这比我第一次想到的更复杂,但是下面演示了一个SendMessage解决方案,该解决方案模拟了一个不需要实际移动用户光标的用户 – 鼠标移除清理。

请注意,在Windows 7计算机上,名称Notification Area应替换为User Promoted Notification Area