Blog. Just Blog

Работа с окнами оповещений в трее на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Работа с окнами оповещений в трее на Ассемблере
Работа с окнами оповещений в трее на Ассемблере

Окно оповещения в системном трее, оно же System Tray Balloon Notification, - очень удобный инструмент для взаимодействия с пользователем и оповещения его о каких-либо событиях. Когда у меня возникла необходимость, в этих ваших интернетах нашлось не так много материалов по работе с такими оповещениями, а тем более на Ассемблере. Пришлось разбираться самому. Зато теперь я попробую хоть чуть-чуть восполнить этот пробел.

Как обычно, все начинается с описания большого количества констант, которые FASM в заводской комплектации не знает. Пока я ограничусь краткими комментариями, в дальнейшем по тексту значения и применение констант будут описаны более подробно.
  1. ; Стандартные иконки
  2. NIIF_NONE       = 0x00000000
  3. NIIF_INFO       = 0x00000001
  4. NIIF_WARNING    = 0x00000002
  5. NIIF_ERROR      = 0x00000003
  6. NIIF_USER       = 0x00000004
  7. ; Модификатор - не использовать звуковой сигнал
  8. NIIF_NOSOUND    = 0x00000010
  9. ; Модификатор для большой иконки
  10. NIIF_LARGE_ICON = 0x00000020
  11.  
  12. ; Уведомления от окна оповещения и подсказки
  13. NIN_BALLOONSHOW      = WM_USER + 2
  14. NIN_BALLOONHIDE      = WM_USER + 3
  15. NIN_BALLOONTIMEOUT   = WM_USER + 4
  16. NIN_BALLOONUSERCLICK = WM_USER + 5
  17. NIN_POPUPOPEN        = WM_USER + 6
  18. NIN_POPUPCLOSE       = WM_USER + 7
  19.  
  20. ; Дополнительные константы
  21. NOTIFYICON_VERSION_4 = 4
  22. NIF_REALTIME         = 0x00000040
  23. NIF_SHOWTIP          = 0x00000080
Основная работа выполняется через структуру NOTIFYICONDATA. В принципе, FASM ее знает, но только самую первую, базовую версию. Поэтому все равно придется определить структуру новой версии самостоятельно:
  1. ; Структура NOTIFYICONDATA версии 3
  2. struct _NOTIFYICONDATA
  3.         cbSize       dd ?
  4.         hWnd         dd ?
  5.         uID          dd ?
  6.         uFlags       dd ?
  7.         uCallbackMessage dd ?
  8.         hIcon        dd ?
  9.         szTip        rb 128
  10.         dwState      dd ?
  11.         dwStateMask  dd ?
  12.         szInfo       rb 256
  13.         uVersion     dd ?
  14.         szInfoTitle  rb 64
  15.         dwInfoFlags  dd ?
  16.         guidItem     rd 4
  17.         hBalloonIcon dd ?
  18. ends
Небольшое лирическое отступление. В статье часто используются термины "уведомление", причем, как правило, рядом, но в разном контексте. Вы должны понимать, что фраза "отправляет уведомление окну" подразумевает отправку notification message, а словосочетание "показывать уведомление" в значении "balloon notification" используется в локализованной версии Windows. Я очень надеюсь, что вы разберетесь.

Чтобы выводить уведомления, надо сперва добавить в системный трей иконку, к которой эти уведомления и будут привязаны. Делается это при помощи функции Shell_NotifyIcon. В любом руководстве по программированию наверняка найдется пример заполнения структуры NOTIFYICONDATA и вызова Shell_NotifyIcon. Здесь почти все то же самое, но с некоторыми дополнениями. Поле uVersion заполняется значением NOTIFYICON_VERSION_4, тем самым обозначая, что должны использоваться флаги и события, которые введены в систему, начиная с Windows Vista. Для того, чтобы этот флаг вступил в силу, после добавления иконки в трей надо сразу же вызвать Shell_NotifyIcon с параметром NIM_SETVERSION.
  1.         ; Заполнить структуру NOTIFYICONDATA
  2.         mov     [node.cbSize],sizeof._NOTIFYICONDATA
  3.         ; Хэндл окна-владельца иконки
  4.         mov     eax,[hwnddlg]
  5.         mov     [node.hWnd],eax
  6.         ; Идентификатор иконки
  7.         mov     [node.uID],IDI_TRAY
  8.         mov     [node.uFlags],\
  9.                 NIF_MESSAGE+NIF_INFO+NIF_TIP+NIF_ICON+NIF_SHOWTIP
  10.         ; Подсказка при наведении на иконку
  11.         invoke  lstrcpy,node.szTip,szIconTooltip
  12.         mov     [node.uCallbackMessage],WM_SHELLNOTIFY
  13.         ; Загрузить иконку для отображения в трее
  14.         invoke  LoadIcon,[hInstance],1
  15.         mov     [node.hIcon],eax
  16.         ; Версия обработчиков для Windows Vista и выше
  17.         mov     [node.uVersion],NOTIFYICON_VERSION_4
  18.         ; Добавить иконку в трей
  19.         invoke  Shell_NotifyIcon,NIM_ADD,node
  20.         ; Установить версию для Windows Vista и выше
  21.         invoke  Shell_NotifyIcon,NIM_SETVERSION,node
