代码之家  ›  专栏  ›  技术社区  ›  Brian R. Bondy

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

  •  8
  • Brian R. Bondy  · 技术社区  · 16 年前

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

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

    Shell_NotifyIcon(NIM_ADD, &m_tnd);
    

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

    Shell_NotifyIcon(NIM_DELETE, &m_tnd);
    

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

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

    8 回复  |  直到 9 年前
        1
  •  4
  •   Stefan    16 年前

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

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

        2
  •  2
  •   Brian    16 年前

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

        3
  •  2
  •   MSalters    16 年前

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

    terminateprocess()必须更具破坏性。你真的无法防范,当它发生的时候,你的过程就完了。不处理ORE指令,因此应用程序中有什么代码并不重要。

    一个外部应用程序不会真的有帮助,是吗?它也可能坠毁,或者被杀死。

        4
  •  1
  •   casperOne    16 年前

    嗯,您始终可以让外部监视器进程调用sendmessage,并将wm_paint消息发送到系统托盘窗口(您必须根据窗口的类执行此操作)。这将删除不再有效的图标。

        5
  •  0
  •   Stefan    16 年前

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

    如果有任何帮助,请查看: http://www.codeproject.com/KB/shell/ashsystray.aspx

        6
  •  0
  •   Ferruccio    16 年前

    你可以使用 SetUnhandledExceptionFilter 为了赶上撞车。我通常使用它来创建一个崩溃转储文件,以便可以调试崩溃,但是没有理由不能像删除托盘图标那样进行简单的清理。

        7
  •  0
  •   Community CDub    7 年前

    有很多方法可以确保 Shell_NotifyIcon(NIM_DELETE, &m_tnd); 在C++中对应用程序进行CRHHASH;使用 RAII 包裹在 NOTIFYICONDATA 你使用的will可以完成这项工作,例如:

    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 在静态存储器中,它将在 WinMain main 调用及其析构函数将在程序清理时调用,即使此清理是由于异常终止所致。

    所以,我们可以用这个 通知数据 资源包装在 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); 图标将从通知区域中删除;此代码包括正常终止和异常终止,您可以在中阅读有关此主题的更多信息 this good answer NPE :

    至于 终止进程 万一没有简单的办法。

    我已经测试过了 std::atexit std::at_quick_exit 在通过任务管理器终止程序后不会调用函数,所以我想您必须 终止通话…这似乎是一项相当复杂的任务,但在 this answer BSH :

    当一个进程被终止(未关闭)时,除非你开始钩住它,否则任何事情都做不到。 TerminateProcess NtTerminateProcess 在任务管理器过程中

    希望能帮上忙(不过是6年后的一个答案,哈哈)

        8
  •  -1
  •   phillipwei    14 年前

    没有直接解决您的问题,但这对我来说是一项非常有用的工作:

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

    请注意,在Windows7计算机上 Notification Area 应替换为 User Promoted Notification Area .