Глава 20 - программирование для Windows
Мы используем cookie-файлы, чтобы получить статистику, которая помогает нам улучшить сервис для Вас с целью персонализации сервисов и предложений. Вы можете прочитать подробнее о cookie-файлах или изменить настройки браузера. Продолжая пользоваться сайтом без изменения настроек, вы даёте согласие на использование ваших cookie-файлов.
speech bubble

Глава 20 - программирование для Windows

Самоучитель по языку ассемблер(assembler)

 

Содержание:

 

ВНИМАНИЕ! Данный самоучитель был написан много лет назад и его автор не сможет ответить на ваши вопросы. Курс по assembler предназначен для саморазвития. Если у вас хватает квалификации, можете предложить внести правки.

 

Рассмотрим задачу создания текстового редактора. Программировать на ассемблере под Windows очень просто. Надо лишь функции вызывать. Вообще говоря конечно тут всё не так просто про программирование под Windows на ассемблере можно создать целую книгу. Она конечно будет содержать описания WinAPI! поэтому если что то не ясно то смотрите дополнительный материал.

Для начала рассмотрим ка это делать на Masm 8.0! Версия именно такая!

Для создания программы использовался инструмент MASM32 Prostart Code Wizard, который сгенерировал основной каркас программы – файл ресурса с меню (File, Help) и иконкой, основной файл программы содержащий стандартный каркас приложения – создания окна, обработка основных сообщений, файл с описанием функций стандартных диалоговых окон по открытию и сохранению файлов, включаемый файл содержащий описание необходимых данных, make файл позволяющий проводить компиляцию и сборку приложения. Для создания простейшего текстового редактора в процессе обработки сообщения WM_CREATE создается текстовое поле – окно с преопределенным классом EDIT, с помощью функции CreateWindowEx. Для организации открытия и сохранения файла в процессе обработки сообщения WM_COMMAND проверяется какой пункт меню выбран и в зависимости от этого предпринимается либо вызов функции открытия файла либо его сохранения с целью получения полного имени файла. Далее при открытии с помощь CreateFile создается файл, выделяется и блокируется память для буфера GlobalAlloc и GlobalLock, файл читается в буфер ReadFile, окну редактора посылается сообщение WM_SETTEXT, выделенная память освобождается GlobalUnLock и GlobalFree. При сохранении последовательность действий та же но окну посылается сообщение WM_GETTEXT а вместо ReadFile используется WriteFile. Обрабатываются также сообщения WM_SIZE – для изменения размера окна редактора и сообщение WM_CLOSE для про-верки модификации текста и сохранения его (опрос окна редактора через SendMessage с сообщением EM_GETMODIFY)

Запустите файл PROSTART.EXE - перед вами удобный генератор исходных текстов программ! Отметьте значки как на рисунке и нажмите Create Project:

PROSTART.EXE

После этого создастся проект! Замените файлы на те что приведены здесь:

Project.asm

; ######

.386
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive

include Project.inc ; local includes for this file

; #######

.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax

invoke GetCommandLine
mov CommandLine, eax

invoke WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax

; #######
hPrevInst :DWORD,
CmdLine :DWORD,
CmdShow :DWORD

;====================
; Put LOCALs on stack
;====================

LOCAL wc :WNDCLASSEX
LOCAL msg :MSG
LOCAL Wwd :DWORD
LOCAL Wht :DWORD
LOCAL Wtx :DWORD
LOCAL Wty :DWORD

;=====
; Fill WNDCLASSEX structure with required variables
;=====

invoke LoadIcon,hInst,500 ; icon ID
mov hIcon, eax

szText szClassName,"Project_Class"

mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_BYTEALIGNWINDOW
mov wc.lpfnWndProc, offset WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
m2m wc.hInstance, hInst
mov wc.hbrBackground, COLOR_WINDOW+12
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset szClassName
m2m wc.hIcon, hIcon
invoke LoadCursor, NULL, IDC_ARROW
mov wc.hCursor, eax
m2m wc.hIconSm, hIcon

