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

Работа с окнами оповещений в трее на Ассемблере
Окно оповещения в системном трее, оно же System Tray Balloon Notification, - очень удобный инструмент для взаимодействия с пользователем и оповещения его о каких-либо событиях. Когда у меня возникла необходимость, в этих ваших интернетах нашлось не так много материалов по работе с такими оповещениями, а тем более на Ассемблере. Пришлось разбираться самому. Зато теперь я попробую хоть чуть-чуть восполнить этот пробел.
Как обычно, все начинается с описания большого количества констант, которые FASM в заводской комплектации не знает. Пока я ограничусь краткими комментариями, в дальнейшем по тексту значения и применение констант будут описаны более подробно.
Code (Assembler) : Убрать нумерацию
- ; Стандартные иконки
- NIIF_NONE = 0x00000000
- NIIF_INFO = 0x00000001
- NIIF_WARNING = 0x00000002
- NIIF_ERROR = 0x00000003
- NIIF_USER = 0x00000004
- ; Модификатор - не использовать звуковой сигнал
- NIIF_NOSOUND = 0x00000010
- ; Модификатор для большой иконки
- NIIF_LARGE_ICON = 0x00000020
- ; Уведомления от окна оповещения и подсказки
- NIN_BALLOONSHOW = WM_USER + 2
- NIN_BALLOONHIDE = WM_USER + 3
- NIN_BALLOONTIMEOUT = WM_USER + 4
- NIN_BALLOONUSERCLICK = WM_USER + 5
- NIN_POPUPOPEN = WM_USER + 6
- NIN_POPUPCLOSE = WM_USER + 7
- ; Дополнительные константы
- NOTIFYICON_VERSION_4 = 4
- NIF_REALTIME = 0x00000040
- NIF_SHOWTIP = 0x00000080
Code (Assembler) : Убрать нумерацию
- ; Структура NOTIFYICONDATA версии 3
- struct _NOTIFYICONDATA
- cbSize dd ?
- hWnd dd ?
- uID dd ?
- uFlags dd ?
- uCallbackMessage dd ?
- hIcon dd ?
- szTip rb 128
- dwState dd ?
- dwStateMask dd ?
- szInfo rb 256
- uVersion dd ?
- szInfoTitle rb 64
- dwInfoFlags dd ?
- guidItem rd 4
- hBalloonIcon dd ?
- ends
Чтобы выводить уведомления, надо сперва добавить в системный трей иконку, к которой эти уведомления и будут привязаны. Делается это при помощи функции Shell_NotifyIcon. В любом руководстве по программированию наверняка найдется пример заполнения структуры NOTIFYICONDATA и вызова Shell_NotifyIcon. Здесь почти все то же самое, но с некоторыми дополнениями. Поле uVersion заполняется значением NOTIFYICON_VERSION_4, тем самым обозначая, что должны использоваться флаги и события, которые введены в систему, начиная с Windows Vista. Для того, чтобы этот флаг вступил в силу, после добавления иконки в трей надо сразу же вызвать Shell_NotifyIcon с параметром NIM_SETVERSION.
Code (Assembler) : Убрать нумерацию
- ; Заполнить структуру NOTIFYICONDATA
- mov [node.cbSize],sizeof._NOTIFYICONDATA
- ; Хэндл окна-владельца иконки
- mov eax,[hwnddlg]
- mov [node.hWnd],eax
- ; Идентификатор иконки
- mov [node.uID],IDI_TRAY
- mov [node.uFlags],\
- NIF_MESSAGE+NIF_INFO+NIF_TIP+NIF_ICON+NIF_SHOWTIP
- ; Подсказка при наведении на иконку
- invoke lstrcpy,node.szTip,szIconTooltip
- mov [node.uCallbackMessage],WM_SHELLNOTIFY
- ; Загрузить иконку для отображения в трее
- invoke LoadIcon,[hInstance],1
- mov [node.hIcon],eax
- ; Версия обработчиков для Windows Vista и выше
- mov [node.uVersion],NOTIFYICON_VERSION_4
- ; Добавить иконку в трей
- invoke Shell_NotifyIcon,NIM_ADD,node
- ; Установить версию для Windows Vista и выше
- invoke Shell_NotifyIcon,NIM_SETVERSION,node
Code (Assembler) : Убрать нумерацию
- ; Текст уведомления и заголовок
- invoke lstrcpy,node.szInfoTitle,szSystemHead
- invoke lstrcpy,node.szInfo,szSystemText
- ; Задействовать стандартную иконку
- ; Тип иконки - Информация, маленькая иконка
- mov [node.dwInfoFlags],NIIF_INFO
- ; Перерисовать иконку в трее
- invoke Shell_NotifyIcon,NIM_MODIFY,node
Code (Assembler) : Убрать нумерацию
- ; Текст уведомления и заголовок
- invoke lstrcpy,node.szInfoTitle,szUserHead
- invoke lstrcpy,node.szInfo,szUserText
- ; Задействовать пользовательскую иконку
- mov [node.dwInfoFlags],NIIF_USER+NIIF_LARGE_ICON
- invoke LoadIcon, [hInstance],2
- mov [node.hBalloonIcon],eax
- ; Перерисовать иконку в трее
- invoke Shell_NotifyIcon,NIM_MODIFY,node
Code (Assembler) : Убрать нумерацию
- ; Обработчик сообщений окна
- ...
- ; Поступило сообщение от иконки в трее
- cmp [msg],WM_SHELLNOTIFY
- je wmshellnotify
- ...
- wmshellnotify:
- ; Обработка действий с окном уведомления
- cmp [wparam],IDI_TRAY
- jne processed
- ; Баллун отобразился на экране
- cmp [lparam],NIN_BALLOONSHOW
- je loc_balloonshow
- ; Клик на баллуне
- cmp [lparam],NIN_BALLOONUSERCLICK
- je loc_balloonuserclick
- ; Баллун скрыт по истечению времени или закрыт пользователем
- cmp [lparam],NIN_BALLOONTIMEOUT
- je loc_balloontimeout
- ; Приложению запрещено выводить уведомления
- cmp [lparam],NIN_BALLOONHIDE
- je loc_balloonhide
- ; Подсказка отображается на экране
- cmp [lparam],NIN_POPUPOPEN
- je loc_popupopen
- ; Подсказка скрыта
- cmp [lparam],NIN_POPUPCLOSE
- je loc_popupclose
Основное уведомление, которое баллун отправляет окну-владельцу, это 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 и выше.
Просмотров: 2340 | Комментариев: 0

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

Добавить комментарий
Заполните форму для добавления комментария
