Установщик свойств TTrayIcon.Visible
вызывает EOutOfResources
, когда запрос NIM_DELETE
завершается неудачно:
procedure TCustomTrayIcon.SetVisible(Value: Boolean);
begin
if FVisible <> Value then
begin
FVisible := Value;
...
if not (csDesigning in ComponentState) then
begin
if FVisible then
...
else if not (csLoading in ComponentState) then
begin
if not Refresh(NIM_DELETE) then
raise EOutOfResources.Create(STrayIconRemoveError); // <-- HERE
end;
...
end;
end;
end;
Где Refresh()
- это просто вызов функции Win32 Shell_NotifyIcon()
:
function TCustomTrayIcon.Refresh(Message: Integer): Boolean;
...
begin
Result := Shell_NotifyIcon(Message, FData);
...
end;
Когда вы получаете сообщение TaskbarCreated
, ваши предыдущие значки больше не отображаются на панели задач, поэтому Shell_NotifyIcon(NIM_DELETE)
возвращает False. Когда панель задач создается (повторно), вы не должны пытаться удалить старые значки, а только повторно добавлять новые значки с Shell_NotifyIcon(NIM_ADD)
по мере необходимости.
TTrayIcon
имеет publi c Refresh()
, но в нем используется NIM_MODIFY
вместо NIM_ADD
, так что в этой ситуации он тоже не сработает:
procedure TCustomTrayIcon.Refresh;
begin
if not (csDesigning in ComponentState) then
begin
...
if Visible then
Refresh(NIM_MODIFY);
end;
end;
Однако на самом деле вам не нужно обрабатывать TaskbarCreated
сообщение вручную при использовании TTrayIcon
, потому что он уже обрабатывает это сообщение внутри для вас, и он вызовет Shell_NotifyIcon(NIM_ADD)
, если Visible=True
:
procedure TCustomTrayIcon.WindowProc(var Message: TMessage);
...
begin
case Message.Msg of
...
else
if (Cardinal(Message.Msg) = RM_TaskBarCreated) and Visible then
Refresh(NIM_ADD); // <-- HERE
end;
end;
...
initialization
...
TCustomTrayIcon.RM_TaskBarCreated := RegisterWindowMessage('TaskbarCreated');
end.
Если по какой-то причине это не работает правильно, и / или вам нужно обрабатывать TaskbarCreated
вручную, тогда я бы предложил напрямую вызвать защищенный метод TCustomTrayIcon.Refresh()
, например:
type
TTrayIconAccess = class(TTrayIcon)
end;
procedure TForm1.WndProc(var Message: TMessage);
begin
if (msgTaskbarRestart <> 0) and (Message.Msg = msgTaskbarRestart) then begin
if TrayIcon1.Visible then begin
// TrayIcon1.Refresh;
TTrayIconAccess(TrayIcon1).Refresh(NIM_ADD);
end;
Message.Result := 1;
end;
inherited WndProc(Message);
end;
В противном случае просто не используйте TTrayIcon
в все. Известно, что глючит. Я видел много людей, у которых было много проблем с TTrayIcon
на протяжении многих лет. Я бы предложил вместо этого напрямую использовать Shell_NotifyIcon()
. У меня никогда не было проблем с его использованием.