Blog. Just Blog

Обработка изменения иконок в системном трее

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
С обновлением иконок в системном трее разобрались, теперь давайте разберем, как можно отслеживать изменения в трее. Причем изменения касаются не только добавления-удаления иконок, но также изменения всплывающих подсказок и изменения иконки с сохранением ее индекса.
  1. CLSCTX_LOCAL_SERVER = 0x04
  2. S_OK = 0
  3.  
  4. struct NOTIFYITEM
  5.     pszExeName   dd ?
  6.     pszTip       dd ?
  7.     hIcon        dd ?
  8.     hWnd         dd ?
  9.     dwPreference dd ?
  10.     uID          dd ?
  11.     guidItem     rd 4
  12. ends
  13.  
  14. ; GUID {D782CCBA-AFB0-43F1-94DB-FDA3779EACCB}
  15. IID_INotificationCB dd 0D782CCBAh
  16.                     dw 0AFB0h
  17.                     dw 043F1h
  18.                     db 094h, 0DBh, 0FDh, 0A3h, 077h, 09Eh, 0ACh, 0CBh
  19.  
  20. ; INotificationCB interface
  21. struct INotificationCB
  22.         QueryInterface dd ?
  23.         AddRef         dd ?
  24.         Release        dd ?
  25.         ; INotificationCB
  26.         Notify         dd ?
  27. ends
  28.  
  29. ; GUID {FB852B2C-6BAD-4605-9551-F15F87830935}
  30. IID_ITrayNotify dd 0FB852B2Ch
  31.                 dw 06BADh
  32.                 dw 04605h
  33.                 db 095h, 051h, 0F1h, 05Fh, 087h, 083h, 009h, 035h
  34.  
  35. ; ITrayNotify interface
  36. struct ITrayNotify
  37.         QueryInterface   dd ?
  38.         AddRef           dd ?
  39.         Release          dd ?
  40.         ; ITrayNotify
  41.         RegisterCallback dd ?
  42.         SetPreference    dd ?
  43.         EnableAutoTray   dd ?
  44. ends
  45.  
  46. ; GUID {25DEAD04-1EAC-4911-9E3A-AD0A4AB560FD}
  47. CLSID_TrayNotify dd 025DEAD04h
  48.                  dw 01EACh
  49.                  dw 04911h
  50.                  db 09Eh, 03Ah, 0ADh, 00Ah, 04Ah, 0B5h, 060h, 0FDh
  51.  
  52. ; GUID {00000000-0000-0000-C000-000000000046}
  53. IID_IUnknown dd 000000000h
  54.              dw 00000h
  55.              dw 00000h
  56.              db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
Практически все, что тут используется, относится к недокументированным функциям Windows, поэтому внимательно смотрите примеры и описания. И да, работает оно только на современных системах, начиная с Windows Vista.

Для отслеживания изменений в системном трее создается COM-объект TrayNotify, затем заполняется структура INotificationCB для callback-обработчика, после чего через метод RegisterCallback этот обработчик активируется.
  1.         ; Создать объект
  2.         invoke  CoCreateInstance,CLSID_TrayNotify,NULL,\
  3.                 CLSCTX_LOCAL_SERVER,IID_ITrayNotify,pTrNotDisp
  4.         cmp     eax,S_OK
  5.         jne     wmclose
  6.  
  7.         ; Настроить структуру INotificationCB
  8.         mov     [NCallBack.QueryInterface],CallBack_QueryInterface
  9.         mov     [NCallBack.AddRef],CallBack_AddRef
  10.         mov     [NCallBack.Release],CallBack_Release
  11.         mov     [NCallBack.Notify],CallBack_Notify
  12.  
  13.         mov     eax,NCallBack
  14.         mov     [pNCallBack],eax
  15.  
  16.         ; Установить callback-функцию
  17.         mov     eax,[pTrNotDisp]
  18.         mov     eax,[eax]
  19.         stdcall dword [eax+ITrayNotify.RegisterCallback],\
  20.                 [pTrNotDisp],pNCallBack
