用户注销/登录

时间:2017-07-22 13:49:25

标签: c++ windows winapi system-tray systray

我用:

创建一个系统托盘图标
BOOL TrayMessage(HWND hWnd, DWORD dwMessage)
{
    NOTIFYICONDATA nid;
    nid.cbSize = sizeof(nid);
    nid.hWnd = hWnd;
    nid.uID = 1;
    nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nid.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_MYAPP));
    lstrcpy(nid.szTip, L"MyApp");
    nid.uCallbackMessage = WM_NOTIFYICON;
    return Shell_NotifyIcon(dwMessage, &nid);
}

当应用程序启动/创建窗口时:

case WM_CREATE:
    if (!TrayMessage(hWnd, NIM_ADD))
        MessageBox(hMainWnd, L"Tray error.", 0, 0);

此错误消息框:

    当我正常启动.exe时,
  • 永远不会发生。

  • 仅在用户注销/用户重新登录后发生,平均每5次启动一次(我的应用程序会在每次会话启动时使用TaskSchedular任务自动启动)

当然,当错误发生时,任务栏中不会显示图标。

可能是什么原因?

  1. 系统托盘系统还没有准备好(用户退出/再次登录后很短)?

  2. 任务栏本身还没准备好?

  3. 我应该将创作移到WM_CREATE以外的某个位置吗?

  4. 编辑:在@ RbMm发表评论后,我尝试了这个:

    case WM_CREATE:
        TrayMessage(hWnd, NIM_ADD);
        // I removed MessageBox(...) from here
        uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
        ... 
        break;
    
    default:
        if (message == uTaskbarRestart)
        {
            TrayMessage(hWnd, NIM_ADD);
            MessageBox(hMainWnd, L"TaskbarRestart", 0, 0);
        }
    

    此测试的结果:托盘图标无法显示的情况完全未显示MessageBox TaskbarRestart的情况,即当TaskbarRestart事件永远不会出现时消息循环...这很奇怪......

    注意:这仅在用户注销/重新登录后才会发生。

1 个答案:

答案 0 :(得分:0)

当前版本的MSDN Shell_NotifyIcon不再显示它(真是太遗憾了!),但幸运的是,archived version here提供了两个有趣的信息:

1

  

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

2

  

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

     

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

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

     

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

解决方案:

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;