invoke RegisterClassEx, ADDR wc

;======
; Centre window at following size
;======

mov Wwd, 500
mov Wht, 350

invoke GetSystemMetrics, SM_CXSCREEN
invoke TopXY,Wwd,eax
mov Wtx, eax

invoke GetSystemMetrics, SM_CYSCREEN
invoke TopXY, Wht, eax
mov Wty, eax

invoke CreateWindowEx,WS_EX_LEFT,
ADDR szClassName,
ADDR szDisplayName,
WS_OVERLAPPEDWINDOW,
Wtx,Wty,Wwd,Wht,
NULL, NULL,
hInst, NULL
mov hWnd,eax

invoke LoadMenu, hInst,600 ; menu ID
invoke SetMenu, hWnd, eax

invoke ShowWindow, hWnd, SW_SHOWNORMAL
invoke UpdateWindow, hWnd

;======
; Loop until PostQuitMessage is sent
;======

StartLoop:
invoke GetMessage,ADDR msg, NULL,0,0
cmp eax, 0
je ExitLoop
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
jmp StartLoop
ExitLoop:

return msg.wParam

WinMain endp

; #####

WndProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD
LOCAL var :DWORD
LOCAL caW :DWORD
LOCAL caH :DWORD
LOCAL Rct :RECT
LOCAL hDC :DWORD
LOCAL Ps :PAINTSTRUCT
LOCAL buffer1[128]:BYTE ; these are two spare buffers
LOCAL buffer2[128]:BYTE ; for text manipulation etc..

.if uMsg == WM_COMMAND
;== menu commands ==
.if wParam == 1000
jmp @F
szTitleO db "Открыть файл",0
szFilterO db "All files",0,"*.*",0,
"Text files",0,"*.txt",0,0
@@:

invoke FillBuffer, ADDR szFileName, length szFileName,0
invoke GetFileName, hWin, ADDR szTitleO, ADDR szFilterO

cmp szFileName[0],0 ;<< zero if cancel pressed in dlgbox
je @F
; file name returned in szFileName
invoke CreateFile, ADDR szFileName, GENERIC_READ or GENERIC_WRITE ,\
FILE_SHARE_READ or FILE_SHARE_WRITE,\
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE,\
NULL
mov hFile,eax
;Выделение динамической памяти и сохранение дескриптора
invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMSIZE
mov hMemory,eax
;Закрытие блока памяти и сохранение указателя на него
invoke GlobalLock, hMemory
mov pMemory,eax
;Чтение файла
invoke ReadFile,hFile,pMemory,MEMSIZE-1,\
ADDR SizeReadWrite, NULL
;Смена текста в EDIT
invoke SendMessage, hwndEdit, WM_SETTEXT, NULL, pMemory
;Закрытие файла
invoke CloseHandle,hFile
;Открытие блока памяти и его освобождение
invoke GlobalUnlock, pMemory
invoke GlobalFree, hMemory

@@:

.elseif wParam == 1001
jmp @F
szTitleS db "Сохранить файл",0
szFilterS db "All files",0,"*.*",0,
"Text files",0,"*.txt",0,0
@@:
s:
invoke FillBuffer, ADDR szFileName, length szFileName,0
invoke SaveFileName,hWin,ADDR szTitleS,ADDR szFilterS

cmp szFileName[0],0 ;<< zero if cancel pressed in dlgbox
je @F
; file name returned in szFileName
;Открытие файла и сохранение его дескриптора
invoke CreateFile,ADDR szFileName,GENERIC_READ or GENERIC_WRITE ,\
FILE_SHARE_READ or FILE_SHARE_WRITE,\
NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE,\
NULL
mov hFile,eax
;Выделение динамической памяти и сохранение дескриптора
invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMSIZE
mov hMemory,eax
;Закрытие блока памяти и сохранение указателя на него
invoke GlobalLock,hMemory
mov pMemory,eax
;Получение текста из EDIT
invoke SendMessage, hwndEdit, WM_GETTEXT, MEMSIZE-1,pMemory
;Запись в файл и его закрытие
invoke WriteFile, hFile, pMemory, eax, ADDR SizeReadWrite, NULL
invoke CloseHandle,hFile
;Открытие блока памяти и его освобождение
invoke GlobalUnlock,pMemory
invoke GlobalFree,hMemory

