在应用程序崩溃的情况下,有很多方法可以确保在 C++ 中调用Shell_NotifyIcon(NIM_DELETE, &m_tnd);;在您正在使用的 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 的实例,它将在WinMain 或main 调用之前初始化,其析构函数将是调用程序清理,即使此清理是由于异常终止。
所以,我们可以这样使用包裹在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::atexit 和 std::at_quick_exit 函数在通过任务管理器杀死程序后不会被调用,所以我猜你必须挂钩终止调用......它似乎是一项相当复杂的任务,但在this answer 中的BSH 中进行了解释:
当一个进程终止(未关闭)时,除非你开始做一些挂钩,否则实际上什么都做不了,无论是通过在任务管理器进程中挂钩 TerminateProcess 或 NtTerminateProcess
希望它有所帮助(虽然是 6 年后的答案,哈哈)