Отлично, иконка в трее создана. Теперь можно выводить уведомления. Начнем с самого простого уведомления - заголовок и текст с одной из стандартных системных иконок. Для этого поля szInfoTitle и szInfo заполняются, соответственно, строкой заголовка и текстом, который будет выведен в баллуне. Тип иконки задается в поле dwInfoFlags одним из стандартных значений, описанных в константах. По умолчанию используется маленькая иконка, а если надо показать большую, то к этому полю дополнительно применяется флаг-модификатор NIIF_LARGE_ICON. Если иконка вообще не нужна, то поле dwInfoFlags заполняется единственным значением NIIF_NONE.
  1.         ; Текст уведомления и заголовок
  2.         invoke  lstrcpy,node.szInfoTitle,szSystemHead
  3.         invoke  lstrcpy,node.szInfo,szSystemText
  4.         ; Задействовать стандартную иконку
  5.         ; Тип иконки - Информация, маленькая иконка
  6.         mov     [node.dwInfoFlags],NIIF_INFO
  7.         ; Перерисовать иконку в трее
  8.         invoke  Shell_NotifyIcon,NIM_MODIFY,node
Чуть более сложный пример - окно уведомления с нашей собственной иконкой. Поля szInfoTitle и szInfo заполняются аналогично предыдущему примеру, а вот поле dwInfoFlags заполняется комбинацией флагов NIIF_USER и NIIF_LARGE_ICON. Хэндл пользовательской иконки заносится в поле hBalloonIcon. Важно! Если для системных иконок можно было выбирать большой или маленький размер, то пользовательские иконки выводятся без вариантов только в размере 32х32 пиксела и флаг NIIF_LARGE_ICON в этом случае обязателен! Маленькие иконки будут растянуты, большие, соответственно, отмасштабированы. Если флаг NIIF_LARGE_ICON не указать, то окно уведомления вообще не появится, даже если все остальные поля NOTIFYICONDATA были заполнены правильно.
  1.         ; Текст уведомления и заголовок
  2.         invoke  lstrcpy,node.szInfoTitle,szUserHead
  3.         invoke  lstrcpy,node.szInfo,szUserText
  4.         ; Задействовать пользовательскую иконку
  5.         mov     [node.dwInfoFlags],NIIF_USER+NIIF_LARGE_ICON
  6.         invoke  LoadIcon, [hInstance],2
  7.         mov     [node.hBalloonIcon],eax
  8.         ; Перерисовать иконку в трее
  9.         invoke  Shell_NotifyIcon,NIM_MODIFY,node
С отображением окна уведомления разобрались. Но одного отображения обычно мало, нужна обратная связь от пользователя. Для этого иконка должна быть создана с флагом NIF_MESSAGE и установлены поля uCallbackMessage и uID. Если все сделано правильно, то система будет отправлять сообщения окну приложения, к которому приписана иконка в трее. Обработка выполняется примерно так:
  1.         ; Обработчик сообщений окна
  2.         ...
  3.         ; Поступило сообщение от иконки в трее
  4.         cmp     [msg],WM_SHELLNOTIFY
  5.         je      wmshellnotify
  6.         ...
  7. wmshellnotify:
  8.         ; Обработка действий с окном уведомления
  9.         cmp     [wparam],IDI_TRAY
  10.         jne     processed
  11.         ; Баллун отобразился на экране
  12.         cmp     [lparam],NIN_BALLOONSHOW
  13.         je      loc_balloonshow
  14.         ; Клик на баллуне
  15.         cmp     [lparam],NIN_BALLOONUSERCLICK
  16.         je      loc_balloonuserclick
  17.         ; Баллун скрыт по истечению времени или закрыт пользователем
  18.         cmp     [lparam],NIN_BALLOONTIMEOUT
  19.         je      loc_balloontimeout
  20.         ; Приложению запрещено выводить уведомления
  21.         cmp     [lparam],NIN_BALLOONHIDE
  22.         je      loc_balloonhide
  23.         ; Подсказка отображается на экране
  24.         cmp     [lparam],NIN_POPUPOPEN
  25.         je      loc_popupopen
  26.         ; Подсказка скрыта
  27.         cmp     [lparam],NIN_POPUPCLOSE
  28.         je      loc_popupclose
