Поле EDIT для ввода шестнадцатеричных цифр
Поле для ввода только цифр организовать несложно, для этого достаточно просто прописать в ресурсах у нужного поля флаг ES_NUMBER. После этого с клавиатуры в это поле можно будет ввести только символ из интервала "0" - "9". Впрочем этот ничуть не мешает через Ctrl+C / Ctrl+V затолкать в него все что угодно, вплоть до непечатных бинарных данных. А как сделать поле, в которое можно вводить с клавиатуры только шестнадцатеричные цифры? Ведь там могут быть не только символы с десятичными цифрами, но и символы "A" - "F", которые также являются шестнадцатеричными цифрами. Это делается через субклассирование. Мы уже рассмотрели один пример субклассирования, превратив поле EDIT в гиперссылку, и там же определили алгоритм обработчика субклассированного элемента. Как и в прошлый раз, субклассирование должно выполняться на этапе инициализации диалогового окна.Code (Assembler) : Убрать нумерацию
- ; Сегмент данных
- section '.data' data readable writeable
- OldProc dd ? ; Адрес предыдущего обработчика
- ; Сегмент кода
- section '.code' code readable executable
- ...
- ; Субклассирование на этапе инициализации окна
- invoke GetDlgItem,[hwnddlg],ID_HEX
- ; Установить наш собственный обработчик
- invoke SetWindowLong,eax,GWL_WNDPROC,EditWindowProc
- ; Сохранить хэндл предыдущего обработчика
- mov [OldProc],eax
- ...
Назначенная процедура EditWindowProc будет обрабатывать только одно сообщение: WM_CHAR, оно происходит при нажатии на любую клавишу, когда курсор находится в нашем поле EDIT. При фильтрации нажатых клавиш, кроме шестнадцатеричных цифр не забывайте про служебные комбинации Ctrl+C / Ctrl+V / Ctrl+X и клавишу Backspace. Все остальные клавиши фильтруются и блокируются. Похожий пример на MASM был показан в одном из уроков Iczelion'а, но в нем не учитывались клавиши копирования-вставки, а также функции вставки данных в поле ввода.
Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------
- ; Субклассированный обработчик
- ;------------------------------------------------
- proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
- ; Нажатие клавиши?
- cmp [uMsg],WM_CHAR
- je .chk_char
- ; Вставка?
- cmp [uMsg],WM_PASTE
- jne .char_ok
- .loc_paste:
- ; Получить формат буфера обмена
- invoke IsClipboardFormatAvailable,CF_TEXT
- or eax,eax
- jz .exit_proc
- ; Получить хэндл родительского окна
- invoke GetParent,[hEdit]
- ; Открыть буфер обмена
- invoke OpenClipboard,eax
- invoke GetClipboardData,CF_TEXT
- mov ebx,eax
- invoke GlobalLock,eax
- ; Поочередно передать все символы из буфера обмена
- mov esi,eax
- @@:
- lodsb
- or al,al
- jz @f
- movzx eax,al
- invoke SendMessage,[hEdit],WM_CHAR,eax,0
- jmp @b
- @@:
- ; Закрыть буфер обмена
- invoke GlobalUnlock,ebx
- invoke CloseClipboard
- jmp .exit_proc
- .char_ok:
- ; Передать управление предыдущему обработчику или пропустить
- ; разрешенный символ
- invoke CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
- ret
- .chk_char:
- ; Проверить код нажатой клавиши
- mov eax,[wParam]
- cmp al,VK_BACK ; Backspace
- je .char_ok
- cmp al,22 ; Ctrl+V
- je .loc_paste
- cmp al,3 ; Ctrl+C
- je .char_ok
- cmp al,24 ; Ctrl+X
- je .char_ok
- cmp al,'0' ; Hex-цифра
- jb .exit_proc
- cmp al,'9'
- jbe .char_ok
- or al,20h
- cmp al,'a'
- jb .exit_proc
- cmp al,'f'
- jbe .char_ok
- .exit_proc:
- ; Подавить сообщение нажатия клавиши и вернуть из обработчика FALSE
- xor eax,eax
- ret
- endp
В приложении пример диалогового окна с двумя полями ввода. Одно имеет стандартный флаг ES_NUMBER для ввода десятичных цифр, второе реализовано через субкласирование и позволяет вводить только шестнадцатеричные цифры.
Просмотров: 6262 | Комментариев: 9
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(27.02.2020 в 18:00):
Учел все недостатки, полностью перекроил код обработчика. Теперь вставка обрабатывается корректно. Архив и статья обновлены.
brute
(04.01.2012 в 10:53):
у меня теория - сплошной пробел! (пытаюсь писать на PB - это тот же fasm)
1.Посмотрел примеров 20 с wasma, и ничего не понял! Где-то при сабклассинге правят значения wParam/lParam; где-то значения eax/ebx - это зависит от типа сообщений? (например, при наезде мышкой на button WM_MOUSEMOVE в ebx - хендл buttona?) Что почитать?
2. Обычное окно (созданное через Wldclass) обрабатыает msg=WM_CTLCOLOREDIT в основном цикле сообщений - без сабклассинга, меняя цвет вводимого через SetTextColor. А диалоговое окно не реагирует на это сообщение!!! (контол EDIT создавал и в ресурсах и через CreateWinowEX).
3. Где должна быть CallWindowProc - в новой процедуре или в цикле старой? С WM_SETCURSOR и сменой формы курсора работает по любому. (с другими сообщениями не работает никак)
4. Зачем нужен сабклассинг? Чтобы научить контрол обрабатывать сообщения, которые он не обрабатывает по умолчанию? Где должна происходить смена свойств контрола (в основной процедуре окна или в новой?)
5. как (правильно и вообще) работать с нотификационными сообщениями, когда они посылаются?
1.Посмотрел примеров 20 с wasma, и ничего не понял! Где-то при сабклассинге правят значения wParam/lParam; где-то значения eax/ebx - это зависит от типа сообщений? (например, при наезде мышкой на button WM_MOUSEMOVE в ebx - хендл buttona?) Что почитать?
2. Обычное окно (созданное через Wldclass) обрабатыает msg=WM_CTLCOLOREDIT в основном цикле сообщений - без сабклассинга, меняя цвет вводимого через SetTextColor. А диалоговое окно не реагирует на это сообщение!!! (контол EDIT создавал и в ресурсах и через CreateWinowEX).
3. Где должна быть CallWindowProc - в новой процедуре или в цикле старой? С WM_SETCURSOR и сменой формы курсора работает по любому. (с другими сообщениями не работает никак)
4. Зачем нужен сабклассинг? Чтобы научить контрол обрабатывать сообщения, которые он не обрабатывает по умолчанию? Где должна происходить смена свойств контрола (в основной процедуре окна или в новой?)
5. как (правильно и вообще) работать с нотификационными сообщениями, когда они посылаются?
brute
(02.01.2012 в 22:12):
-файл закрывается при нажатии ENTER (почему?)
-нет на форме кнопки ОК с IDOK (в коде есть)
-"никакое субклассирование не спасает от копирования и вставки данных в поле EDIT" - если не обрабатывать Ctrl+C/Ctrl+V, то спасает (см. аттач)
-в уроке 20Iczelion'а, в CallWindowProc возвращают eax вместо wParam. Почему здесь не так?
- не получается сабклассировать гиперссылку (её цвет) - переписываю для разнообразия и обучения примеры на PB (hiperlink.pb - в аттаче)- может, советом поможешь?:^);
- во всех примерах трудно разобраться из-за кучи джампов (с if-elseif обработка сообщений была бы нагляднее) приходится две страницы постоянно скролить вверх-вниз
http://www.fayloobmennik.net/1360934
-нет на форме кнопки ОК с IDOK (в коде есть)
-"никакое субклассирование не спасает от копирования и вставки данных в поле EDIT" - если не обрабатывать Ctrl+C/Ctrl+V, то спасает (см. аттач)
-в уроке 20Iczelion'а, в CallWindowProc возвращают eax вместо wParam. Почему здесь не так?
- не получается сабклассировать гиперссылку (её цвет) - переписываю для разнообразия и обучения примеры на PB (hiperlink.pb - в аттаче)- может, советом поможешь?:^);
- во всех примерах трудно разобраться из-за кучи джампов (с if-elseif обработка сообщений была бы нагляднее) приходится две страницы постоянно скролить вверх-вниз
http://www.fayloobmennik.net/1360934
ManHunter
(29.12.2010 в 08:53):
Кстати, было бы еще неплохо проверить на юникод. По идее проблем быть не должно, но все-таки многобайтные символы передаются по одному байту.
Pretorian
(28.12.2010 в 23:10):
Хотя лучше добавить еще проверку на Lower Case (так как иногда некорректно срабатывает при вставке текста), т.е.
…
cmp al,61H ; 'a'
jb .upper
cmp al,7AH ; 'z'
ja loc_exit_proc
xor al,20H ; Символ в нижний регистр
.upper:
…
…
cmp al,61H ; 'a'
jb .upper
cmp al,7AH ; 'z'
ja loc_exit_proc
xor al,20H ; Символ в нижний регистр
.upper:
…
ManHunter
(27.12.2010 в 17:17):
Надо будет проверить и этот способ, спасибо.
Pretorian
(27.12.2010 в 17:15):
Это вариант еще эффективнее:
...
buffer db 256 dup(?)
buflen dd ?
...
proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
cmp [uMsg],WM_CHAR
jnz loc_paste
mov eax,[wParam]
cmp al,1 ; Ctrl+A
je loc_char_ok
cmp al,8 ; Backspace
je loc_char_ok
cmp al,16h ; Ctrl+V
je loc_char_ok
cmp al,18h ; Ctrl+X
je loc_char_ok
cmp al,30h ; '0'
jb loc_exit_proc
cmp al,39h ; '9'
jbe loc_char_ok
xor al,20h ; Символ в нижний регистр
cmp al,41h ; 'A'
jb loc_exit_proc
cmp al,46h ; 'F'
jbe loc_char_ok
loc_exit_proc:
xor eax,eax
ret
loc_char_ok:
mov [wParam],eax
loc_paste:
invoke CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
cmp [uMsg],WM_PASTE
je loc_chk_paste
ret
loc_chk_paste:
invoke GetWindowText,[hEdit],buffer,255
invoke SetWindowText,[hEdit],NULL
mov [buflen],0
push esi
mov esi,buffer
loc_loop:
cmp [buflen],255
je loc_exit_loop
lodsb
or al,al
je loc_exit_loop
invoke SendMessage,[hEdit],WM_CHAR,eax,0
inc [buflen]
jmp loc_loop
loc_exit_loop:
pop esi
ret
endp
...
buffer db 256 dup(?)
buflen dd ?
...
proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
cmp [uMsg],WM_CHAR
jnz loc_paste
mov eax,[wParam]
cmp al,1 ; Ctrl+A
je loc_char_ok
cmp al,8 ; Backspace
je loc_char_ok
cmp al,16h ; Ctrl+V
je loc_char_ok
cmp al,18h ; Ctrl+X
je loc_char_ok
cmp al,30h ; '0'
jb loc_exit_proc
cmp al,39h ; '9'
jbe loc_char_ok
xor al,20h ; Символ в нижний регистр
cmp al,41h ; 'A'
jb loc_exit_proc
cmp al,46h ; 'F'
jbe loc_char_ok
loc_exit_proc:
xor eax,eax
ret
loc_char_ok:
mov [wParam],eax
loc_paste:
invoke CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
cmp [uMsg],WM_PASTE
je loc_chk_paste
ret
loc_chk_paste:
invoke GetWindowText,[hEdit],buffer,255
invoke SetWindowText,[hEdit],NULL
mov [buflen],0
push esi
mov esi,buffer
loc_loop:
cmp [buflen],255
je loc_exit_loop
lodsb
or al,al
je loc_exit_loop
invoke SendMessage,[hEdit],WM_CHAR,eax,0
inc [buflen]
jmp loc_loop
loc_exit_loop:
pop esi
ret
endp
ManHunter
(26.08.2009 в 10:52):
Да, есть такое дело.
Борис Александрович
(26.08.2009 в 08:25):
"прочем этот ничуть не мешает через Ctrl+C / Ctrl+V затолкать в него все что угодно"
а ваш вариант в этом плане не лучше нискольно - туда тоже можно что угодно засунуть. Правда, его можно слегка улучшить:
proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
cmp [uMsg],WM_CHAR
je .chk_char
cmp eax,WM_PASTE
je .paste
.char_ok:
invoke CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
ret
.chk_char:
invoke GetAsyncKeyState,VK_CONTROL
mov ecx,[wParam]
test eax,eax
jne .ctrl
cmp cl,VK_BACK
je .char_ok
cmp cl,'0'
jb .exit_proc
cmp cl,'9'
jbe .char_ok
or cl,20h
cmp cl,'a'
jb .exit_proc
cmp cl,'f'
jbe .char_ok
.exit_proc:
xor eax,eax
ret
.ctrl: cmp cl,3
je .char_ok
cmp cl,22
jne .exit_proc
.paste: invoke IsClipboardFormatAvailable,CF_TEXT
test eax,eax
je .exit_proc
invoke OpenClipboard,ebx
test eax,eax
je .exit_proc
invoke GetClipboardData,CF_TEXT
test eax,eax
je .exit_proc
push eax
invoke GlobalLock,eax
push ebx
sub ebx,ebx
.l00p: mov cl,byte[eax]
cmp cl,'0'
jb .e_l00p
cmp cl,'9'
jbe .inc
or cl,20h
cmp cl,'a'
jb .e_l00p
cmp cl,'f'
ja .e_l00p
.inc: inc eax
cmp [eax],bl
jne .l00p
inc ebx
.e_l00p:call [GlobalUnlock]
.close: call [CloseClipboard]
test ebx,ebx
pop ebx
jne .char_ok
jmp .exit_proc
endp
а ваш вариант в этом плане не лучше нискольно - туда тоже можно что угодно засунуть. Правда, его можно слегка улучшить:
proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
cmp [uMsg],WM_CHAR
je .chk_char
cmp eax,WM_PASTE
je .paste
.char_ok:
invoke CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
ret
.chk_char:
invoke GetAsyncKeyState,VK_CONTROL
mov ecx,[wParam]
test eax,eax
jne .ctrl
cmp cl,VK_BACK
je .char_ok
cmp cl,'0'
jb .exit_proc
cmp cl,'9'
jbe .char_ok
or cl,20h
cmp cl,'a'
jb .exit_proc
cmp cl,'f'
jbe .char_ok
.exit_proc:
xor eax,eax
ret
.ctrl: cmp cl,3
je .char_ok
cmp cl,22
jne .exit_proc
.paste: invoke IsClipboardFormatAvailable,CF_TEXT
test eax,eax
je .exit_proc
invoke OpenClipboard,ebx
test eax,eax
je .exit_proc
invoke GetClipboardData,CF_TEXT
test eax,eax
je .exit_proc
push eax
invoke GlobalLock,eax
push ebx
sub ebx,ebx
.l00p: mov cl,byte[eax]
cmp cl,'0'
jb .e_l00p
cmp cl,'9'
jbe .inc
or cl,20h
cmp cl,'a'
jb .e_l00p
cmp cl,'f'
ja .e_l00p
.inc: inc eax
cmp [eax],bl
jne .l00p
inc ebx
.e_l00p:call [GlobalUnlock]
.close: call [CloseClipboard]
test ebx,ebx
pop ebx
jne .char_ok
jmp .exit_proc
endp
Добавить комментарий
Заполните форму для добавления комментария