Ассемблер под Windows №8

Макросы и стандартные диалоги Windows


Доброго времени суток, уважаемые подписчики.
Как видно из заголовка сегодняшнего урока, я решил обратить ваше внимание на одно из приемуществ ассемблера, макросы. Наверняка многие из Вас уже знают, что это такое, но одно дело знать, а другое использовать. А использовать правильно - это ещё труднее. В зтом уроке мы поговорим об основах написания макросов и сделаем пару примеров, которые будем использовать в нашей программе. Макрос - это часть программы, которая ассемблируется каждый раз, когда компилятор встречает, причём этот код может получать параметры и выполняться в зависимости от них! Например мокрос обнуления регистра директивой xor может быть очень удобен, давайте создадим файл makros.inc и запишем в него следующий макрос:
null macro param1
  xor param1,param1
endm
после добавление в файл с кодом программы строки include macros.inc команда null eax будет интерпритироваться как xor eax,eax, null ebx - xor ebx,ebx и т.д. Вы спросите нафиг это надо, ведь и так не было так трудно написать, однако если кто-то не очень соображающий в ассемблере увидит xor eax,eax, он в 99 случаях из ста непоймёт что это такое, а null eax заставит его подумать, что происходит обнуление еах. Это вторая полезность макросов, они делают программу более понятной. Пока макросы нам не особо нужны, но при написании более серьёзных программ они начинают играть серьёзную роль.


Другой вопрос, который я хотел бы рассмотреть сегодня, это использование стандартных диалогов Windows. В принципе, мы уже сталкивались с этим явлением, так как MessageBox тоже является стандартным диалогом. Сегодня мы познакомимся со стандартным диалогом открытия файла, который вызывается функцией Windows GetOpenFileName, которая получает один(!) параметр, offset структуры OPENFILENAME, которую мы сейчас и рассмотрим:
OPENFILENAME struc
  lStructSize       dd ? ;Размер структуры, используется для определения версии структуры
  hwndOwner         dd ? ;handle окна-родителя
  _hInstance        dd ? ;handle приложения, из которого происходит запуск
  lpstrFilter       dd ? ;указатель на фильтры поиска
  lpstrCustomFilter dd ? ;указатель на вторичные фильтры поиска
  nMaxCustFilter    dd ? ;кол-во символов в lpstrCustomFilter
  nFilterIndex      dd ? ;номер фильтра, устанофленного по умолчанию
  lpstrFile         dd ? ;указатель на буфер для полного имени файла
  nMaxFile          dd ? ;размер буфера lpstrFile
  lpstrFileTitle    dd ? ;указатель на буфер для имени файла без диретории
  nMaxFileTitle     dd ? ;размер буфера lpstrFileTitle
  lpstrInitialDir   dd ? ;Указатель на директорию по умолчанию
  lpstrTitle        dd ? ;Указатель на строку, которая будет помещена в заголовок
  Flags             dd ? ;Битовые флаги, определяющие работу диалога
  nFileOffset       dw ? ;указатель на имя файла
  nFileExtension    dw ? ;указатель на расширение файла
  lpstrDefExt       dd ? ;расширение по умолчанию
  lCustData         dd ? ;Пока нам не нужно
  lpfnHook          dd ? ;Пока нам не нужно
  lpTemplateName    dd ? ;Пока нам не нужно
OPENFILENAME ends
Многие параметры я оставил без объяснения так как мы ещё не умеем использовать операции для которых они существуют.


Теперь дополним нашу программу:
include kernel32.inc
include user32.inc
include def32.inc
include comdlg32.inc ;Добавляем функции библиотеки стандартных диалогов
include macros.inc   ;наши макросы (пока один;)
MAXFILENAME equ 260
  .386
  .model flat
  .data
error         db 'Ошибка',0
error1        db 'Файл не найден,0
error2        db 'Заданный файл не существует',0
filters       db 'Text files',0,'*.txt',0   ;Фильтры поиска
              db 'All files',0,'*.*',0,0
fileName      dd 0
programHandle dd 0
fileHandle    dd 0
memoryHandle  dd 0
memoryOffset  dd 0
SizeRW        dd 0
filename_     db MAXDILENAME dup(0)
ofn           OPENFILENAME<size ofn,?,?,offset filters,?,?,?,offset filename_,MAXFILENAME,0,?,0,?,?,?,?,0,?,?,?>
  .code
_start:
 null ebx ;используем наш макрос
 push ebx
 call GetModuleHandle
 mov programHandle,eax
 call GetCommandLine
 mov edi,eax
 mov al,20h
 mov ecx,-1
 repne scasb
 cmp byte ptr [edi],bl
 jne File_OK
 mov ofn.Flags,OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_EXPLORER
 push offset ofn
 call GetOpenFileName          ;Вызваем диалог
 test eax,eax                  ;Если не "отмена", то не ноль
 jz program_end
 mov fileName,offset filename_ ;для совместимости с уже написаным
File_OK:
 repe scasb
 dec edi
 mov esi,edi
 mov fileName,edi
 push ebx
 push FILE_ATTRIBUTE_ARCHIVE
 push OPEN_EXISTING
 push ebx
 push FILE_SHARE_READ
 push GENERIC_READ
 push esi
 call CreateFile
 test eax,eax
 jnz file_opened_OK
 mov eax,offset error2
 jmp program_error
file_opened_OK:
 mov fileHandle,eax
 push ebx
 push eax
 call GetFileSize
 mov edi,eax
 push eax
 push GMEM_MOVEABLE or GMEM_ZEROINIT
 call GlobalAlloc
 mov memoryHandle,eax
 push eax
 call GlobalLock
 mov memoryOffset,eax
 push ebx
 push offset SizeRW
 push edi
 push eax
 push fileHandle
 call ReadFile
 push fileHandle
 call CloseHandle
 call CheckSymbol
 push ebx
 push FILE_ATTRIBUTE_ARCHIVE
 push TRUNCATE_EXISTING
 push ebx
 push FILE_SHARE_WRITE
 push GENERIC_WRITE
 push fileName
 call CreateFile
 push ebx
 push offset SizeRW
 push edi
 push memoryOffset
 push FileHandle
 call WriteFile
 push fileHandle
 call CloseHandle
program_end:
 push memoryHandle
 call GlobalUnlock
 push memoryHandle
  call GlobalFree
 push ebx
 call ExitProcess
program_error:
 push MB_IconWarning
 push offset error
 push eax
 push ebx
 call MessageBox
 jmp program_end

CheckSymbol proc
 push edi
 mov al,'s'
 mov ecx,edi
 inc ecx
 mov edi,memoryOffset
loop_check:
 repne scasb
 test ecx,ecx
 jz end_check
 mov byte ptr [edi-1],'$'
 jmp loop_check
end_check:
 pop edi
 ret
CheckSymbol endp

 end _start
Следующие файлы Вы можете скачать к этому уроку:
0012asm - код программы
0012exe - компиляторы и сама программа
0012inc - файлы дополнения
0012lib - библиотеки импорта


На сегодня это всё. Если есть какие вопросы, пишите, обязательно отвечу.. Пишите, Dark_Lord@RusFAQ.ru, Dark_Lord@land.ru.

Сайт управляется системой uCoz