Вопрос, с которым сталкиваются разработчики в среде Delphi XE, касается обработки системных уведомлений для иконок в системном трее, и в частности, возникающего исключения EOutOfResources при попытке скрыть иконку после сбоя или перезапуска Проводника Windows (Explorer).
Причины возникновения исключения EOutOfResources
Исключение EOutOfResources в контексте работы с иконками в трее обычно возникает из-за неудачной попытки удаления уведомления о системной иконке. Это может произойти, если код пытается удалить иконку, которая уже не существует в системе после сбоя Проводника.
Пример кода, вызывающего исключение
В представленном коде (см. выше) при получении системного сообщения TaskbarCreated происходит попытка скрыть иконку, что приводит к исключению EOutOfResources:
procedure TForm1.WndProc(var Message: TMessage);
begin
if (msgTaskbarRestart <> 0) and (Message.Msg = msgTaskbarRestart) then begin
TrayIcon1.Visible := False; // здесь возникает исключение
TrayIcon1.Visible := True; // попытка заменить иконку в трее
Message.Result := 1;
end;
inherited WndProc(Message);
end;
Подтвержденный ответ
Проблема заключается в том, что свойство Visible компонента TTrayIcon вызывает метод Refresh с параметром NIM_DELETE, который не может быть выполнен, так как уведомление уже не существует в системе после сбоя Проводника. Это приводит к возникновению исключения EOutOfResources.
procedure TCustomTrayIcon.SetVisible(Value: Boolean);
begin
...
if not Refresh(NIM_DELETE) then
raise EOutOfResources.Create(STrayIconRemoveError);
end;
Альтернативный путь решения
Используя внутренние механизмы компонента TTrayIcon, можно обойтись без ручной обработки сообщения TaskbarCreated. Компонент сам обрабатывает это сообщение и вызывает Shell_NotifyIcon с параметром NIM_ADD, если свойство Visible установлено в True:
procedure TCustomTrayIcon.WindowProc(var Message: TMessage);
begin
...
if (Cardinal(Message.Msg) = RM_TaskBarCreated) and Visible then
Refresh(NIM_ADD);
...
end;
Рекомендации
Если стандартная обработка сообщения TaskbarCreated не работает корректно, можно напрямую вызвать защищенный метод Refresh с параметром NIM_ADD:
procedure TForm1.WndProc(var Message: TMessage);
begin
if (msgTaskbarRestart <> 0) and (Message.Msg = msgTaskbarRestart) then begin
if TrayIcon1.Visible then begin
TTrayIconAccess(TrayIcon1).Refresh(NIM_ADD);
end;
Message.Result := 1;
end;
inherited WndProc(Message);
end;
Также стоит рассмотреть возможность использования Shell_NotifyIcon напрямую, минуя TTrayIcon, так как последний может быть нестабильным.
В данной статье были рассмотрены причины возникновения исключения EOutOfResources при работе с иконками в трее в среде Delphi XE, а также предложены пути решения этой проблемы. Описанные методы позволяют эффективно обрабатывать системные уведомления и предотвращать возникновение исключений в коде.
Разработчики в Delphi XE сталкиваются с необходимостью корректной обработки системных уведомлений для иконок в трее, включая решение проблемы возникновения исключения `EOutOfResources` при попытке скрыть иконку после сбоя Проводника Windows.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.