Создание текстовой гиперссылки в диалоговом окне, казалось бы, простая задача. Но дело в том, что в Windows по умолчанию нет элементов диалоговых окон, которые бы выполняли роль гиперссылки. Готовых решений на FASM тоже не нашлось, значит придется создавать такой элемент самостоятельно. Сперва определимся с задачами, что нам надо сделать. Должен получиться элемент диалогового окна в виде текста определенного цвета, при наведении на который курсор должен менять свою форму, а цвет изменяться на подсвеченный. При клике на такой элемент должна открываться заданная ссылка. Задачи ясны, начнем их решать. Сперва выберем элемент диалоговых окон из списка стандартных, который и будет использоваться в качестве гиперссылки. Сразу же приходит на ум STATIC. По умолчанию элемент класса STATIC полностью оправдывает свое название и не реагирует практически ни на какие сообщения. Чтобы STATIC принимал движение курсора и нажатия клавиш мышки, его надо описать в ресурсах с флагом стилей SS_NOTIFY.
А как отследить движение курсора только над нашей гипессылкой? Тут нам на помощь придет такая полезная вещь, как субклассирование. Суть субклассирования проста. С каждым окном связан указатель на оконную процедуру, которая обрабатывает сообщения Windows. Когда система получает сообщение, предназначенное для некоторого окна, она находит адрес оконной процедуры этого окна и вызывает ее. При субклассировании мы заменяем эту процедуру нашей и сохраняем указатель на старую процедуру, чтобы можно было передать ей сообщения для дальнейшей обработки. Это делается функцией
SetWindowLong с индексом GWL_WNDPROC на этапе инициализации главного окна:
...
; Получить хэндл нашего STATIC'а
invoke GetDlgItem,[hwnddlg],ID_LINK
; Субклассировать гиперссылку и установить собственный
; обработчик для STATIC'а
invoke SetWindowLong,eax,GWL_WNDPROC,WindowProc
; Сохранить адрес предыдущего обработчика
mov [OldWndProc],eax
...
Теперь напишем процедуру обработки. Тут важно понять основной принцип: при сообщениях, которые мы подавляем или обрабатываем самостоятельно, процедура должна возвращать FALSE, как будто бы их вообще не было. Если сообщение не обрабатывается или оно было модифицировано нашим обработчиком, то его обязательно надо передавать функцией
CallWindowProc предыдущему обработчику, адрес которого сохранен при субклассировании. Это можно посмотреть на примере обработчика нашей гиперссылки.
;------------------------------------------------------------
; Наша собственная процедура обработки дочернего окна STATIC
;------------------------------------------------------------
proc WindowProc hwnddlg:DWORD,msg:DWORD,wparam:DWORD,lparam:DWORD
cmp [msg],WM_SETCURSOR ; Курсор над ссылкой
je .cursor_over_hyperlink
cmp [msg],WM_LBUTTONDOWN ; Нажатие мышкой на ссылке
je .open_link
; Передать управление предыдущему обработчику
invoke CallWindowProc,[OldWndProc],[hwnddlg],[msg],[wparam],[lparam]
ret
.cursor_over_hyperlink:
; Загрузить и установить курсор в виде руки
invoke LoadCursor,0,IDC_HAND
invoke SetCursor,eax
jmp .finish
.open_link:
; Открыть ссылку
invoke ShellExecute,[hwnddlg],szOpen,szLink,NULL,NULL,SW_SHOW
.finish:
xor eax,eax
ret
szOpen db 'open',0 ; Команда открытия
szLink db 'http://www.manhunter.ru',0 ; Ссылка на сайт
endp
Обрабатывается движение курсора над элементом и клик по нему левой кнопкой мыши. Все остальные сообщения без изменения передаются сохраненному предыдущему обработчику. Оставим реализацию гиперссылки через элемент STATIC на этом этапе и выберем для следующего примера какой-нибудь другой. Пусть это будет элемент класса EDIT. В сегменте данных добавляются новые переменные:
section '.data' data readable writeable
hHyper dd ? ; Хэндл гиперссылки
hBrushBack dd ? ; Хэндл кисточки
sscolor dd ? ; Цвет закраски
clrMain = 0FF0000h ; Обычный цвет ссылки (синий)
clrActive = 00000FFh ; Цвет активной ссылки (красный)
В инициализацию главного окна добавляется следующий код:
Code (Assembler) : Убрать нумерацию
...
; Получить хэндл кисточки основного цвета окна
invoke GetSysColor,COLOR_BTNFACE
invoke CreateSolidBrush,eax
mov [hBrushBack],eax
; Установить обычный цвет гиперссылки
mov [sscolor],clrMain
; Получить хэндл нашего EDIT'а
invoke GetDlgItem,[hwnddlg],ID_LINK
mov [hHyper],eax
...
Хэндл кисточки основного цвета окна нужен для отрисовки фонового цвета EDIT. Цвет элемента устанавливается по сообщению WM_CTLCOLOREDIT, но в обработчике надо обрабатывать только наш EDIT, остальные пропускать:
...
cmp [msg],WM_CTLCOLOREDIT
je .set_color_edit
...
.set_color_edit:
; Обрабатывается наш EDIT?
mov eax,[hHyper]
cmp [lparam],eax
je @f
; Нет, пропустить
xor eax,eax
jmp .finish
@@:
; Установить цвет текста ссылки
invoke SetTextColor,[wparam],[sscolor]
; Установить режим заднего фона на прозрачный
invoke SetBkMode,[wparam],TRANSPARENT
; Установить цвет EDIT как основной цвет окна
mov eax,[hBrushBack]
jmp .finish
В обработчике субклассированного элемента добавляется изменение цвета при наведении курсора на ссылку. Обновление и перерисовка гиперссылки с новым цветом выполняется функцией
InvalidateRect, но сама обработка перерисовки выполняется в главном окне.
;------------------------------------------------------------
; Наша собственная процедура обработки дочернего окна EDIT
;------------------------------------------------------------
proc WindowProc hwnddlg:DWORD,msg:DWORD,wparam:DWORD,lparam:DWORD
cmp [msg],WM_SETCURSOR ; Курсор над ссылкой
je .cursor_over_hyperlink
cmp [msg],WM_LBUTTONDOWN ; Нажатие мышкой на ссылке
je .open_link
; Передать управление предыдущему обработчику
invoke CallWindowProc,[OldWndProc],[hwnddlg],[msg],[wparam],[lparam]
ret
.cursor_over_hyperlink:
; Загрузить и установить курсор в виде руки
invoke LoadCursor,0,IDC_HAND
invoke SetCursor,eax
; Установить цвет текста ссылки
mov [sscolor],clrActive
; Перерисовать EDIT в новом цвете
invoke InvalidateRect,[hHyper],NULL,TRUE
jmp .finish
.open_link:
; Открыть ссылку
invoke ShellExecute,[hwnddlg],szOpen,szLink,NULL,NULL,SW_SHOW
; Установить цвет текста ссылки
mov [sscolor],clrMain
; Перерисовать EDIT в новом цвете
invoke InvalidateRect,[hHyper],NULL,TRUE
.finish:
xor eax,eax
ret
szOpen db 'open',0 ; Команда открытия
szLink db 'http://www.manhunter.ru',0 ; Ссылка на сайт
endp
Когда курсор выходит за границы гиперссылки, надо возвращать ее цвет в исходный. Это придется выполнять в главном окне, обрабатывая движение курсора над ним.
UPD: Тут камрад Zummenix подсказал как корректно сделать STATIC цветным. Спасибо! Перезалил примеры, статью править пока не буду.
Есть еще варианты создания гиперссылки в диалоговых окнах через RichEdit, внедренный HTML и всякие посторонние компоненты, но они тут рассматриваться не будут. В приложении два примера диалоговых окон с текстовой гиперссылкой, реализованной через элементы классов STATIC и EDIT.