В wParam приходит идентификатор иконки, а в lParam - полученное уведомление. Ничего сложного, но есть несколько особенностей, о которых я сейчас расскажу поподробнее.

Основное уведомление, которое баллун отправляет окну-владельцу, это NIN_BALLOONSHOW. Оно отправляется сразу же, как только окно уведомления появится на экране.

Система Windows устроена таким образом, что одновременно может быть открыто только одно окно оповещения. Если несколько приложений одновременно пытаются вывести свои окна, то по умолчанию они выстраиваются в очередь и следующее уведомление отображается только когда предыдущее закрывается. В этом случае уведомление NIN_BALLOONSHOW приходит в момент фактического появления окна. Если для приложения важно, чтобы уведомление отображало мгновенные события, его надо отображать с установленным флагом NIF_REALTIME в поле uFlags. Такое уведомление или отобразится мгновенно, если очередь не занята, или не отобразится никогда, если какое-то окно с уведомлением уже открыто. Хороший пример из документации - информирование о входящем звонке. Вряд ли кому-то будет интересно получить сообщение типа "вам звонят", когда фактически звонок уже давно закончился, но очередь до этого сообщения еще не дошла. Вы можете поэкспериментировать с очередью, запустив одновременно несколько копий тестовой программы и открыв из каждой несколько уведомлений.

Уведомление NIN_BALLOONHIDE приходит в том случае, если на уровне системы приложению запрещено выводить уведомления. Также оно отправляется, если в трее уже открыто какое-либо окно уведомления, а приложение пытается добавить свое окно с установленным флагом NIF_REALTIME в поле uFlags. В большинстве случаев это уведомление можно приравнивать к ситуации, когда баллун был просто закрыт. А если, например, надо обязательно уведомить пользователя о каком-то важном событии, то приложение может продублировать информацию через MessageBox или иным способом.

Когда поле uVersion имеет значение NOTIFYICON_VERSION_4, то есть используется система Windows Vista и выше, окно приложения получает дополнительные системные уведомления: NIN_POPUPOPEN и NIN_POPUPCLOSE. Для этого поле uFlags обязательно надо дополнить флагом NIF_SHOWTIP. Уведомление NIN_POPUPOPEN приходит когда курсор мыши наведен на иконку приложения в трее и появилась подсказка (текст из поля szTip). Когда курсор мыши выходит за пределы иконки и подсказка скрывается, приложению отправляется уведомление NIN_POPUPCLOSE. Оба уведомления передаются независимо от состояния и наличия окна оповещения. Затрудняюсь сказать, где на практике это можно использовать, но знать это будет полезно. Для совместимости с Windows XP в поле uVersion надо заносить нулевое значение, но тогда уведомления NIN_POPUPOPEN и NIN_POPUPCLOSE будут недоступны. Невелика потеря.

Уведомление NIN_BALLOONUSERCLICK приходит, когда пользователь кликнул на само окно, например, когда ему о чем-то сообщают и предлагают выполнить какое-нибудь действие на основании этой информации. После клика окно уведомления закрывается, но каких-либо других уведомлений о закрытии баллуна родительскому окну больше не поступает. Это же сообщение отправляется, если кликнуть на иконке в трее при открытом окне уведомления.

Кроме этого, баллун может быть закрыт принудительно кликом на "крестик" или по истечении времени, отведенного системой на показ всплывающих уведомлений. В обоих случаях родительскому окну отправляется уведомление NIN_BALLOONTIMEOUT. На мой взгляд логичней было бы разделить эти два события, они все-таки не равноценны, но разработчики Windows посчитали иначе.

В приложении пример программы с исходным текстом, которая выводит баллуны с пользовательской или стандартной иконкой и обрабатывает поступающие от них сообщения. Из-за описанных выше особенностей реализации, тестовая программа работоспособна на Windows Vista и выше.

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

Balloon.Demo.zip (7,054 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

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

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

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