@@:

.endif
.if wParam == 1010
invoke SendMessage, hWin, WM_SYSCOMMAND, SC_CLOSE,NULL
.elseif wParam == 1900
szText AboutMsg, "Программа - текстовый редактор", 13, 10, "Copyright © Student IS-103 2004"
invoke ShellAbout, hWin, ADDR szDisplayName, ADDR AboutMsg, hIcon
.endif
;====== end menu commands ======

.elseif uMsg == WM_CREATE
szText EditClass,"EDIT"
invoke CreateWindowEx, NULL, ADDR EditClass, NULL, WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or\
ES_AUTOVSCROLL, 5, 5, 475, 280, hWin, 1111, hInstance, NULL
mov hwndEdit,eax
invoke SetFocus,hwndEdit
.elseif uMsg == WM_SIZE
invoke GetClientRect,hWin, ADDR Rct
sub Rct.right,10
sub Rct.bottom,10
invoke MoveWindow, hwndEdit, 5, 5, Rct.right, Rct.bottom,1

.elseif uMsg == WM_PAINT
invoke BeginPaint,hWin,ADDR Ps
mov hDC, eax
invoke Paint_Proc,hWin,hDC
invoke EndPaint, hWin, ADDR Ps
return 0

.elseif uMsg == WM_CLOSE
szText TheText,"Текст не сохранен - Сохранить?"
invoke SendMessage, hwndEdit, EM_GETMODIFY,0,0
test eax,eax
jz nomod
invoke MessageBox,hWin,ADDR TheText,ADDR szDisplayName,MB_YESNOCANCEL
.if eax == IDYES
jmp s ;return 0
.endif
.if eax == IDCANCEL
return 0
.endif
.if eax == IDNO
jmp nomod
.endif
.elseif uMsg == WM_DESTROY
nomod: invoke PostQuitMessage,NULL
return 0
.endif

invoke DefWindowProc, hWin, uMsg, wParam, lParam

ret

WndProc endp

; ######

TopXY proc wDim:DWORD, sDim:DWORD

shr sDim, 1 ; divide screen dimension by 2
shr wDim, 1 ; divide window dimension by 2
mov eax, wDim ; copy window dimension into eax
sub sDim, eax ; sub half win dimension from half screen dimension

return sDim

TopXY endp

; ######

Paint_Proc proc hWin:DWORD, hDC:DWORD

LOCAL btn_hi :DWORD
LOCAL btn_lo :DWORD
LOCAL Rct :RECT

invoke GetSysColor, COLOR_BTNHIGHLIGHT
mov btn_hi, eax

invoke GetSysColor, COLOR_BTNSHADOW
mov btn_lo, eax

return 0
Paint_Proc endp
; #######
end start

Файл filedlgs.asm
; ########

GetFileName PROTO :DWORD, :DWORD, :DWORD
SaveFileName PROTO :DWORD, :DWORD, :DWORD
FillBuffer PROTO :DWORD, :DWORD, :BYTE

.data
szFileName db 260 dup(0)
ofn OPENFILENAME <> ; structure

.code

; #######

GetFileName proc hParent:DWORD, lpTitle:DWORD, lpFilter:DWORD

mov ofn.lStructSize, sizeof OPENFILENAME
m2m ofn.hWndOwner, hParent
m2m ofn.hInstance, hInstance
m2m ofn.lpstrFilter, lpFilter
m2m ofn.lpstrFile, offset szFileName
mov ofn.nMaxFile, sizeof szFileName
m2m ofn.lpstrTitle, lpTitle
mov ofn.Flags, OFN_EXPLORER or OFN_FILEMUSTEXIST or \
OFN_LONGNAMES

