A way to ensure that a system tray icon is removed… guaranteed

后端 未结 8 2358
广开言路
广开言路 2021-02-20 10:21

Is there a way to guarantee that your system tray icon is removed?

To add the system tray icon you do:

Shell_NotifyIcon(NIM_ADD, &m_tnd);
         


        
8条回答
  •  自闭症患者
    2021-02-20 11:04

    There are many ways to ensure the call to Shell_NotifyIcon(NIM_DELETE, &m_tnd); in C++ for the case of the application crhashing; using a RAII wrapper over the NOTIFYICONDATA you're using will do the work, for example:

    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;
    };
    

    This is a simplified version of the wrapper but it will illustrate the main idea: if you create an instance of NID in static storage it will be initialized before the WinMain or main call and its destructor will be called on the program cleanup, even if this cleanup is due an abnormal termination.

    So, we can use this NOTIFYICONDATA resource wrapped in struct NID this way:

    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;
    }
    

    The example above calls the ~NID() when the program terminates (after an exception or after closing the program), the destructor will call Shell_NotifyIcon(NIM_DELETE, &icon_data); and the icon is deleted from the notification area; this code covers the normal termination and the exception termination, you can read more about this topic in this good answer from NPE:

    As for the kill the process case there's no simple way to do this.

    I've already tested that std::atexit and std::at_quick_exit functions aren't called after killing the program through the task manager so I guess that you must hook the termination call... it seems a pretty complex task but is explained in this answer from BSH:

    When a process is terminated (not closed) nothing realy can be done unless you start do some hooking, either by hooking TerminateProcess or NtTerminateProcess in the Task Manger process

    Hope it helps (though is an answer 6 years later lol)

提交回复
热议问题