Blog. Just Blog

Получение списка иконок в трее

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Иногда приложению требуется получить список иконок, находящихся в трее, а также список приложений, которые их туда разместили. Это может быть нужно для обнаружения некоторых скрывающихся приложений, для эмуляции кликов на иконках, ну или просто для спортивного интереса. В любом случае для получения списка иконок надо сделать следующее: найти в трее панель с иконками, при помощи сообщения TB_BUTTONCOUNT получить количество иконок, а затем через отправку сообщения TB_GETBUTTON получить всю необходимую информацию по каждой иконке. Теперь рассмотрим все шаги подробнее.

Работать с вложенными окнами трея мы уже умеем, здесь практически то же самое, разница только в названиях классов дочерних окон.
  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. ...
  11. ; Сегмент кода
  12. section '.code' code readable executable
  13.         ...
  14.         ; Найти окно трея
  15.         invoke  FindWindow,class1,NULL
  16.         or      eax,eax
  17.         jz      exit_process
  18.  
  19.         ; Найти панель уведомлений
  20.         invoke  FindWindowEx,eax,NULL,class2,NULL
  21.         or      eax,eax
  22.         jz      exit_process
  23.  
  24.         ; Найти трей
  25.         invoke  FindWindowEx,eax,NULL,class3,NULL
  26.         or      eax,eax
  27.         jz      exit_process
  28.  
  29.         ; Найти панель иконок в трее
  30.         invoke  FindWindowEx,eax,NULL,class4,NULL
  31.         or      eax,eax
  32.         jz      exit_process
  33.  
  34.         ; Сохранить хэндл окна с иконками
  35.         mov     [ToolbarHandle],eax
  36.         ...
Теперь у нас есть хэндл окна панели инструментов с иконками в трее. Получим количество иконок в панели.
  1.         ; Получить количество иконок в трее
  2.         invoke  SendMessage,eax,TB_BUTTONCOUNT,0,0
  3.         or      eax,eax
  4.         jz      exit_process
  5.  
  6.         ; Сохранить количество иконок в трее
  7.         mov     [IconsCount],eax
Количество иконок тоже есть. Осталось перебрать их в цикле и получить всю необходимую информацию. Для этого используется сообщение TB_GETBUTTON и структура TBBUTTON для получения результата. Однако, если сейчас попробовать послать окну панели сообщение TB_GETBUTTON, то в результате не получим ничего. Почему? Потому что память, в которую будут записываться данные, обязательно должна принадлежать процессу, который является владельцем окна трея (обычно это explorer.exe).

Ненадолго отвлечемся от трея и выделим блок памяти нужного размера в контексте процесса-владельца трея. Размер блока равен размеру структуры TBBUTTON.
  1.         ; Получить ID процесса-владельца трея
  2.         invoke  GetWindowThreadProcessId,[ToolbarHandle],ProcId
  3.         ; Открыть процесс с полным доступом
  4.         invoke  OpenProcess,PROCESS_ALL_ACCESS,FALSE,[ProcId]
  5.         or      eax,eax
  6.         ; Фокус не удался
  7.         jz      exit_process
  8.  
  9.         ; Сохранить хэндл процесса-владельца трея
  10.         mov     [hProcess],eax
  11.  
  12.         ; Выделить блок памяти в контексте процесса
  13.         invoke  VirtualAllocEx,[hProcess],NULL,dword sizeof.TBBUTTON,\
  14.                 MEM_COMMIT,PAGE_READWRITE
  15.         or      eax,eax
  16.         jz      exit_process
  17.  
  18.         ; Сохранить указатель на блок памяти
  19.         mov     [lpData],eax
Теперь все готово для приема данных, можно приступать к перебору иконок в трее. В структуре TBBUTTON двойное слово dwData - указатель на блок расширенных данных, которые определяются приложением. В нашем случае по этому адресу лежит структура EXTRADATA, не описанная в FASM:
  1. ; Структура пользовательских данных иконки
  2. struct EXTRADATA
  3.         Wnd dd ?  ; Хэндл родительского окна иконки
  4.         uID dd ?  ; Стиль отображения иконки
  5. ends
