Гиперссылки в диалоговых окнах на Ассемблере

Создание текстовой гиперссылки в диалоговом окне, казалось бы, простая задача. Но дело в том, что в 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.
Теги:
Гиперссылка
Добавлено: 10 Апреля 2018 20:12:37 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...