Добавление иконки в SystemTray средствами Visual Basic
Эта статья является самодостаточной, то есть в ней дана исчерпывающая информация по созданию иконки в SystemTray с помощью VB. Однако при этом она является компиляцией общедоступных источников, то есть заслуга автора состоит лишь в сборе этой информации в одном месте и пояснениях.
Основы создания иконки изложены в FAQ Льва Серебрякова. Используется пример на VB от Alexander Shherbakov. Описания функций и констант из книги Daniel Applemana и API.TXT. Вопросы связанные с редактором ресурсов не рассматриваются.
Единственная функция для работы с иконкой Shell_NotifyIcon. Ее описание на VB выглядит так:
Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" _ (ByVal dwMessage As dwMess, lpData As NOTIFYICONDATA) As Long Возвращает ноль в случае ошибки Тип dwMess описывается так: Public Enum dwMess NIM_ADD = &H0 ' Добавление иконки NIM_DELETE = &H2 ' Удаление иконки NIM_MODIFY = &H1 ' Изменение параметров иконки End Enum Переменная dwMessage должна иметь одно из этих значений. Тип NOTIFYICONDATA имеет следующую структуру: Type NOTIFYICONDATA cbSize As Long ' Размер переменной типа NOTIFYICONDATA hwnd As Long ' Указатель окна создающего иконку uID As Long ' Указатель на иконку в пределах приложения uFlags As uF ' Маска для следующих параметров uCallbackMessage As CallMess ' Возвращаемое событие hIcon As Long ' Указатель на изображение для иконки szTip As String * 64 ' Всплывающий над иконкой текст End Type
Где тип uF имеет вид:
Public Enum uF NIF_MESSAGE = &H1 ' Значение имеет uCallbackMessage NIF_ICON = &H2 ' Значение имеет hIcon NIF_TIP = &H4 ' Значение имеет szTip End Enum
Эти константы можно применять в любых сочетаниях, для определения какой из параметров имеет значение.
Тип CallMess:
Public Enum CallMess WM_MOUSEMOVE = &H200 WM_LBUTTONDOWN = &H201 WM_LBUTTONUP = &H202 WM_LBUTTONDBLCLK = &H203 WM_RBUTTONDOWN = &H204 WM_RBUTTONUP = &H205 WM_RBUTTONDBLCLK = &H206 WM_MBUTTONDOWN = &H207 WM_MBUTTONUP = &H208 WM_MBUTTONDBLCLK = &H209 WM_SETFOCUS = &H7 WM_KEYDOWN = &H100 WM_KEYFIRST = &H100 WM_KEYLAST = &H108 WM_KEYUP = &H101 End Enum
Эти константы обозначают, какое событие возвращается вызывающей форме. Буквально, все, что будет происходить с иконкой, будет вызывать у формы одно из перечисленных событий. Ясно, что самое частое событие самой иконки это MouseMove, но для формы оно будет выглядеть как событие заданное переменной uCallbackMessage. Как же узнать, что в действительности произошло с иконкой? Это можно узнать через переменные X и Y событий MouseMove, MouseDown и MouseUp вызывающей формы. При этом Y, если событие произошло с иконкой, а не формой, всегда будет равно нулю, а X несет информацию о событии с иконкой.
О параметре X следует сказать отдельно. Действительно, он передает информацию о событиях с иконкой, однако эти значения зависят от масштабного коэффициента системного шрифта, но не напрямую, а через параметр свойства TwipsPerPixelX объекта Screen. То есть для одной и той же системы, при разных величинах системного шрифта, значения будут разными. Начальными значениями событий являются следующие:
MouseMove - 512
LeftButtonDown - 513
LeftButtonUp - 514
LeftButtonDblClick - 515
RightButtonDown - 516
RightButtonUp - 517
RightButtonDblClick - 518
Для того чтобы узнать действующие в данной системе значения их следует умножить на Screen.TwipsPerPixelX
Как же узнать, что событие произошло с иконкой, а не с формой? Просто, по значению Y, равному нулю. Но есть и другой способ, если используется двухкнопочная мышь то параметр Button в событиях MouseDown и MouseUp формы, будет принимать значения 1 и 2, и при uCallbackMessage равно WM_MBUTTONDOWN=&H207 или WM_MBUTTONUP = &H208 Button равен 4, если событие с иконкой. Само собой разумеется, что возвращаемые X значения следуют одно за другим, как и события (Down->Up->DbClick),поэтому невозможно на одну кнопку мыши назначить два события, к примеру, Click и DbClick. События не связанные с мышью не несут практически ни какой информации, и обычно не используются, следует так же отметить, что количество констант uCallbackMessage намного больше и здесь приведена лишь небольшая часть
Из описанного видно, что с иконкой можно совершить одно из следующих действий: добавить, модифицировать и удалить, при этом, модифицируя можно заменить возвращаемое событие, картинку (указатель при этом останется тем же) и всплывающую надпись (ToolTips).
Следующий момент, который нужно осветить это получение hIcon (указателя на картинку). Предполагается, что иконка будет находится в исполняемом файле или в DLL с ресурсами, но ни в коем случае не валяется в виде ICO файла. Если иконка запакована в DLL, то нам понадобятся две функции:
Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal _ lpLibFileName As String) As Long
Возвращающая hInstance библиотеки с именем lpLibFileName. Достаточно указать только имя файла с расширением, без пути. Возвращает ноль в случае ошибки
Declare Function LoadIconA Lib "user32" (ByVal hInstance As Long, ByVal _ lpIconName As String) As Long
Возвращающая hIcon для иконки указанной параметром lpIconName в библиотеке. Этот параметр может быть String или Long, в зависимости от данного вами наименования в Res файле, соответственно надо изменить декларацию. Можно передать и число как строку, для этого перед числом ставится знак #, а все это берется в кавычки. Следует заметить, что использование срокового параметра не желательно из за значительно большего размера занимаемой памяти и соответственно, большего времени на передачу параметра. Функция возвращает ноль в случае ошибки
Понадобится так же функция:
Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Выгружающая библиотеку из памяти. Параметр hLibModule это hInstanse, возвращаемое LoadLibrary. Возвращает ноль в случае ошибки.
Обязательно надо не забыть выгрузить из памяти библиотеку, для освобождения памяти. Выгрузку можно произвести сразу же после добавления иконки в SystemTray.
Обязательно надо не забыть выгрузить из памяти библиотеку, для освобождения памяти. Выгрузку можно произвести сразу же после добавления иконки в SystemTray.
Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" _ (ByVal lpModuleName As String) As Long
Возвращающей hInstanse нашего приложения. В качестве lpModuleName передается имя EXE файла с расширением. Следует быть внимательным, так как имя процесса в TaskMenager не всегда соответствует имени процесса для Windows. Я использую для определения имени DLLView, можно воспользоваться, встроенным в VB System Information. Функция возвращает действительное значение только при работе скомпилированного приложения, а в режиме отладки возвращает ноль, ведь реального процесса при отладке не существует. Свойство hInstanse объекта App всегда возвращает действительное значение, однако при отладке из за отсутствия процесса LoadIcon возвращает 0, и создается "пустая" иконка, тем не менее годная для отладки (реагирующая на все события).
Полученное hInstanse передаем LoadIconA, в качестве lpIconName указываем номер или имя иконки в Res файле, как и в случае с DLL. Выгружать в этом случае ничего не надо.
Создание иконки можно проиллюстрировать следующим примером.
Считается, что иконка с номером 101 находится в файле Project1.exe. Понятно, что пока мы его не скомпилировали, ее там нет (да и самого файла нет). Форма приложения называется Form1.
Dim NID As NOTIFYICONDATA Sub AddIcon() Dim IDLib As Long ' Указатель на библиотеку Dim IDIcon As Long ' Указатель на иконку Const IDMyIcon = 101 ' Идентификатор иконки внутри приложения Dim AddResult As Long ' Результат добавления иконки IDLib = GetModuleHandle("Project1.exe") ' Получаем hInstanse IDIcon = LoadIcon(IDLib, "#101") ' Получаем hIcon ' Заполняем структуру NID типа NOTIFYICONDATA NID.cbSize = Len(NID) ' Размер структуры NID.hwnd = Form1.hWnd ' Указатель на форму NID.uID = IDMyIcon ' Идентификатор иконки 'Указываем, что действующими являются поля NID.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP 'uCallBackMessage, hIcon и szTip. ' Указываем, что событием возвращаемым в форму NID.uCallbackMessage = WM_LBUTTONDOWN 'является MouseDown с параметром Button = 2 NID.hIcon = IDIcon ' Указатель на иконку в файле ' Передаем всплывающую фразу "MyIcon", при этом обрезаем NID.szTip = Left$("MyIcon", 63) & Chr(0) 'ее до 63 символов и добавляем 64-й символ с кодом ноль ' Вызываем функцию, через параметр dwMessage указываем, AddResult = Shell_NotifyIcon(NIM_ADD, NID) 'что следует добавить иконку, и передаем заполненный NID End Sub
Удаление созданной иконки можно сделать так:
Sub DeleteIcon() Dim DeletResult As Long DeleteResult = Shell_NotifyIcon(NIM_DELETE, NID) ' Вызываем функцию, через dwMessage указываем, 'что следует удалить иконку, при этом, раз переменная NID ' описана на уровне модуля, не следует 'заполнять ее заново End Sub
Размер структуры достаточно указывать один раз, так как за время жизни переменной он измениться не может, и в данном виде составляет 88 байт. Даже при изменении всплывающей строки ее длина (строки) не будет больше 64 байт.
Для модификации иконки надо вызвать Shell_NotifyIcon с параметром dwMessage равным NIM_MODIFY и NID с внесенными изменениями, при этом параметр uFlags будет указывать, какие из параметров изменены.
В форме Form1 для обработки, к примеру, DbClick левой кнопкой мыши по иконке можно применить следующий код:
Private Sub Form_MouseDown(Button As Integer, Shift As Integer _ X As Single, Y As Single) ' Событие MouseDown происходит не потому, 'что пользователь нажал на кнопку мыши над иконкой, а из-за того, 'что параметр uCallbackMessage имеет значение WM_LBUTTONDOWN If Y = 0 Then ' Y = 0 если событие с иконкой Select Case X Case 515*Screen.TwipsPerPixelX ' Значение X при LeftDblClick ' Код, выполняемый в случае LeftDblClick End Select End If End Sub
Оставить комментарий
Комментарии
hwnd окна закинул в иконку всетаки но реакции обратной нет?