Blog. Just Blog

Принудительное обновление иконок в трее

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
В случае аварийного завершения или некорректной работы некоторых приложений, в системном трее могут оставаться "мертвые" иконки, которые уже не принадлежат ни одному запущенному процессу. Глюк хоть и не смертельный, но все равно неприятный. И основная проблема в том, что область трея никак не реагирует на внешние сообщения типа WM_REPAINT, и функции типа UpdateWindow и InvalidateRect. То есть автоматически обновить или перерисовать его, чтобы избавиться от "мертвых" иконок, не получится. Но такие иконки удаляются, если провести курсором мышки над ними. Значит единственный способ перерисовать иконки в трее - это сэмулировать движение мыши над окном трея. Как найти окно трея и его хэндл мы уже знаем, тут ничего нового. В сегменте данных те же значения:
  1. ; Сегмент данных
  2. section '.data' data readable writeable 
  3.  
  4. class1  db 'Shell_TrayWnd',0    ; Название класса окна трея
  5. class2  db 'TrayNotifyWnd',0    ; Название класса панели уведомлений
  6. class3  db 'SysPager',0         ; Трей
  7. class4  db 'ToolbarWindow32',0  ; Панель с иконками
  8.  
  9. ToolbarHandle   dd ?            ; Хэндл окна трея
  10. ToolbarRect     RECT            ; Размер окна трея
С поиском окна тоже никаких проблем. Способ универсальный, прекрасно работает на Windows XP и Windows 7.
  1.         ; Найти окно трея
  2.         invoke  FindWindow,class1,NULL
  3.         or      eax,eax
  4.         jz      exit_process
  5.  
  6.         ; Найти панель уведомлений
  7.         invoke  FindWindowEx,eax,NULL,class2,NULL
  8.         or      eax,eax
  9.         jz      exit_process
  10.  
  11.         ; Найти трей
  12.         invoke  FindWindowEx,eax,NULL,class3,NULL
  13.         or      eax,eax
  14.         jz      exit_process
  15.  
  16.         ; Найти панель иконок в трее
  17.         invoke  FindWindowEx,eax,NULL,class4,NULL
  18.         or      eax,eax
  19.         jz      exit_process
  20.  
  21.         ; Сохранить хэндл окна с иконками
  22.         mov     [ToolbarHandle],eax
Окно трея найдено, осталось сэмулировать движение мышки. Для этого надо просто получить размеры окна трея и в цикле отправить сообщение WM_MOUSEMOVE. Не обязательно эмулировать движение мышки над каждой точкой окна, достаточно пройтись один раз над каждой иконкой. Так как размер маленькой иконки 16х16 пикселов, то шаг выберем также 16.

И, собственно, сам код. Обратите внимание, что сообщения трею мы отправляем через PostMessage, чтобы не тратить время на ожидание от него ответа.
  1.         ; Получить размеры окна трея
  2.         invoke  GetClientRect,[ToolbarHandle],ToolbarRect
  3.  
  4.         ; Эмуляция движения мыши над окном трея
  5.         xor     esi,esi
  6. loc_move_line:
  7.  
  8.         xor     edi,edi
  9. loc_move_column:
  10.         ; y << 16
  11.         mov     eax,esi
  12.         shl     eax,16
  13.  
  14.         ; x
  15.         add     eax,edi
  16.  
  17.         ; Отправить сообщение движения мыши
  18.         invoke  PostMessage,[ToolbarHandle],WM_MOUSEMOVE,NULL,eax
  19.  
  20.         ; Следующий столбец
  21.         add     edi,16
  22.         cmp     edi,[ToolbarRect.right]
  23.         jb      loc_move_column
  24.  
  25.         ; Следующая строка
  26.         add     esi,16
  27.         cmp     esi,[ToolbarRect.bottom]
  28.         jb      loc_move_line
Этот способ, несмотря на то, что он работает, не лишен недостатков. Некоторые приложения, устанавливающие свои иконки в трей, реагируют на перемещение курсора над ними. Например, антивирус DrWeb показывает всплывающее окно с версией своей базы, менеджер USB-устройств Zentimo показывает окно со списком подключенных устройств, какие-нибудь другие программы также могут выполнять свои действия. Так вот, раз мы эмулируем движение мышки над иконками, то и программы срабатывают на это как на реальное движение курсора. Если вы используете трюк с обновлением трея в своей программе, то обязательно оформляйте его как отключаемую опцию с предупреждением о возможной несовместимости. К сожалению, пока что это единственный реальный способ заставить Проводник перерисовать иконки в трее из пользовательского приложения.

