windows 一种确保删除系统托盘图标的方法......保证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/460059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
A way to ensure that a system tray icon is removed... guaranteed
提问by Brian R. Bondy
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);
To remove the system tray icon you do:
要删除系统托盘图标,您可以:
Shell_NotifyIcon(NIM_DELETE, &m_tnd);
What I want to know: what if you application crashes? The icon stays in your system tray until you mouse over. Is there a way to guarantee that the icon will be removed, even when the application crashes? I would prefer not to use structured exception handling for various reasons.
我想知道的是:如果您的应用程序崩溃怎么办?该图标会一直保留在您的系统托盘中,直到您将鼠标悬停在上方。有没有办法保证即使应用程序崩溃也能删除图标?由于各种原因,我不想使用结构化异常处理。
Another case that I want to handle is when the process is killed, but doesn't necessarily crash.
我想处理的另一种情况是进程被杀死但不一定崩溃。
回答by Stefan
Another thing most programmers forget to check for is if the explorer restarts/crashes. Its nice if the application handle this and recreate its own icon.
大多数程序员忘记检查的另一件事是资源管理器是否重新启动/崩溃。如果应用程序处理这个并重新创建自己的图标,那就太好了。
Just check for Message WM_TASKBARCREATED and recreate the icon.
只需检查消息 WM_TASKBARCREATED 并重新创建图标。
回答by MSalters
Personally I would use a Vectored Exception Handler. Yes, it's based on SEH, but you don't have to deal with all the different stack that you might need to unwind.
我个人会使用向量异常处理程序。是的,它基于 SEH,但您不必处理可能需要放松的所有不同堆栈。
TerminateProcess() is must more destructive. You really can't guard yourself against that; when it happens your process is dead. No ore instructions are processed, so it does not matter what code there is in your application.
TerminateProcess() 必须更具破坏性。你真的无法防备自己。当它发生时,你的进程就死了。不处理矿石指令,因此您的应用程序中有什么代码并不重要。
An external application wouldn't really help, would it? It too could crash, or be killed.
外部应用程序不会真正有帮助,不是吗?它也可能崩溃,或被杀死。
回答by Brian
You could have a separate, simpler (and thus presumably more robust) program which monitors your application. This program could actually launch your program and then monitor the process. Yeah, this is a very ugly solution.
您可以拥有一个单独的、更简单(因此可能更健壮)的程序来监视您的应用程序。该程序实际上可以启动您的程序,然后监视该过程。是的,这是一个非常丑陋的解决方案。
回答by casperOne
Hmm, you can always have an external monitor process call SendMessage with the WM_PAINT message to the system tray window (which you would have to do based on the class of the window). That should remove the icon which is no longer valid.
嗯,您始终可以让外部监视器进程调用 SendMessage,并将 WM_PAINT 消息发送到系统托盘窗口(您必须根据窗口的类别执行此操作)。那应该删除不再有效的图标。
回答by Stefan
You have to handle the applications exit when crashing some way or another or the icon will not disapear.
当以某种方式崩溃时,您必须处理应用程序退出,否则图标不会消失。
Check this out if it can be any help: http://www.codeproject.com/KB/shell/ashsystray.aspx
看看这个是否有帮助:http: //www.codeproject.com/KB/shell/ashsystray.aspx
回答by Ferruccio
You can use SetUnhandledExceptionFilterto catch the crash. I normally use it to create a crash dump file so that the crash can be debugged, but there's no reason you can't so some simple cleanup like removing tray icons.
您可以使用SetUnhandledExceptionFilter来捕获崩溃。我通常使用它来创建崩溃转储文件,以便可以调试崩溃,但没有理由不能进行一些简单的清理,例如删除托盘图标。
回答by PaperBirdMaster
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 RAIIwrapper over the NOTIFYICONDATA
you're using will do the work, for example:
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;
};
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.
这是包装器的简化版本,但它将说明主要思想:如果您NID
在静态存储中创建一个实例,它将在WinMain
ormain
调用之前初始化,并且在程序清理时将调用其析构函数,即使此清理到期异常终止。
So, we can use this NOTIFYICONDATA
resource wrapped in struct NID
this way:
所以,我们可以这样使用这个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;
}
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 answerfrom NPE:
上面的例子调用了~NID()
当程序终止时(异常后或关闭程序后),析构函数会调用Shell_NotifyIcon(NIM_DELETE, &icon_data);
,图标从通知区域中删除;此代码覆盖正常终止和异常终止,你可以阅读更多关于此主题的这个好答案来自NPE:
As for the kill the processcase 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 hookthe termination call... it seems a pretty complex task but is explained in this answerfrom BSH:
我已经测试了std::atexit
和std::at_quick_exit
,所以我猜你一定作用不是通过任务管理器杀程序后叫勾终止电话...这似乎是一个相当复杂的任务,但在解释这个答案从BSH:
When a process is terminated (not closed) nothing realy can be done unless you start do some hooking, either by hooking
TerminateProcess
orNtTerminateProcess
in the Task Manger process
当一个进程终止(未关闭)时,除非你开始做一些挂钩,或者通过挂钩
TerminateProcess
或NtTerminateProcess
在任务管理器进程中,否则什么也做不了
Hope it helps (though is an answer 6 years later lol)
希望它有所帮助(虽然是 6 年后的答案,哈哈)
回答by phillipwei
Does not directly address your problem, but this was a very helpful work around for me:
没有直接解决您的问题,但这对我来说是一个非常有用的解决方法:
I wanted to avoid confusing system-tray states. So for me, it was sufficient to 'refresh' the notification tray on startup. This was trickier than I first thought, but the followingdemonstrates a SendMessage solution that simulates a user-mouse-over cleanup that doesn't involve needing to actually move the user's cursor around.
我想避免混淆系统托盘状态。所以对我来说,在启动时“刷新”通知托盘就足够了。这比我最初想象的要棘手,但下面演示了一个 SendMessage 解决方案,它模拟用户鼠标悬停清理,不需要实际移动用户的光标。
Note that on Windows 7 machines the name Notification Area
should be replaced with User Promoted Notification Area
.
请注意,在 Windows 7 机器上,名称Notification Area
应替换为User Promoted Notification Area
.