10

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

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

Shell_NotifyIcon(NIM_ADD, &m_tnd);

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

Shell_NotifyIcon(NIM_DELETE, &m_tnd);

我想知道:如果您的应用程序崩溃了怎么办?该图标会一直保留在系统托盘中,直到您将鼠标悬停。有没有办法保证图标会被删除,即使应用程序崩溃?由于各种原因,我宁愿不使用结构化异常处理。

我要处理的另一种情况是进程被终止但不一定崩溃。

4

8 回答 8

4

大多数程序员忘记检查的另一件事是资源管理器是否重新启动/崩溃。如果应用程序处理这个并重新创建自己的图标,那就太好了。

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

于 2009-01-20T23:58:48.013 回答
2

您可以有一个单独的、更简单(因此可能更健壮)的程序来监控您的应用程序。该程序实际上可以启动您的程序,然后监视该过程。是的,这是一个非常丑陋的解决方案。

于 2009-01-20T03:45:50.007 回答
2

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

TerminateProcess() 必须更具破坏性。你真的无法避免这种情况;当它发生时,你的进程已经死了。没有矿石指令被处理,所以你的应用程序中有什么代码并不重要。

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

于 2009-01-20T09:29:46.207 回答
1

在应用程序崩溃的情况下,有很多方法可以确保Shell_NotifyIcon(NIM_DELETE, &m_tnd);在 C++ 中调用;在您使用的RAII包装器上NOTIFYICONDATA使用将完成工作,例如:

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在静态存储中创建一个实例,它将在WinMainormain调用之前初始化,并且在程序清理时将调用其析构函数,即使此清理到期异常终止。

所以,我们可以用这种方式NOTIFYICONDATA包装这个资源struct NID

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::atexit并且std::at_quick_exit在通过任务管理器杀死程序后不会调用函数,所以我想你必须挂钩终止调用......这似乎是一个非常复杂的任务,但在 BSH 的这个答案中进行解释

当一个进程终止(未关闭)时,除非你开始做一些挂钩,要么通过挂钩TerminateProcessNtTerminateProcess在任务管理器进程中,否则什么都做不了

希望它有所帮助(虽然是 6 年后的答案,哈哈)

于 2015-04-27T14:06:12.817 回答
1

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

于 2009-01-20T03:46:08.397 回答
0

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

于 2009-01-20T10:14:37.960 回答
0

当以某种方式崩溃时,您必须处理应用程序退出,否则图标不会消失。

看看它是否有任何帮助: http: //www.codeproject.com/KB/shell/ashsystray.aspx

于 2009-01-20T03:47:00.237 回答
-1

不能直接解决您的问题,但这对我来说是一个非常有用的解决方法:

我想避免混淆系统托盘状态。所以对我来说,在启动时“刷新”通知托盘就足够了。这比我最初想象的要棘手,但下面演示了一个 SendMessage 解决方案,它模拟了用户鼠标悬停清理,不需要实际移动用户的光标。

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

于 2010-11-24T09:02:33.633 回答