确保系统托盘图标被移除的方法...保证

10

有没有一种方法可以保证您的系统托盘图标被删除?

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

Shell_NotifyIcon(NIM_ADD, &m_tnd);

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

Shell_NotifyIcon(NIM_DELETE, &m_tnd);
我想知道:如果你的应用程序崩溃了怎么办?除非你将鼠标移动到图标上方,否则图标会一直停留在系统托盘中。是否有一种方法可以确保即使应用程序崩溃,图标也会被删除?出于各种原因,我不想使用结构化异常处理。
另一个我想要处理的情况是进程被杀死,但不一定会崩溃。
8个回答

4

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

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


2

您可以编写一个独立的、更简单的程序来监控您的应用程序,这样可以增强程序的稳定性。该程序实际上可以启动您的程序并监视其进程。是的,这是一种非常丑陋的解决方案。


此外,这个外部程序可以管理托盘图标,主程序使用通知来传递其状态,如果超时还未到达通知,则该图标将被隐藏,相当于保持活动的消息。 - Ismael

2

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

TerminateProcess()更具破坏性。您真的无法保护自己免受此影响;当它发生时,您的进程已经死亡。没有其他指令被处理,因此您应用程序中的任何代码都没有意义。

外部应用程序真的没有帮助,对吧?它也可能崩溃或被终止。


1

有许多方法可以确保在应用程序崩溃的情况下,在C ++中调用Shell_NotifyIcon(NIM_DELETE,&m_tnd);。例如,使用 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实例,则它将在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);并且图标会从通知区域中删除;此代码涵盖了正常终止和异常终止,您可以在this good answer中阅读更多关于此主题的内容,该回答来自NPE
至于“杀死进程”的情况,没有简单的方法可以做到这一点。
我已经测试过std::atexitstd::at_quick_exit函数在通过任务管理器杀死程序后不会被调用,所以我猜你必须hook终止调用...这似乎是一个相当复杂的任务,但可以在this answer中从BSH中找到解释。

当进程被终止(而不是关闭)时,除非开始进行一些挂钩,否则什么都无法做,要么通过挂钩TerminateProcessNtTerminateProcess在任务管理器进程中。

希望能有所帮助(虽然是六年后的答案哈哈)。

1

嗯,您可以始终具有外部监视器进程通过 SendMessage 调用 WM_PAINT 消息到系统托盘窗口(您必须根据窗口的类来执行此操作)。这应该会删除不再有效的图标。


0

0

你可以使用SetUnhandledExceptionFilter来捕获崩溃。我通常使用它来创建一个崩溃转储文件,以便进行调试,但你也可以做一些简单的清理工作,比如移除托盘图标。


-1

虽然这并没有直接解决你的问题,但对我来说这是一个非常有用的解决方法:

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

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


1
如果用户在Win XP或更高版本中使用“箭头”隐藏图标,则会出现问题。你打算怎么做——通过编程尝试点击箭头,然后将鼠标移动到弹出窗口中的每个图标上——如果弹出窗口消失,则重复点击箭头?那么当新版本的Windows推出时呢?这个“箭头”功能是在XP中引入的,在Vista中更改的,我不知道在Windows 8中是否会再次更改。你必须为每个操作系统进行硬编码,而你的应用程序将在新版本上崩溃。这是一种非常难以维护的方法! - James Johnston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接