На методы AddRef и Release ставятся заглушки, а вот метод QueryInterface должен проверять из какого интерфейса он был вызван и возвращать правильный результат. Callback-функция описывается, как в приведенном примере.
  1. ;------------------------------------------------------------------
  2. ; Метод QueryInterface интерфейса IUnknown / INotificationCB
  3. ;------------------------------------------------------------------
  4. proc CallBack_QueryInterface pthis:DWORD, iid:DWORD, ppvObject:DWORD
  5.         pusha
  6.  
  7.         mov     eax,[ppvObject]
  8.         cmp     eax,0
  9.         jne     @f
  10.         ; E_POINTER
  11.         mov     eax,0x80004003
  12.         jmp     .loc_ret
  13. @@:
  14.         ; Это интерфейс INotificationCB?
  15.         push    4
  16.         pop     ecx
  17.         mov     esi,[iid]
  18.         mov     edi,IID_INotificationCB
  19.         xor     eax,eax
  20.         repe    cmpsd
  21.         jz      .loc_call
  22.  
  23.         ; Это интерфейс IUnknown?
  24.         push    4
  25.         pop     ecx
  26.         mov     esi,[iid]
  27.         mov     edi,IID_IUnknown
  28.         xor     eax,eax
  29.         repe    cmpsd
  30.         jz      .loc_call
  31.  
  32.         ; E_NOINTERFACE
  33.         mov     eax,0x80004002
  34.         jmp     .loc_ret
  35. .loc_call:
  36.         mov     eax,[pthis]
  37.         ; Установить интерфейс
  38.         mov     ecx,[ppvObject]
  39.         mov     [ecx],eax
  40.         mov     ecx,[eax]
  41.         stdcall dword [ecx+INotificationCB.AddRef],eax
  42. .loc_ok:
  43.         ; S_OK
  44.         xor     eax,eax
  45. .loc_ret:
  46.         mov     [esp+28],eax
  47.         popa
  48.         ret
  49. endp
  50.  
  51. ;------------------------------------------------------------------
  52. ; Заглушка для INotificationCB::AddRef
  53. ;------------------------------------------------------------------
  54. proc CallBack_AddRef pthis:DWORD
  55.         mov     eax,1
  56.         ret
  57. endp
  58.  
  59. ;------------------------------------------------------------------
  60. ; Заглушка для INotificationCB::Release
  61. ;------------------------------------------------------------------
  62. proc CallBack_Release pthis:DWORD
  63.         mov     eax,1
  64.         ret
  65. endp
  66.  
  67. ;------------------------------------------------------------------
  68. ; Callback-функция для получения уведомлений об изменении трея
  69. ;------------------------------------------------------------------
  70. proc CallBack_Notify pthis:DWORD, Event:DWORD, pItem:DWORD
  71.         ; [Event] -> тип события: иконка добавлена, удалена, изменена
  72.  
  73.         ; Указатель на структуру NOTIFYITEM
  74.         mov     ebx,[pItem]
  75.  
  76.         ...
  77.         ; Действия с иконкой
  78.         ...
  79.  
  80.         ; S_OK
  81.         xor     eax,eax
  82.         ret
  83. endp
При вызове callback-функции в параметре Event ей передается тип произошедшего события (0 - иконка добавлена, 1 - иконка изменена, 2 - иконка удалена), а также указатель на структуру NOTIFYITEM, в которой содержится вся полезная информация: pszExeName - имя исполняемого файла-владельца иконки, pszTip - текст подсказки, hIcon - хэндл изображения иконки, hWnd - хэндл окна-владельца иконки, dwPreference - режим отображения иконки (0 - скрывать если неактивно, 1 - всегда прятать, 2 - всегда показывать), uID - индекс иконки, guidItem - GUID иконки.

По результатам тестов выяснились интересные особенности. Например, удаленные ранее иконки тоже могут попадать в обработчик, отловить их можно по невалидному хэндлу окна, а удалить по индексу, как при принудительном обновлении иконок. Имена исполняемых файлов могут передаваться в привычном виде, но если файл расположен в одной из папок, относящихся к стандартным папкам Windows, часть пути будет представлена в виде идентификатора KNOWNFOLDERID. Что-то типа {D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27}\taskmgr.exe. Как превратить такие ссылки в нормальный путь я подробно рассказал в этой статье.

Еще одно важное замечание. Если включен UAC, а процесс, который отслеживает изменения в трее, имеет повышенные привилегии (запущено от имени Администратора), то при попытке создать объект TrayNotify будет возвращена ошибка "Class not registered". Такое поведение наблюдается по крайней мере в Windows 7. Это связано с тем, что обработчик трея и оболочка имеют разные уровни контроля целостности, а приложение с большим уровнем контроля не может принимать сообщения от приложения с меньшим уровнем и наоборот.

В приложении пример программы с исходным текстом, которая отслеживает все изменения в системном трее и выводит их в лог.

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

Tray.Notification.Demo.zip (4,757 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
Василий (09.02.2022 в 20:59):
Очень пригодилось спасибо))) Набросал прогу для клиента mega.nz, чтобы при остановке закачки меняла айпишник и качала дальше)))

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

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

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