Common Controls - практика
Доброго времени суток, уважаемые подписчики.
Сегодня мы сделаем простенькую программу с одной кнопкой и обсудим преимущества использования Common Controls в окнах перед диалогами. Так как один из самых больших недостатков диалогов является их зафиксированный размер, для примера я выбрал программу, в которой не зависимо от размеров окна кнопка всегда будет оставаться в центре окна. Для выполнения этой задачи мы должны будем обрабатывать сообщение WM_SIZE, которое посылается при изменении размера окна. Также нам надо обеспечить видимость кнопки, так как если окно будет 0 пикселей в высоту, то кнопку мы не увидим. Чтоб предотвратить задание меньшего размера, а не обрабатывать его как исключение мы должны также обрабатывать сообщение WM_SIZING, которое приходит в момент изменения размера окна. В lParam этого сообщение лежит структура RECT, изменяя которую мы можем изменять будущее положение окна. Вот в принципе и всё, что нужно знать для создания такой программы, поэтому давайте приступим!
ID_BUTTON | equ | 100h |
include macros.inc |
include def32.inc |
include kernel32.inc |
include user32.inc |
include comdlg32.inc |
| .386 |
| .model flat |
| .data |
HQuitButton | dd | ? |
wc | WNDCLASSEX<size wc,cs_hredraw or cs_vredraw,offset | win_proc,0,0,?,?,?, color_window,0,offset class_name,0> |
msg_ | MSG | > |
rc | RECT | > |
class_name | db | 'Simple Window',0 |
ButtonClass | db | 'Button',0 |
WndName | db | 'Button example',0 |
QuitButton | db | 'Exit',0 |
| .code |
_start: |
| null ebx |
| push ebx |
| call GetModuleHandle |
| push ebx |
| push eax |
| mov wc.hInstance,eax |
| push IDI_Application |
| push ebx |
| call loadicon |
| mov wc.hIcon,eax |
| push idc_arrow |
| push ebx |
| call LoadCursor |
| mov wc.hCursor,eax |
| push offset wc |
| call registerclassEx |
| mov ecx,CW_USEDEFAULT |
| push ebx |
| push ebx |
| push ecx |
| push ecx |
| push ecx |
| push ecx |
| push WS_OVERLAPPEDWINDOW |
| push offset WndName |
| push offset class_name |
| push ebx |
| call CreateWindowEx |
| push eax |
| push sw_shownormal |
| push eax |
| call showwindow |
| call updatewindow |
| mov edi,offset msg_ |
main_loop: |
| push ebx |
| push ebx |
| push ebx |
| push edi |
| call Getmessage |
| test eax,eax |
| jz exit_program |
| push edi |
| call TranslateMessage |
| push edi |
| call DispatchMessage |
| jmp short main_loop |
exit_program: |
| push ebx |
| call ExitProcess |
win_proc proc |
| push ebp |
| mov ebp,esp |
wp_hWnd | equ dword ptr [ebp+08h] |
wp_uMsg | equ dword ptr [ebp+0Ch] |
wp_wParam | equ dword ptr [ebp+10h] |
wp_lParam | equ dword ptr [ebp+14h] |
| null ebx |
| mov eax,wp_uMsg |
| cmp eax,WM_DESTROY |
| je destroy_proc |
| cmp eax,WM_CREATE |
| je create_proc |
| cmp eax,WM_SIZe |
| je size_proc |
| cmp eax,WM_SIZING |
| je sizing_proc |
| null eax |
| leave |
| jmp DefWindowProc |
size_proc: |
| push offset rc |
| push wp_hWnd |
| call GetClientRect |
| mov eax,rc.bottom |
| sub eax,rc.top |
| shr eax,1 |
| sub eax,10 |
| mov rc.top,eax |
| mov eax,20 |
| mov rc.bottom,eax |
| mov eax,rc.right |
| sub eax,rc.left |
| shr eax,1 |
| sub eax,25 |
| mov rc.left,eax |
| mov eax,50 |
| push 1 |
| push rc.bottom |
| push eax |
| push rc.top |
| push rc.left |
| push HQuitButton |
| call MoveWindow |
| jmp short WndProcEnd |
sizing_proc: |
| mov esi,wp_lParam |
| mov eax,[esi+0Ch] |
| sub eax,47 |
| cmp eax,[esi+04h] |
| jnb WndProcEnd |
| mov eax,[esi+04h] |
| add eax,47 |
| mov [esi+0ch],eax |
WndProcEnd: |
| null eax |
| inc eax |
| leave |
| jmp DefWindowProc |
create_proc: |
| push offset rc |
| push wp_hWnd |
| call GetClientRect |
| mov eax,rc.bottom |
| sub eax,rc.top |
| shr eax,1 |
| sub eax,10 |
| mov rc.top,eax |
| mov eax,20 |
| mov rc.bottom,eax |
| mov eax,rc.right |
| sub eax,rc.left |
| shr eax,1 |
| sub eax,25 |
| mov rc.left,eax |
| mov eax,50 |
| push ebx |
| push wc.hInstance |
| push ID_BUTTON |
| push wp_hWnd |
| push rc.bottom |
| push eax |
| push rc.top |
| push rc.left |
| push WS_VISIBLE or WS_CHILD or WS_BORDER |
| push offset QuitButton |
| push offset ButtonClass |
| push ebx |
| call CreateWindowEx |
| mov HQuitButton,eax |
| jmp WndProcEnd |
destroy_proc: |
| push ebx |
| call PostQuitMessage |
| leave |
| ret 16 |
win_proc endp |
| end _start |
Теперь давайте рассмотрим некоторые моменты этой программы. Я думаю, большая часть программы Вам понятна, но есть некоторые моменты. Проблемные моменты я выделил разными цветами, первый момент (красный цвет). Этот случай наилучшим образом отображает выгоду программирования на языке Ассемблер. Так как push eax гораздо быстрее соответствующей команде для переменной в памяти, мы помещаем его в стек задолго до его использования, но ведь стек же сохраняется! Второй момент отмечен зелёным и является лишь замечанием, что иногда гораздо выгоднее несколько раз прописать один и тот же код, чем помещать его в процедуру, так как create_proc вызывается один раз, а вот size_proc может быть вызвано огромное количество раз, а так как переход в процедуру и возврат оттуда тоже занимают процессорное время, то легче два раза прописать один и тот же код.
Ещё хочу отдельно рассмотреть sizing_proc. В ней, как я уже сказал ранее, передаётся адрес глобальной структуры RECT, поэтому, записав этот адрес в esi, я могу смело сказать, что [esi]=RECT.left, [esi+04h]=RECT.top, [esi+08h]=RECT.right, [esi+0Ch]=RECT.bottom, что мы и видим в моём примере. Надеюсь, всё понятно, если есть какие вопросы, пишите!
Следующие файлы Вы можете скачать к этому уроку:
0012asm - код программы
0012exe - сама программа
0012inc - файлы дополнения
0012lib - библиотеки импорта
На сегодня это всё. Если есть какие вопросы, пишите, обязательно отвечу. Пишите, Dark_Lord@RusFAQ.ru, Dark_Lord@land.ru.
Или свяжитесь со мной по ICQ, мой номер 126222874!
|