Оконное приложение

.386p.model flat, stdcalloption casemap:none includelib .\masm32\lib\kernel32.libincludelib .\masm32\lib\user32.lib include .\masm32\include\windows.inc include .\masm32\include\kernel32.incinclude .\masm32\include\user32.inc .data newhwnd dd 0hInst dd 00000000hszTitleName db 'Window Application',0szClassName db 'ASMCLASS32',0msg MONMSGSTRUCT <?> ; структура сообщенияwc WNDCLASS <?> ; структура класса .codestart: Invoke GetModuleHandle,0 ; получаем hInstanseMov [hInst], eax Mov [wc.style], CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS ; устанавливаем стиль окнаMov [wc.lpfnWndProc], offset WndProc ; Mov [wc.cbClsExtra], 0Mov [wc.cbWndExtra], 0Mov eax, [hInst]Mov [wc.hInstance], eaxInvoke LoadIcon,0,IDI_APPLICATION ; получаем значок приложения по ; умолчаниюMov [wc.hIcon], eax Invoke LoadCursorA,0,IDC_ARROW ; получаем курсор по умолчаниюMov [wc.hCursor], eax Mov [wc.hbrBackground], COLOR_BACKGROUND+1Mov dword ptr [wc.lpszMenuName], 0Mov dword ptr [wc.lpszClassName], offset szClassName ; задаём имя класса ;окнаInvoke RegisterClassA,offset wc ; регистрируем класс окна Push 0Push [hInst] ; дескрипторPush 0Push 0Push CW_USEDEFAULT ; высотаPush CW_USEDEFAULT ; ширинаPush CW_USEDEFAULT ; yPush CW_USEDEFAULT ; xPush WS_OVERLAPPEDWINDOW ; стильPush offset szTitleName ; заголовок окнаPush offset szClassName ; имя классаPush 0 ; дополнительный стильCall CreateWindowEx ; создаём окноmov [newhwnd], eax ; сохраняем его дескрипторinvoke ShowWindow,[newhwnd],SW_SHOWNORMAL; показываем окно invoke UpdateWindow, [newhwnd]; обновляем егоmsg_loop: ; запускаем цикл обработки сообщенийinvoke GetMessage,offset msg, 0,0,0 cmp ax, 0je end_loop invoke TranslateMessage, offset msg invoke DispatchMessage, offset msgjmp msg_loopend_loop: invoke ExitProcess, 0 WndProc proc uses ebx edi esi, hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD Cmp [wmsg], WM_DESTROYJe wmdestroyCmp [wmsg], WM_KEYDOWNJe wmkeydownInvoke DefWindowProcA,[hwnd],[wmsg],[wparam],[lparam] ; вызываем стандартный обработчик сообщенийJmp finishwmkeydown:cmp [wparam], VK_ESCAPEje wmdestroy; если нажата клавиша Escape то выходjmp finishwmdestroy:invoke PostQuitMessage, 0invoke ExitProcess, 0 ; выходfinish: retWndProc endpend start

В самой первой строке мы получаем hInstanse т.е дескриптор приложения, фактически это база образа приложения, т.е. то место в памяти в которого начинается наша программа. Функция GetModuleHandle нужна для получения дескриптора библиотеки (фактически хендл библиотеки это и есть её база образа), параметром этой функции надо передавать имя библиотеки, но если мы укажем 0, то получим дескриптор нашего приложения. Потом мы заполняем структуру класса окна, т.е. задаём атрибуты класса окна.

Mov [wc.lpfnWndProc], offset WndProc

Этой строкой мы указываем, какая функция будет обрабатывать сообщения окна. Функция, которая обрабатывает сообщения окна, называется оконной функцией. Оконная функция вызывается всякий раз, когда окну было прислано какое-либо сообщение.

Потом мы получаем иконку окна с помощью функции LoadIcon, в качестве первого параметра этой функции надо передавать дескриптор приложения, но мы указали 0 поэтому мы получим стандартный значок окна. Во втором параметре мы указываем указатель на строку, которая содержит имя иконки, которую мы хотим получить, но если мы укажем определённую константу, то сможем получить предопределённую иконку. Точно также мы получаем курсор, т.е. его дескриптор.

Потом мы вызываем RegisterClass, единственным параметром которой является указатель на структуру, которая описывает новый класс окна.

Потом мы создаём окно с помощью функции CreateWindowEx.

HWND CreateWindowEx( DWORD dwExStyle, // расширенный стиль окна LPCTSTR lpClassName, // имя класса LPCTSTR lpWindowName, // заголовок окна DWORD dwStyle, // стиль окна int x, // позиция х int y, // позиция у int nWidth, // ширина int nHeight, // высота HWND hWndParent, // хендл окна родителя HMENU hMenu, // хендл меню HINSTANCE hInstance, // хендл приложения LPVOID lpParam //указатель на данные (обычно они не нужны) );

После создания окна мы показываем его и обновляем. Потом запускаем бесконечный цикл обработки системных сообщений.

В оконной функции мы получаем сообщение и обрабатываем его. Если тип сообщения WM_DESTROY, то мы переходим на соответствующую метку, после которой выходим из нашей программы. Если была нажата клавиша, то мы продолжаем обработку и смотрим, нажата ли клавиша escape, если да, то выходим. Если сообщение, какое либо другое, то вызываем стандартный обработчик сообщений окна. Этот обработчик превращает наше окно в настоящее "живое" окно, которое может двигаться, расширятся и свёртываться. Можно и не вызывать эту функцию, но для того чтобы окно стало живым нам придётся вручную обрабатывать все сообщения окна, а это просто нецелесообразно.