invoke GetOpenFileName,ADDR ofn

ret

GetFileName endp

; ######

SaveFileName proc hParent:DWORD, lpTitle:DWORD, lpFilter:DWORD

mov ofn.lStructSize, sizeof OPENFILENAME
m2m ofn.hWndOwner, hParent
m2m ofn.hInstance, hInstance
m2m ofn.lpstrFilter, lpFilter
m2m ofn.lpstrFile, offset szFileName
mov ofn.nMaxFile, sizeof szFileName
m2m ofn.lpstrTitle, lpTitle
mov ofn.Flags, OFN_EXPLORER or OFN_LONGNAMES

invoke GetSaveFileName,ADDR ofn

ret

SaveFileName endp

; #####

FillBuffer proc lpBuffer:DWORD, lenBuffer:DWORD, TheChar:BYTE

push edi

mov edi, lpBuffer ; address of buffer
mov ecx, lenBuffer ; buffer length
mov al, TheChar ; load al with character
rep stosb ; write character to buffer until ecx = 0

pop edi

ret

FillBuffer endp

; ####

Файл Project.inc
; ####

; include files
; ~~~~~~~~~~~~~
include C:\MASM32\INCLUDE\windows.inc
include C:\MASM32\INCLUDE\masm32.inc
include C:\MASM32\INCLUDE\gdi32.inc
include C:\MASM32\INCLUDE\user32.inc
include C:\MASM32\INCLUDE\kernel32.inc
include C:\MASM32\INCLUDE\Comctl32.inc
include C:\MASM32\INCLUDE\comdlg32.inc
include C:\MASM32\INCLUDE\shell32.inc

; libraries
; ~~~~~~~~~
includelib C:\MASM32\LIB\masm32.lib

includelib C:\MASM32\LIB\gdi32.lib
includelib C:\MASM32\LIB\user32.lib
includelib C:\MASM32\LIB\kernel32.lib
includelib C:\MASM32\LIB\Comctl32.lib
includelib C:\MASM32\LIB\comdlg32.lib
includelib C:\MASM32\LIB\shell32.lib

; ###

;======
; Local prototypes
;=====
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
TopXY PROTO :DWORD,:DWORD
FillBuffer PROTO :DWORD, :DWORD, :BYTE
Paint_Proc PROTO :DWORD,:DWORD

wsprintfA PROTO C :DWORD,:VARARG
wsprintf equ

;=====
; Local macros
;=====

szText MACRO Name, Text:VARARG
LOCAL lbl
jmp lbl
Name db Text,0
lbl:
ENDM

m2m MACRO M1, M2
push M2
pop M1
ENDM

return MACRO arg
mov eax, arg
ret
ENDM
MAXSIZE equ 260
MEMSIZE equ 65535
.data
szDisplayName db "Text Editor",0
CommandLine dd 0
hWnd dd 0
hInstance dd 0
hIcon dd 0
.data?
hwndEdit HWND ?
hFile HANDLE ?
hMemory HANDLE ?
pMemory DWORD ?
SizeReadWrite DWORD ?

; ## Inserted modules ##

include filedlgs.asm

; #####

Файл rsrc.rc
500 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "PROJECT.ICO"

600 MENUEX MOVEABLE IMPURE LOADONCALL DISCARDABLE
BEGIN
POPUP "&File", , , 0
BEGIN
MENUITEM "&Open", 1000
MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
MENUITEM "&Save", 1001
MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
MENUITEM "&Exit", 1010
END
POPUP "&Help", , , 0
BEGIN
MENUITEM "&About", 1900
END
END

Компиляция makeit.bat - он сгенерирован автоматически

Результат:

 

 

 

Для комментирования необходимо авторизоваться