Поскольку все нужные данные находятся в другом процессе, читать их будем через функцию ReadProcessMemory: сперва структуру TBBUTTON, а затем соответствующую ей структуру EXTRADATA. Зная хэндл окна-владельца каждой иконки, можно получить идентификатор процесса, которому принадлежит окно, а по нему, в свою очередь, можно узнать имя исполняемого файла. Для получения имени есть несколько методов, в этом примере я буду использовать функцию CreateToolhelp32Snapshot.
  1.         ; Перебрать все иконки в трее
  2. loc_loop:
  3.         dec     [IconsCount]
  4.  
  5.         ; Получить иконку из трея с индексом IconsCount
  6.         invoke  SendMessage,[ToolbarHandle],TB_GETBUTTON,[IconsCount],[lpData]
  7.         ; Прочитать структуру иконки
  8.         invoke  ReadProcessMemory,[hProcess],[lpData],button,\
  9.                 dword sizeof.TBBUTTON,BytesRead
  10.         or      eax,eax
  11.         jz      exit_process
  12.         ; Прочиталась вся структура?
  13.         cmp     [BytesRead],sizeof.TBBUTTON
  14.         jnz     exit_process
  15.  
  16.         ; Прочитать пользовательские данные иконки
  17.         invoke  ReadProcessMemory,[hProcess],[button.dwData],extra,\
  18.                 dword sizeof.EXTRADATA,BytesRead
  19.         or      eax,eax
  20.         jz      exit_process
  21.         ; Прочиталась вся структура?
  22.         cmp     [BytesRead],sizeof.EXTRADATA
  23.         jnz     exit_process
  24.  
  25.         ; Это скрытая иконка?
  26.         mov     eax,[extra.uID]
  27.         and     eax,80000000h
  28.         or      eax,eax
  29.         ; Да, пропустить
  30.         jnz     loc_loop
  31.  
  32.         ; Окно процесса существует?
  33.         invoke  IsWindow,[extra.Wnd]
  34.         or      eax,eax
  35.         jz      loc_loop
  36.  
  37.         ; Получить Id процесса, чья иконка находится в трее
  38.         invoke  GetWindowThreadProcessId,[extra.Wnd],ProcTrayId
  39.  
  40.         ; Снимок процессов системы
  41.         invoke  CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
  42.         mov     ebx,eax
  43.  
  44.         ; Перебрать в цикле все процессы
  45.         mov     eax,sizeof.PROCESSENTRY32
  46.         mov     [ProcEntry.dwSize],eax
  47.         invoke  Process32First,ebx,ProcEntry
  48. @@:
  49.         cmp     eax,FALSE
  50.         je      @f
  51.         ; Это нужный нам процесс?
  52.         mov     eax,[ProcEntry.th32ProcessID]
  53.         cmp     eax,[ProcTrayId]
  54.         je      @f
  55.         ; Следующий процесс
  56.         invoke  Process32Next,ebx,ProcEntry
  57.         or      eax,eax
  58.         jz      loc_loop
  59.         jmp     @b
  60. @@:
  61.         push    eax
  62.         ; Закрыть хэндл
  63.         invoke  CloseHandle,ebx
  64.         pop     eax
  65.  
  66.         ; Имя файла определить не удалось
  67.         or      eax,eax
  68.         jz      @f
  69.  
  70.         invoke  wsprintf,buff,mask,ProcEntry.szExeFile
  71.         add     esp,12
  72.  
  73.         ; Записать имя файла в консоль
  74.         invoke  lstrlen,buff
  75.         invoke  WriteConsole,[stdout],buff,eax,BytesRead,NULL
  76. @@:
  77.         ; Все иконки обработали?
  78.         cmp     [IconsCount],0
  79.         ja      loc_loop
  80.  
  81.         ; Очистить память и ресурсы
  82.         invoke  VirtualFreeEx,[ProcId],[lpData],0,MEM_RELEASE
  83.         invoke  CloseHandle,[ProcId]
