Ассемблерное программирование в Windows |
15.09.2004 |
||
Глава 4. Исходный текст второй программыНиже представлен исходный текст второй программы, выводящей настоящее окно приложения со строкой меню. Он размещается в пяти небольших файлах: bloknot.asm — основной файл программы Файл «bloknot.asm» - основной файл программы include def32.inc ;Включить в исходник файл с определениями разных констант ;и структур. include kernel32.inc ;Включить файл с объявлениями внешних функций ;из библиотеки kernel32.dll. include user32.inc ;Включить файл с объявлениями внешних функций ;из библиотеки user32.dll, в которую входят ;все основные функции, отвечающие за оконный интерфейс. .386 ;Пишем код в командах процессора 80386 .model flat ;Плоская модель памяти .data ;Инициализированные или частично инициализированные данные class_name db "NotePadWiindow",0 ;Имя класса окна. window_name db "Блокнотик",0 ;Название окна (выводится в его заголовке) win_menu db "Выбран пункт меню:",0 ;Название окна, вызываемого через меню about_msg db "О программе",0 ; \ open_msg db "Открыть",0 ; > Тексты для окон сообщений save_msg db "Сохранить",0 ; / ;Определим структуру wc типа WNDCLASSEX, описывающую класс нашего окна. ;Для создания объекта структуры wc используем описание структуры WNDCLASSEX ;из файла def32.inc. В структуре помимо прочих параметров прописываем ;идентификатор меню, созданного в файле ресурсов (помечен красным цветом). wc WNDCLASSEX <4*12,CS_HREDRAW or CS_VREDRAW,offset win_proc,\ 0,0,?,?,?,COLOR_WINDOW+1,1,offset class_name,0> .data? ;Неинициализированные данные ;Определим структуру msg_ типа MSG, в которую будут записываться сообщения ;после вызова GetMessage. ;Для создания объекта структуры msg_ используем описание структуры MSG ;из файла def32.inc. msg_ MSG <> .code _start: xor ebx,ebx ;Занести в bx ноль ;Создадим класс нашего окна, заполнив недостающие поля структуры wc ;и зарегистрировав его. push ebx call GetModuleHandle ;Определить идентификатор нашей программы mov esi,eax ;Занести его в esi mov dword ptr 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_USERDEFAULT ;Идентификатор значения по умолчанию занесем в cx push ebx ;Адрес структуры CREATESTRUCT (ноль) push esi ;Идентификатор нашего процесса, ;который будет получать сообщения от окна push ebx ;Идентификатор меню (или окна-потомка) push ebx ;Идентификатор окна-предка — 0, ибо предка нет. push ecx ;Высота(в ecx идентификатор значения по умолч.) push ecx ;Ширина push ecx ;Координата у push ecx ;Координата х push WS_OVERLAPPEDWINDOW ;стиль окна push offset window_name ;Заголовок окна push offset class_name ;Любой зарегистрированный класс push ebx ;Дополнительный стиль call CreateWindowEx ;Создать окно (в eax идентификатор окна) push eax ;Идентификатор окна для UpdateWindow push SW_SHOWNORMAL ;Тип показа для ShowWindow push eax ;Идентификатор окна для ShowWindow call ShowWindow ;Отобразить окно call UpdateWindow ;Перерисовать рабочую область окна mov edi, offset msg_ ;зарядим регистр адресом сообщения ;Цикл обработки сообщений message_loop: push ebx ;Последнее сообщение push ebx ;Первое сообщение push ebx ;Идентификатор окна (0-любое наше сообщение) push edi ;Адрес структуры для размещения сообщения call GetMessage ;Ждать получение сообщения из очереди сообщений test eax,eax ;Если получен 0 (WM_QUIT), jz exit_msg_loop ;то выйти. push edi ;Иначе снова забить адрес структуры с сообщением call TranslateMessage ;преобразовать сообщение типа WM_KEYUP в WM_CHAR push edi ;Снова забить адрес структуры с сообщением call DispatchMessage ;и послать его оконной процедуре jmp short message_loop ;Продолжить цикл exit_msg_loop: push ebx call ExitProcess ;Выход из программы ;Процедура вызывается Windows, для передачи сообщения в окно, ;после чего процедура снова передает управление Windows. win_proc proc 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] ;Четыре параметра этой процедуры идентичны ;первым четырем параметрам ;структуры передачи сообщений msg_. push ebp ;Сохранить регистр ebp mov ebp,esp ;Сохранить регистр указателя стека pusha ;Сохранить все регистры в стеке cmp wp_uMsg, WM_DESTROY ;Пришло сообщение о закрытии окна? jne not_wm_destroy ;Если нет, перейти на наш ;обработчик сообщений push ebx ;иначе загрузить код выхода (WM_QUIT) call PostQuitMessage ;и послать его основной программе, чтобы считать ;его в следующий раз и выйти из программы. jmp short end_wm_check ;Выйти из процедуры проверки сообщений not_wm_destroy: cmp wp_uMsg,WM_COMMAND ;Если мы получили WM_COMMAND, ;то сообщение от нашего меню. jne not_wm_command ;иначе перейти на стандартный ;обработчик Windows. mov eax,wp_wParam ;Забираем идентификатор пункта меню из wp_wParam ;в eax (0,1,2 или 3) jmp dword ptr menu_handlers[eax*4] ;и осуществляем переход на метку, ;вытащенную из адреса, полученного ;умножением значения идентификатора ;на размерность следующих данных: menu_handlers dd offset menu_about, offset menu_open dd offset menu_save, offset menu_exit ;Выбор текста «О программе» menu_about: mov eax, offset about_msg ;В eax заносим смещение к тексту jmp short show_msg ;Переходим на вывод окна с текстом ;Выбор текста «Открыть» menu_open: mov eax, offset open_msg ;В eax заносим смещение к тексту jmp short show_msg ;Переходим на вывод окна с текстом ;Выбор текста «Сохранить» menu_save: mov eax, offset save_msg ;В eax заносим смещение к тексту jmp short show_msg ;Переходим на вывод окна с текстом ;Вывод окна с текстом show_msg: push MB_OK ;Зададим стиль окна push offset win_menu ;Название окна push eax ;Текст в окне push wp_hWnd ;Идентификатор окна-предка call MessageBox ;Вывод окна на экран jmp short end_wm_check ;Выйти из процедуры ;Уничтожить окно menu_exit: push wp_hWnd ;Идентификатор уничтожаемого окна call DestroyWindow ;Уничтожить окно ;Выйти из процедуры end_wm_check: popa ;Восстановить все регистры leave ;Восстановить esp и ebp xor eax,eax ;В качестве кодв аозврата вернуть ноль ret 16 ;Очистить стек от параметров и выйти ;Переход на стандартный обработчик сообщений Windows not_wm_command: popa ;Восстановить все регистры leave ;Восстановить esp и ebp jmp DefWindowProc ;Вызвать стандартный обработчик сообщений win_proc endp end _start Файл «Bloknot.rc» - файл ресурсов 1 MENUEX ;Организовать меню и присвоить идентификатор BEGIN ;Идентификатор выделен красным цветом. POPUP "&Файл",,, ;Организовать раскрывающийся пункт меню BEGIN ;Начать раскрывающийся пункт меню MENUITEM "&Открыть\tCtrl+J",1,, ;Организовать в нём пункты и присвоить MENUITEM "&Сохранить\tCtrl+C",2,, ;им идентификаторы. MENUITEM "",,0x00000800, ;Вставить линию-разделитель MENUITEM "&Выход\tCtrl+D",3,, ; END ;Завершить раскрывающийся пункт меню MENUITEM "&О программе",0,, ; END ; Файл «def32.inc» — содержит описания структур и присвоения константам имен ;Зададим имена константам IDI_APPLICATION EQU 32512 WM_DESTROY EQU 2 CS_HREDRAW EQU 2 CS_VREDRAW EQU 1 CW_USERDEFAULT EQU 80000000H WS_OVERLAPPEDWINDOW EQU 0CF0000H IDC_ARROW EQU 32512 SW_SHOWNORMAL EQU 1 COLOR_WINDOW EQU 5 WM_COMMAND EQU 111h ;сообщение от меню MB_OK EQU 0 ;Опишем тип стандартной структуры для описания класса окна WNDCLASSEX struc cbSize dd ? ;Размер этой структуры в байтах (12 записей по 4 байта) style dd ? ;Стили окна (перерисовывать ли окно при изменении ;размеров и перемещении и т.п.) lpfnWndProc dd ? ;Смещение к оконной процедуре, которую вызывает Windows, ;чтобы обратиться к окну cbClsExtra dd ? ;Количество байт, резервируемых после ;структуры класса окна cbWndExtra dd ? ;Количество байт, резервируемых после экземпляра окна hInstance dd ? ;Идентификатор процесса класса окна hIcon dd ? ;Идентификатор класса иконки hCursor dd ? ;Идентификатор класса курсора hbrBackground dd ? ;Цвет фона окна lpszMenuName dd ? ;Имя меню или его идентификатор lpszClassName dd ? ;Имя класса окна hIconSm dd ? ;Идентификатор класса маленькой иконки окна WNDCLASSEX ends ;Опишем тип структуры, содержащейся в структуре MSG. POINT struc x dd ? ;Координата x курсора y dd ? ;Координата Y курсора POINT ends ;Опишем тип стандартной структуры для передачи сообщений MSG struc hwnd dd ? ;Идентификатор окна, которое получает сообщение; message dd ? ;Определяет номер сообщения wParam dd ? ;Дополнительная информация о сообщении lParam dd ? ;Дополнительная информация о сообщении time dd ? ;Время послания сообщения pt POINT <> ;Позиция курсора в экранных координатах, ;которая была при отправке сообщения MSG ends Файл «kernel32.inc» — содержит объявления внешних функций, отвечающих за управление программой includelib kernel32.lib ;Будем использовать функции из этой библиотеки ;Будем использовать эти функци extrn __imp__GetModuleHandleA@4:dword extrn __imp__ExitProcess@4:dword ;Упростим их названия GetModuleHandle equ __imp__GetModuleHandleA@4 ExitProcess equ __imp__ExitProcess@4 Файл «user32.inc» — содержит объявления внешних функций, отвечающих за оконный интерфейс includelib user32.lib ;Будем использовать функции из этой библиотеки ;Будем использовать эти функци extrn __imp__DispatchMessageA@4:dword extrn __imp__TranslateMessage@4:dword extrn __imp__GetMessageA@16:dword extrn __imp__LoadIconA@8:dword extrn __imp__UpdateWindow@4:dword extrn __imp__ShowWindow@8:dword extrn __imp__CreateWindowExA@48:dword extrn __imp__DefWindowProcA@16:dword extrn __imp__PostQuitMessage@4:dword extrn __imp__RegisterClassExA@4:dword extrn __imp__LoadCursorA@8:dword extrn __imp__LoadMenuA@8:dword extrn __imp__DestroyWindow@4:dword extrn __imp__MessageBoxA@16:dword ;Упростим их названия DispatchMessage equ __imp__DispatchMessageA@4 TranslateMessage equ __imp__TranslateMessage@4 GetMessage equ __imp__GetMessageA@16 LoadIcon equ __imp__LoadIconA@8 UpdateWindow equ __imp__UpdateWindow@4 ShowWindow equ __imp__ShowWindow@8 CreateWindowEx equ __imp__CreateWindowExA@48 DefWindowProc equ __imp__DefWindowProcA@16 PostQuitMessage equ __imp__PostQuitMessage@4 RegisterClassEx equ __imp__RegisterClassExA@4 LoadCursor equ __imp__LoadCursorA@8 LoadMenu equ __imp__LoadMenuA@8 DestroyWindow equ __imp__DestroyWindow@4 MessageBox equ __imp__MessageBoxA@16 |
|||
[Вернуться в начало] |
Глава 3 | Глава 5 | [Оставить отзыв в гостевой] |