且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

用户注销/登录后,创建托盘图标时出现罕见错误

更新时间:2023-12-04 19:57:04

当前版本的 MSDN Shell_NotifyIcon 不再显示(太可惜了!),但幸运的是,有一个 这里有两个存档版本信息:

The current version of MSDN Shell_NotifyIcon doesn't show it anymore (such a shame!), but fortunately, there's an archived version here that gives two interesting informations:

1.

如果成功则返回 TRUE,否则返回 FALSE.[...]您可以调用 GetLastError 以获取有关失败案例的更多具体信息.失败的最常见原因是任务栏窗口不存在或无响应.在这种情况下,GetLastError 返回 E_FILE_NOT_FOUND.

Returns TRUE if successful, or FALSE otherwise. [...] You can call GetLastError for more specific information about a failure case. The most common cause of failure is that the taskbar window doesn't exist or is unresponsive. GetLastError in that case returns E_FILE_NOT_FOUND.

2.

处理 Shell_NotifyIcon 失败
Shell_NotifyIcon 在 Windows 启动时调用时经常会失败(例如,如果您的应用程序列在 HKLM\Software\Microsoft\Windows\CurrentVersion\Run 中.这似乎是因为系统正忙于启动应用程序.该失败更常见于低-spec 的计算机或安装了某些品牌防病毒软件的计算机,启动时似乎非常密集.

Handling Shell_NotifyIcon failure
Shell_NotifyIcon will often fail when called during Windows startup (for instance, if your application is listed in HKLM\Software\Microsoft\Windows\CurrentVersion\Run. This appears to be because the system is busy starting applications. The failure is more common on low-spec computers or computers with some brands of antivirus software installed, which seem to be very intensive at startup.

不幸的是,您不能依赖 GetLastError 返回的错误代码.当 Shell_NotifyIcon 返回 false 时,GetLastError 返回的一些常见错误是:

Unfortunately, you cannot rely on the error code returned by GetLastError. When Shell_NotifyIcon returns false, some of the common errors returned by GetLastError are:

ERROR_FILE_NOT_FOUND (2)
ERROR_TIMEOUT (1460)
ERROR_SUCCESS (0)

对 Shell_NotifyIcon 返回的任何错误的最合适的响应是休眠一段时间并重试.

Paul Baker 解释了错误代码可能不同的原因,转述自 http://groups.google.com/group/microsoft.public.platformsdk.shell/msg/59235b293cbf5dfahttp://groups.google.com/group/microsoft.public.platformsdk.shell/msg/73973287f15c03fc:

An explanation of why the error code may differ has been made by Paul Baker, paraphrased from http://groups.google.com/group/microsoft.public.platformsdk.shell/msg/59235b293cbf5dfa and http://groups.google.com/group/microsoft.public.platformsdk.shell/msg/73973287f15c03fc:

Shell_NotifyIcon 实际上最初调用 SetLastError(0).之后,基本上它使用 FindWindow 来查找托盘通知窗口.如果失败,它通常会返回 ERROR_FILE_NOT_FOUND.否则,它使用 SendMessageTimeout 向托盘通知窗口发送 WM_COPYDATA 消息,超时仅为 4 秒.如果该消息返回零,则 Shell_NotifyIcon 将失败,GetLastError 将返回零.

Shell_NotifyIcon actually calls SetLastError(0) initially. After that, basically it uses FindWindow to find the tray notification window. If this fails, it will typically return ERROR_FILE_NOT_FOUND. Otherwise it sends a WM_COPYDATA message to the tray notification window, using SendMessageTimeout with a timeout of only 4 seconds. If that message returns zero, then Shell_NotifyIcon will fail with GetLastError returning zero.

解决方案:

case WM_CREATE:
    ...
    if (!TrayMessage(hWnd, NIM_ADD)) 
        SetTimer(hWnd, IDT_TIMER1, 4000, (TIMERPROC) NULL);
    break;

case WM_TIMER:
    TrayMessage(hWnd, NIM_ADD);
    KillTimer(IDT_TIMER1);
    break;