Описанный метод протестирован и гарантированно работает в Windows XP и Windows 7, но не работает в альтернативных оболочках типа Aston Desktop, потому что в них используются другие названия классов окон и их иерархия.

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

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

Tray.Applications.Listing.Demo.zip (3,501 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 6727 | Комментариев: 9

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

Комментарии

Отзывы посетителей сайта о статье
brute (14.12.2015 в 11:23):
Спасибо! буду дальше медитировать. Запускать код x32 на x64 - это извращение: зачем? - проще перекомпилировать без изменения исходников. В п.1 я пытался сказать, что сами структуры (по крайней мере, поле для иконки) для "ReadProcessMemory" для x32 на x64 не совпадают! Они различны, а в чём различие - не известно, так как не нашёл полного описания полей этих структур..
ManHunter (14.12.2015 в 10:57):
1. Затем, что не получив одной структуры, нельзя узнать адрес другой. По чтению из памяти - NtWow64ReadVirtualMemory64, иначе ничего 32-битному процессу из 64-байтного адресного пространства не прочитать. Адаптация кода под x64 меня не интересует, я ей заниматься не собираюсь.
2. "Нет тела - нет дела". Читать тут тоже нечего.
3. Разве у треда есть иконки? Иконки есть у окна и у исполняемого файла. Если интересует какое окно принадлежит треду, то перебираешь все окна, проверяешь их процесс-владельца, затем проверяешь принадлежность треду, при совпадении выдергиваешь иконку из окна. Не забывай про IsWindowVisible.
brute (14.12.2015 в 09:59):
пытался сие повторить на PB.. Вот что получилось:
https://yadi.sk/d/Qt3ziCQMmCppF
Вопросы:
1. Зачем читаем из процесса в две разных структуры а не в одну? и где почитать про чтение инфы из процесса, в частности про строение структур/процессов в памяти для x32 и x64?
На Win7_64 не работает (в моем варианте)структура button_td.TRAYDATA - в твоем extra. Методом тыка (добавлением новых членов в структуру) удалось что-то получить, но всё равно не все иконки видны.
2. где почитать теорию про "скрытаю иконку"   
3. Почему "ExtractIcon" криво/не похоже извлекает иконки?
пробовал также безрезультатно
SendMessage_(hwnd,#WM_GETICON,#ICON_SMALL,0)
GetClassLong_(hwnd,#GCL_HICONSM)
Вернее, понятно, что ExtractIcon извлекает иконки приложения, а не трэда/процесса этого приложения. Как извлечь иконку трэда?
ManHunter (01.09.2015 в 13:00):
Ясно дело ничего не выведет, или ты думал, что 32-битная программа вот так просто получит доступ к памяти 64-битного эксплорера?
Сергей (01.09.2015 в 12:51):
Программа не работает. Ничего не вывело
ManHunter (25.10.2010 в 08:36):
Здесь где-то сказано, что я пишу на дельфи?
URTUR (25.10.2010 в 07:35):
ПОМОГИТЕ!!
Я пишу оболочку (или как это называется:) в Delphi (6,7)
и вот столкнулся с проблемой трея:
как получить список иконок на свою форму и работать с ними?!
(т.е эмулировать работу трея)..
К сожалению Google не помог! :(
Поэтому попал к Вам, т.к здесь имеется хоть какая-то информация:)
Буду очень признателен, если кто поделится куском кода или хотябы подскажет в какую сторону копать.. Заранее спасибо!.
Контактная информация: [мыло: del], [icq: del]
ManHunter (28.07.2010 в 10:15):
Дублируй, я не против.
umka (28.07.2010 в 10:00):
А можно на Delphi продублировать???
В принципе, понятно, но есть пару мест...
Спасибо.

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

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2018
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.004 сек.) / Память: 4.75 Mb
Наверх