В приложении пример программы, обновляющей иконки в трее описанным в статье способом. Для тестов прилагается программа, которая устанавливает свою иконку в трей, и не удаляет ее после выхода.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Force.Update.Tray.Demo.zip (5,801 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 8874 | Комментариев: 21

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (22.01.2021 в 23:16):
Да сколько ж можно... Вот единственно правильное обновление. Без вариантов.
https://www.manhunter.ru/assem..._v_tree.html
Ivan_Alone (22.01.2021 в 23:10):
Если кому-то вдруг нужно, вот реализация того же на C++

HWND finder = FindWindow(L"Shell_TrayWnd", NULL);

if (finder) {
finder = FindWindowEx(finder, NULL, L"TrayNotifyWnd", NULL);

if (finder) {
finder = FindWindowEx(finder, NULL, L"SysPager", NULL);

if (finder) {
finder = FindWindowEx(finder, NULL, L"ToolbarWindow32", NULL);
RECT rect;

if (finder && GetClientRect(finder, &rect)) {
for (int x = 0; x < rect.right; x += 8) {
for (int y = 0; y < rect.bottom; y += 8) {
PostMessage(finder, WM_MOUSEMOVE, NULL, MAKELPARAM(x, y));
}
}
}
}
}
}
gorger (26.05.2018 в 22:34):
Чтобы не просило запуск от админа, просто переименуйте программу.
Слова update/install/setup/patch вызывают UAC.
ManHunter (08.04.2018 в 14:09):
Я что, как-то непонятно пишу? Покупай где-нибудь в даркнете приватный эксплойт на повышение привилегий, присылай мне, я добавлю в программу, чтобы она сама себе давала админа.
Павел (08.04.2018 в 09:32):
Не пароль, а запрос запуска от имени администратора)
ManHunter (07.04.2018 в 18:11):
У меня никаких паролей не запрашивает. Разбирайся в своей системе.
Павел (07.04.2018 в 18:06):
А можете обновить программу, чтобы не запрашивало пароль?
ManHunter (07.04.2018 в 15:34):
Конечно можно. В ядре винды наверняка остались какие-нибудь уязвимости, позволяющие получить доступ к памяти системных процессов из юзерской учетки.
Павел (07.04.2018 в 15:21):
Спасибо, работает. А можно обойтись без запуска от имени администратора?
Владимир (25.02.2016 в 00:48):
Респект добрым людям!
ManHunter (27.10.2014 в 18:22):
Открыл в FASM IDE, нажал Ctrl+F9. А вопросы по работе каких-то SASM, каких-то gcc и других программ надо направлять их авторам.
Mark (27.10.2014 в 18:13):
Не могли бы вы описать процесс компоновки?
gcc ругается: .../main.c:91: undefined reference to `WinMain@16'
ManHunter (27.10.2014 в 16:09):
Файл из стандартного комплекта FASM. Надо смотреть настройки IDE, где там все хранится. Я ей не пользуюсь.
Mark (27.10.2014 в 16:06):
Здравствуйте! В ходе компиляции в IDE SASM появляются следующие ошибки:

C:/Users/Mark/AppData/Local/Temp/SASM/program.asm [10]:
include 'win32a.inc'
error: file not found.
gcc.exe: error: C:/Users/Mark/AppData/Local/Temp/SASM/program.o: No such file or directory
gcc.exe: fatal error: no input files
compilation terminated.

Не могли бы вы подсказать где взять недостающие файлы?
Vladimir (04.07.2013 в 16:05):
Спасибо, очень помогло. Тем более, что в ассемблере я не силён.
antik (19.01.2012 в 14:44):
Было бы хорошо иметь возможность прописать конкретные программы.
И чтобы программа в трее искала только их=)
SAY (17.01.2012 в 19:37):
Точно также делал в одном приложении у себя. Очень огорчило отсутствие нормального обновления.
ManHunter (12.01.2012 в 09:15):
Обрабатывать сообщение минимизации окна, отслеживать скрытие (ShowWindow + SW_HIDE) своего окна из сторонних приложений.
Dimas (12.01.2012 в 08:08):
Спасибо, пример поглядел все понятно и работает
Немного неправильно я выразился - программу требуется прятать в трей при нажатие кнопки свернуть все (или свернуть все окна) или при нажатие win+D
Где-то на форумах советовали отслеживать события окон, была даже чья-то мысль обратиться к разработчику total-а)) Вообщем в итоге так ничего и не нашел.
ManHunter (11.01.2012 в 20:26):
По таймеру через GetForegroundWindow получаешь активное окно, находишь окно рабочего стола (class='Progman', text='Program Manager') если оно равно активному окну, то гасишь свое окно и ставишь иконку в трей. При клике на иконке убираешь ее из трея и показываешь свое окно.
Как-то так: http://rghost.ru/35859064 (без иконки в трее)
Dimas (11.01.2012 в 19:07):
Интересный вариант, можно попробовать
А вот такой вопрос - никогда не приходилось решать такое - сворачивание проги в трей при активации рабочего стола ? (а-ля total commander)
Как-то пробовал гуглить данный вопрос для Дельфей, но чет путнего ничего не нашел...

Добавить комментарий

Заполните форму для добавления комментария
Комментарии отключены администратором сайта
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 2 (0.005 сек.) / Память: 4.5 Mb
Наверх