Теперь, когда мы знаем, как просто выводится окно с предопределенным классом, возьмемся за вывод собственного окна — процедуры, на которой будут базироваться все последующие примеры, познакомимся с понятием сообщения. В DOS основным средством передачи управления программам в различных ситуациях служат прерывания. В Windows прерывания используются системой для своих нужд, а для приложений существует аналогичный механизм — механизм событий. Так, нажатие клавиши на клавиатуре, если эта клавиша не используется Windows, генерирует сообщение WM_KEYDOWN или WM_KEYUP, которое можно перехватить, добавив в цепь обработчиков события собственное при помощи SetWindowHookEx(). События затем преобразуются в сообщения, которые рассылаются функциям — обработчикам сообщений и которые можно прочитать из основной программы при помощи вызовов GetMessage() и PeekMessage().
Нам пока потребуется только обработка сообщения закрытия окна (WM_DESTROY и WM_QUIT), по которому программа будет завершаться.
; window.asm ; Графическое win32-приложение, демонстрирующее базовый вывод окна ; include def32.inc include kernel32.inc include user32.inc .386 .model flat .data class_name db "window class 1",0 window_name db "win32 assembly example",0 ; структура, описывающая класс окна. wc WNDCLASSEX <4*12,CS_HREDRAW or CS_VREDRAW,offset win_proc,0,0,?,?,?, COLOR_WINDOW+1,0,offset class_name,0> ; здесь находятся следующие поля ; wc.cbSize = 4*12 - размер этой структуры ; wc.style - стиль окна (перерисовывать при изменении размера) ; wc.lpfnWndProc - обработчик событий окна (win_proc) ; wc.cbClsExtra - число дополнительных байтов после структуры (0) ; wc.cbWndExtra - число дополнительных байтов после окна (0) ; wc.hInstance - идентификатор нашего процесса (?) ; wc.hIcon - идентификатор иконки (?) ; wc.hCursor - идентификатор курсора (?) ; wc.hbrBackground - идентификатор кисти или цвет фона+1 ; (COLOR_WINDOW+1) ; wc.lpszMenuName - ресурс с основным меню (в этом примере - 0) ; wc.lpszClassName - имя класса (строка class_name) ; wc.hIconSm - идентификатор маленькой иконки (только в windows 95, ; для NT должен быть 0) .data? msg_ MSG <?,?,?,?,?,?> ; а это - структура, в которой возвращается ; сообщение после GetMessage .code _start: xor ebx,ebx ; в EBX будет 0 для команд push 0 ; (короче в 2 раза) ; определим идентификатор нашей программы 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_USEDEFAULT ; push ecx короче push N в пять раз push ebx ; адрес структуры CREATESTRUCT (здесь NULL) push esi ; идентификатор процесса, который будет получать ; сообщения от окна (то есть, наш) push ebx ; идентификатор меню или окна-потомка push ebx ; идентификатор окна-предка push ecx ; высота (CW_USEDEFAULT - по умолчанию) push ecx ; ширина (по умолчанию) push ecx ; y-координата (по умолчанию) push ecx ; x-координата (по умолчанию) 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 ; и послать ему сообщение WM_PAINT