Редкая ошибка при создании иконки в трее после выхода пользователя из системы / входа в систему

Я создаю значок 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. Система systray еще не готова (очень скоро после выхода пользователя из системы / входа в систему)?

  2. Сама панель задач еще не готова?

  3. Должен ли я переместить творение куда-то за WM_CREATE?


редактировать: после комментария @ 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

Решение

Текущая версия MSDN Shell_NotifyIcon больше не показывает это (такой позор!), Но, к счастью, есть архивная версия здесь это дает две интересные сведения:

1.

Возвращает ИСТИНА в случае успеха или ЛОЖЬ в противном случае. […] Вы можете вызвать GetLastError для получения более конкретной информации о случае сбоя. Наиболее распространенная причина сбоя заключается в том, что окно панели задач не существует или не отвечает. GetLastError в этом случае возвращает E_FILE_NOT_FOUND.

2.

Обработка ошибки Shell_NotifyIcon
Shell_NotifyIcon часто завершается ошибкой при вызове во время запуска Windows (например, если ваше приложение указано в HKLM \ Software \ Microsoft \ Windows \ CurrentVersion \ Run. Это происходит из-за того, что система занята запуском приложений. Отказ чаще всего происходит на низком уровне). -специфические компьютеры или компьютеры с установленным антивирусным программным обеспечением некоторых марок, которые при запуске выглядят очень интенсивно.

К сожалению, вы не можете полагаться на код ошибки, возвращаемый GetLastError. Когда Shell_NotifyIcon возвращает false, некоторые из распространенных ошибок, возвращаемых GetLastError:

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

Наиболее подходящим ответом на любую ошибку, возвращаемую Shell_NotifyIcon, является период ожидания и повторная попытка.

Пол Бейкер объяснил, почему код ошибки может отличаться, перефразируя http://groups.google.com/group/microsoft.public.platformsdk.shell/msg/59235b293cbf5dfa а также http://groups.google.com/group/microsoft.public.platformsdk.shell/msg/73973287f15c03fc:

Shell_NotifyIcon фактически вызывает SetLastError (0) первоначально. После этого он использует FindWindow для поиска окна уведомлений в трее. Если это не удается, обычно возвращается ERROR_FILE_NOT_FOUND. В противном случае он отправляет сообщение WM_COPYDATA в окно уведомлений в трей, используя SendMessageTimeout с таймаутом всего 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;
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]