Форум общения вебмастеров Devil Art.Net



Ассемблер под Windows для чайников. Часть 7.

Опубликовано 25.07.2008 - В рубриках: Кодинг

Заждались вы, наверное, продолжения? Что ж, ожидание усиливает радость встреч. На сегодня у нас запланирован выход бета-версии 0.2 нашего первого текстового редактора. Он, к сожалению, по возможностям пока что немного уступает даже стандартному Блокноту, но это ведь только во благо вашему обучению. В дальнейшем, у вас будет повод для усовершенствования программы в меру своих возможностей и, самое главное, - знаний. Вы же не ждете, что я всю жизнь буду программировать за вас? Надеюсь, что нет, потому что основная цель этих занятий – развить у вас интерес к программированию на ассемблере под Windows, и изучить основные моменты. Дальше – будет видно. Время покажет, кому что ближе. Кого-то потянет в низкоуровневое программирование, кто-то, привязавшись к макросам, подастся в высокий уровень, забросив ассемблер, …но это все в будущем.

Ну, а сейчас, мы открываем привычный для нас FASMW.EXE и вводим код, электронную копию которого, как обычно, можно скачать на форуме. Код программы частично соответствует коду, приведенному в 6-й части цикла, но только частично. Так что, если решите сэкономить время и скопировать набранные куски из прошлой версии, - будьте предельно внимательны и сверяйте каждую строчку.

format PE GUI 4.0

entry start

include ‘win32a.inc’

include ‘encoding\WIN1251.INC’

MAXSIZE equ 260 ; максимальное имя файла в байтах

MEMSIZE equ 65537 ; размер временного буфера

section ‘.data’ data readable writeable

title db ‘Мой Первый Текстовый Редактор’,0

class db ‘FASMWIN32′,0

edit db ‘EDIT’,0

saveq db ‘Сохранить изменения ?’,0

filter db ‘Text Files’,0,’*.txt’,0

db ‘All formats’,0,’*.txt;*.asm;*.inc;*.ini’,0

db ‘All files’,0,’*.*’,0,0

fnsaved db 0 ;флаг имени файла 1=сохранено, 0=нет

errtxt db ‘Код ошибки: %u’,0

errbuf rb $-errtxt+10

fname rb MAXSIZE

hfile dd ?

hheap dd ?

pmem dd ?

sbuf dd ?

hwnd dd ?

hmenu dd ?

hedit dd ?

hacc dd ?

font dd ?

wc WNDCLASS 0,WindowProc,0,0,0,0,0,COLOR_BTNFACE+1,0,class

ofn OPENFILENAME sizeof.OPENFILENAME,0,0,filter,0,0,0,fname,MAXSIZE

msg MSG

client RECT

menuinfo MENUITEMINFO sizeof.MENUITEMINFO,MIIM_STATE

section ‘.code’ code readable executable

start:

invoke GetModuleHandle,0

mov [wc.hInstance],eax

mov [ofn.hInstance],eax

invoke LoadIcon,[wc.hInstance],IDI_MAIN

mov [wc.hIcon],eax

invoke LoadCursor,0,IDC_ARROW

mov [wc.hCursor],eax

invoke RegisterClass,wc

cmp eax,0

je error

invoke LoadAccelerators,[wc.hInstance],IDA_MAIN

mov [hacc],eax

invoke LoadMenu,[wc.hInstance],IDM_MAIN

mov [hmenu],eax

invoke CreateWindowEx,0,class,title,WS_VISIBLE+WS_OVERLAPPEDWINDOW,\

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,\

0,eax,[wc.hInstance],0

cmp eax,0

je error

mov [hwnd],eax

msg_loop:

invoke GetMessage,msg,0,0,0

cmp eax,0

je end_loop

invoke TranslateAccelerator,[hwnd],[hacc],msg

cmp eax,0

jne msg_loop

invoke TranslateMessage,msg

invoke DispatchMessage,msg

jmp msg_loop

error:

invoke GetLastError

invoke wsprintf,errbuf,errtxt,eax

invoke MessageBox,0,errbuf,0,MB_OK

end_loop:

invoke ExitProcess,[msg.wParam]

proc WindowProc hwnd,wmsg,wparam,lparam

push ebx esi edi

cmp [wmsg],WM_COMMAND

je .wmcommand

cmp [wmsg],WM_CREATE

je .wmcreate

cmp [wmsg],WM_SIZE

je .wmsize

cmp [wmsg],WM_SETFOCUS

je .wmsetfocus

cmp [wmsg],WM_CLOSE

je .EXIT

cmp [wmsg],WM_DESTROY

je .wmdestroy

.defwndproc:

invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]

jmp .finish

.wmcommand:

mov eax,[wparam]

cmp ax,IDM_NEW

je .NEW

cmp ax,IDM_OPEN

je .OPEN

cmp ax,IDM_SAVE

je .SAVE

cmp ax,IDM_SAVEAS

je .SAVEAS

cmp ax,IDM_EXIT

je .EXIT

cmp ax,IDM_UNDO

je .UNDO

cmp ax,IDM_CUT

je .CUT

cmp ax,IDM_COPY

je .COPY

cmp ax,IDM_PASTE

je .PASTE

cmp ax,IDM_DELETE

je .DELETE

cmp ax,IDM_SELECTALL

je .SELECTALL

cmp ax,IDM_ABOUT

je .ABOUT

jmp .finish

; обработчики сообщений меню файл:

.NEW:

call get_modified

invoke SendMessage,[hedit],WM_SETTEXT,0,0

mov [fnsaved],0

jmp .finish

.OPEN:

call get_modified

call open_file

jmp .finish

.SAVE:

call save_file

jmp .finish

.SAVEAS:

call get_save

jmp .finish

.EXIT:

call get_modified

invoke DestroyWindow,[hwnd]

jmp .finish

; обработчики сообщений меню правка:

.UNDO:

mov eax,EM_UNDO

jmp .send2editbox

.CUT:

mov eax,WM_CUT

jmp .send2editbox

.COPY:

mov eax,WM_COPY

jmp .send2editbox

.PASTE:

mov eax,WM_PASTE

jmp .send2editbox

.DELETE:

mov eax,WM_CLEAR

.send2editbox:

invoke SendMessage,[hedit],eax,0,0

jmp .finish

.SELECTALL:

invoke SendMessage,[hedit],EM_SETSEL,0,-1

jmp .finish

.ABOUT:

invoke DialogBoxParam,[wc.hInstance],IDD_ABOUT,[hwnd],AboutDialog,0

jmp .finish

.wmcreate:

invoke GetClientRect,[hwnd],client

invoke CreateWindowEx,WS_EX_CLIENTEDGE,edit,0,WS_VISIBLE+WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,[client.left],[client.top],[client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL

cmp eax,0

je .failed

mov [hedit],eax

invoke SendMessage,[hedit],EM_LIMITTEXT,MEMSIZE-1,0

invoke CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,RUSSIAN_CHARSET,OUT_RASTER_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH+FF_DONTCARE,NULL

cmp eax,0

je .failed

mov [font],eax

invoke SendMessage,[hedit],WM_SETFONT,eax,FALSE

mov eax,0

jmp .finish

.failed:

mov eax,-1

jmp .finish

.wmsize:

invoke GetClientRect,[hwnd],client

invoke MoveWindow,[hedit],[client.left],[client.top],[client.right],[client.bottom],TRUE

mov eax,0

jmp .finish

.wmsetfocus:

invoke SetFocus,[hedit]

mov eax,0

jmp .finish

.wmdestroy:

invoke PostQuitMessage,0

mov eax,0

.finish:

pop edi esi ebx

ret

get_modified:

invoke SendMessage,[hedit],EM_GETMODIFY,0,0

cmp eax,0

je .not_modified

invoke MessageBox,[hwnd],saveq,title,MB_YESNO + MB_ICONWARNING

cmp eax,IDYES

jne .not_modified

call save_file

.not_modified:

retn

save_file:

cmp [fnsaved],1

je create_file

get_save:

mov [ofn.Flags],OFN_EXPLORER + OFN_OVERWRITEPROMPT

invoke GetSaveFileName,ofn

cmp eax,0

je failed

create_file:

invoke CreateFile,fname,GENERIC_READ + GENERIC_WRITE,FILE_SHARE_READ + FILE_SHARE_WRITE,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0

mov [hfile],eax

invoke GetProcessHeap

mov [hheap],eax

invoke HeapAlloc,[hheap],HEAP_ZERO_MEMORY,MEMSIZE

mov [pmem],eax

invoke SendMessage,[hedit],WM_GETTEXT,MEMSIZE,[pmem]

invoke lstrlen,[pmem]

invoke WriteFile,[hfile],[pmem],eax,sbuf,0

mov [fnsaved],1

invoke SendMessage,[hedit],EM_SETMODIFY,0,0

invoke HeapFree,[hheap],0,[pmem]

invoke CloseHandle,[hfile]

retn

open_file:

mov [ofn.Flags], OFN_FILEMUSTEXIST + OFN_PATHMUSTEXIST + OFN_EXPLORER

invoke GetOpenFileName,ofn

cmp eax,0

je failed

invoke CreateFile,fname,GENERIC_READ + GENERIC_WRITE,FILE_SHARE_READ + FILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0

mov [hfile],eax

invoke GetProcessHeap

mov [hheap],eax

invoke HeapAlloc,[hheap],HEAP_ZERO_MEMORY,MEMSIZE

mov [pmem],eax

invoke ReadFile,[hfile],[pmem],MEMSIZE-1,sbuf,0

invoke SendMessage,[hedit],WM_SETTEXT,0,[pmem]

mov [fnsaved],1

invoke HeapFree,[hheap],0,[pmem]

invoke CloseHandle,[hfile]

retn

failed:

retn

endp

proc AboutDialog hwnd,msg,wparam,lparam

push ebx esi edi

cmp [msg],WM_COMMAND

je .close

cmp [msg],WM_CLOSE

je .close

mov eax,0

jmp .finish

.close:

invoke EndDialog,[hwnd],0

.processed:

mov eax,1

.finish:

pop edi esi ebx

ret

endp

section ‘.idata’ import data readable writeable

library kernel32,’KERNEL32.DLL’,\

user32,’USER32.DLL’,\

gdi32,’GDI32.DLL’,\

comdlg32,’COMDLG32.DLL’

include ‘api\kernel32.inc’

include ‘api\user32.inc’

include ‘api\gdi32.inc’

include ‘api\comdlg32.inc’

section ‘.rsrc’ resource data readable

IDM_MAIN = 101

IDA_MAIN = 201

IDD_ABOUT = 301

IDI_MAIN = 401

IDM_NEW = 1101

IDM_OPEN = 1102

IDM_SAVE = 1103

IDM_SAVEAS = 1104

IDM_EXIT = 1109

IDM_UNDO = 1201

IDM_CUT = 1202

IDM_COPY = 1203

IDM_PASTE = 1204

IDM_DELETE = 1205

IDM_SELECTALL = 1206

IDM_ABOUT = 1401

directory RT_MENU,menus,\

RT_ACCELERATOR,accelerators,\

RT_DIALOG,dialogs,\

RT_GROUP_ICON,group_icons,\

RT_ICON,icons,\

RT_VERSION,versions

resource menus,\

IDM_MAIN,LANG_RUSSIAN+SUBLANG_DEFAULT,main_menu

resource accelerators,\

IDA_MAIN,LANG_ENGLISH+SUBLANG_DEFAULT,main_keys

resource dialogs,\

IDD_ABOUT,LANG_RUSSIAN+SUBLANG_DEFAULT,about_dialog

resource group_icons,\

IDI_MAIN,LANG_NEUTRAL,main_icon

resource icons,\

1,LANG_NEUTRAL,main_icon_data

resource versions,\

1,LANG_NEUTRAL,version

menu main_menu

menuitem ‘&Файл‘,0,MFR_POPUP

menuitem <’Созд&ать‘,9,’Ctrl+N’>,IDM_NEW,0

menuitem <’&Открыть…’,9,’Ctrl+O’>,IDM_OPEN,0

menuitem <’&Сохранить‘,9,’Ctrl+S’>,IDM_SAVE,0

menuitem ‘Сохранить &как…’,IDM_SAVEAS,0

menuseparator

menuitem <’В&ыход‘,9,’Ctrl+Q’>,IDM_EXIT,MFR_END

menuitem ‘&Правка‘,0,MFR_POPUP

menuitem <’&Отменить‘,9,’Ctrl+Z’>,IDM_UNDO

menuseparator

menuitem <’&Вырезать‘,9,’Ctrl+X’>,IDM_CUT

menuitem <’&Копировать‘,9,’Ctrl+C’>,IDM_COPY

menuitem <’Вст&авить‘,9,’Ctrl+V’>,IDM_PASTE

menuitem <’&Удалить‘,9,’Del’>,IDM_DELETE

menuseparator

menuitem <’Выделить в&се‘,9,’Ctrl+A’>,IDM_SELECTALL,MFR_END

menuitem ‘&Вид‘,0

menuitem ‘&Справка‘,0,MFR_POPUP+MFR_END

menuitem ‘&О программе‘,IDM_ABOUT,MFR_END

accelerator main_keys,\

FVIRTKEY+FNOINVERT+FCONTROL,’N',IDM_NEW,\

FVIRTKEY+FNOINVERT+FCONTROL,’O',IDM_OPEN,\

FVIRTKEY+FNOINVERT+FCONTROL,’S',IDM_SAVE,\

FVIRTKEY+FNOINVERT+FCONTROL,’Q',IDM_EXIT,\

FVIRTKEY+FNOINVERT+FCONTROL,’Z',IDM_UNDO,\

FVIRTKEY+FNOINVERT+FCONTROL,’X',IDM_CUT,\

FVIRTKEY+FNOINVERT+FCONTROL,’C',IDM_COPY,\

FVIRTKEY+FNOINVERT+FCONTROL,’V',IDM_PASTE,\

FVIRTKEY+FNOINVERT+FCONTROL,’A',IDM_SELECTALL

dialog about_dialog,’О программе‘,40,40,172,60,WS_CAPTION+WS_POPUP+WS_SYSMENU+DS_MODALFRAME

dialogitem ‘STATIC’,<’Мой Первый Текстовый Редактор‘,0Dh,0Ah,’Copyright ‘,0A9h,’ BarMentaLisk 2008.’>,-1,27,10,144,40,WS_VISIBLE+SS_CENTER

dialogitem ‘STATIC’,IDI_MAIN,-1,8,8,32,32,WS_VISIBLE+SS_ICON

dialogitem ‘STATIC’,”,-1,4,34,164,11,WS_VISIBLE+SS_ETCHEDHORZ

dialogitem ‘STATIC’,’Написан при помощи FASM’,-1,12,42,100,20,WS_VISIBLE+SS_LEFT

dialogitem ‘BUTTON’,'OK’,IDOK,124,40,42,14,WS_VISIBLE+WS_TABSTOP+BS_DEFPUSHBUTTON

enddialog

icon main_icon,main_icon_data,’1.ico’

versioninfo version,VOS_NT_WINDOWS32,VFT_APP,VFT2_UNKNOWN,LANG_RUSSIAN+SUBLANG_DEFAULT,0,\

‘Comments’,'Написан при помощи FASM’,\

‘CompanyName’,'BarMentaLisk’,\

‘FileDescription’,’Текстовый редактор‘,\

‘ProductName’,<’Мой Первый’,0Dh,0Ah,’Текстовый Редактор’>,\

‘LegalCopyright’,<’Copyright ‘,0A9h, ‘BarMentaLisk 2008′>,\

‘FileVersion’,'0.2.0.0′,\

‘OriginalFilename’,'editor1.EXE’

В самом начале объявляются две константы: MAXSIZE и MEMSIZE. Первая – это максимальное количество байт под полный путь и имени файла, вторая – размер памяти, выделяемой под буфер для текста, включая завершающий строку ноль. В данной ситуации, максимальное количество символов в тексте у нас не должно превышать 65536 (64 КБ). Памяти выделяется на один байт больше, но в окне редактирования и в файле на жестком диске завершающий ноль записан не будет. При необходимости, вы всегда можете изменить данную константу по своему усмотрению в пределах от 2 до 2147483647 (7FFFFFFFh). Потому что максимальное количество символов, которое может вместить стандартный элемент EDIT =7FFFFFFEh, а минимальное =1.

В секции данных мало чего нового. Фильтр допустимых файлов (filter), состоит из одной или нескольких пар строк завершающихся нолем. Каждая пара – это отображаемое имя фильтра и собственно сам фильтр. Последняя пара должна завершаться двумя нолями. Переменную fnsaved мы будем использовать для того, чтобы определять, сохранено ли текущее имя файла в переменной fname. Еще у нас появилась структура OPENFILENAME. Список ее элементов вы можете увидеть в \INCLUDE\EQUATES\ COMDLG32.INC. Чтобы не париться с нудным описанием каждого элемента, - опишу только те, которые могут нам понадобиться в ближайшем будущем, тем более что последние 11 элементов я даже не инициализировал какими-либо значениями, - последние элементы структуры обычно автоматически инициализируются нолями, если опущены. Хотя, по правилам хорошего стиля, необходимо было бы дописать после MAXSIZE еще одиннадцать ноликов через запятую, но, тут уж, - кому как нравится.

lStructSize – размер структуры в байтах; hwndOwner – дескриптор окна-владельца диалогового окна открытия файла; hInstance – дескриптор исполняемого модуля; lpstrFilter – указатель на фильтр; lpstrCustomFilter – указатель на пользовательский фильтр; nMaxCustFilter – размер пользовательского фильтра; nFilterIndex – номер фильтра выбираемого по умолчанию; lpstrFile – указатель на полное имя файла; nMaxFile – размер буфера для полного имени файла; lpstrFileTitle – короткое имя файла (только имя без пути к файлу); nMaxFileTitle – размер буфера для короткого имени; lpstrInitialDir – открываемая по умолчанию директория; lpstrTitle – заголовок диалогового окна открытия/сохранения файла.

Переходим к секции кода. Начало похоже на предыдущую версию, только надо не забыть скопировать дескриптор исполняемого модуля еще и в ofn.hInstance. Затем, добавляем обработку сообщения WM_CLOSE, чтобы по команде закрытия можно было проверить, изменилось ли содержимое окна, и предложить сохранение, если изменилось.

Обработчики сообщений от элементов меню “Файл” теперь доступны (параметры MFS_GRAYED сняты с этих элементов в ресурсе menu) и готовы обрабатывать свои сообщения. При выборе пункта “Создать” (IDM_NEW -> .NEW), происходит вызов подпрограммы (метка get_modified). Команда call (от англ. Call – вызывать) очень похожа на команду jmp. Только, команда call сохраняет при этом в стек адрес возврата – адрес следующей за call команды, чтобы потом команда ret (от англ. Return – возвращаться) могла вернуть управление на команду следующую за call. Пара команд callret используется для возможности вызова какой-либо подпрограммы из разных мест программы. Например, макрос invoke, к которому мы уже так привыкли, тоже использует команду call, только предварительно запихивает в стек параметры вызываемой функции. На “том конце провода” функция API выполняет необходимые операции и при помощи команды ret возвращает управление следующей команде нашей программы. Сложно? Ерунда! Это я вам еще только в общих чертах обрисовал картину. Ну да ладно, не стоит на этом загоняться, - это уже почти хакерский уровень, а вы пока что как бы “чайники”. Запомните пока просто, что call вызывает, а ret возвращает.

Вот и в нашей ситуации выполнение команд временно перескакивает на метку get_modified. Там посылкой сообщения EM_GETMODIFY нашему окну редактирования, мы узнаем, был ли изменен текст окна: если изменен, вернется единица, иначе – ноль. Параметры у сообщения отсутствуют и потому выставляются в ноли. Если изменений нет, то значит и сохранять нечего, - возвращаемся. retn (Return Near) – это тот же ret, только для близких возвратов, - мы же находимся внутри процедуры WindowProc. Если же изменения имели место – переспрашиваем у пользователя, следует ли их сохранять. Если следует (IDYES), то вызываем save_file, иначе возвращаемся. На метке save_file проверяется, сохранен ли путь к нашему файлу (мы сами будем устанавливать переменную fnsaved в единицу, когда путь сохранен или файл открыт, и в ноль при создании нового файла, путь которого еще не определен). Если путь сохранен, - сразу переходим к метке create_file, иначе – вызываем диалог сохранения файла функцией GetSaveFileName. Эта функция имеет лишь один параметр, но зато какой – указатель на огромную структуру OPENFILENAME. Предварительно, устанавливаем флаги OFN_EXPLORER для открытия диалога в стиле проводника windows и OFN_OVERWRITEPROMPT для подтверждения перезаписи файла, если он существует. GetSaveFileName возвращает ноль в случае, если пользователь отменил сохранение. Иначе, в буферы помещается имя файла, а возвращаемое значение отлично от ноля. Таким образом, на метке create_file, в fname содержится полное имя файла.

Функция CreateFile создает или открывает объект ввода/вывода. Параметры:

  1. Имя объекта;

  2. Права доступа: GENERIC_READ – чтение, GENERIC_WRITE – запись, или оба сразу;

  3. Права на совместный одновременный доступ к файлу несколькими процессами: 0 – доступ другим процессам запрещен до закрытия файла, FILE_SHARE_READ – разрешено чтение, FILE_SHARE_WRITE – разрешена запись, FILE_SHARE_DELETE – разрешено удаление;

  4. Атрибуты безопасности: 0 для значений по умолчанию;

  5. Способ открытия файла: CREATE_NEW – создать новый файл, ошибка, если файл существует, CREATE_ALWAYS – создать новый файл, перезаписывает старый, если файл существует, OPEN_EXISTING – открыть файл, ошибка, если файл не существует, OPEN_ALWAYS – открыть файл, если файл не существует – он будет создан, TRUNCATE_EXISTING – открыть файл и очистить его содержимое, ошибка, если файл не существует;

  6. Набор атрибутов (скрытый, системный и т.д.);

  7. Файл-шаблон атрибутов.

При успешном создании/открытии файла возвращается его дескриптор, если файл отсутствует – возвращается 0, в случае ошибки возвращается -1.

Функция GetProcessHeap возвращает дескриптор кучи вызывающего функцию процесса. Куча – это область виртуальной памяти, под которую не выделяется реальная физическая память, но по мере заполнения кучи данными, диспетчер, управляющий кучами (heap manager), выделяет под нее физическую память. Функция HeapAlloc выделяет блок памяти в куче и возвращает указатель на выделенный блок. Параметры: дескриптор кучи; флаги способа выделения памяти (HEAP_ZERO_MEMORY – проинициализировать блок нулевыми значениями); размер выделяемого блока в байтах. После выделения блока, мы копируем текст, завершающийся нолем, из окна редактирования в этот блок, отсылкой окну редактирования сообщения WM_GETTEXT. Функция lstrlen (параметр – адрес строки) возвращает длину строки в символах без учета завершающего ноля. Функция WriteFile записывает данные в файл. Ее параметры: дескриптор файла; указатель на данные; размер данных в байтах; буфер для ответа сколько байт удалось записать; указатель на структуру OVERLAPPED для дополнительных сведений. В случае ошибки возвращается ноль. Записываем в fnsaved единицу, - файл сохранен и его имя хранится в переменной fname. Отсылаем окну редактирования сообщение EM_SETMODIFY, - первый параметр 0 означает, что содержимое окна не изменялось, второй параметр не используется. Функция HeapFree освобождает указанный блок памяти в куче. Параметры: дескриптор кучи; флаги; указатель на блок памяти. Функция CloseHandle закрывает объект (в нашем случае – открытый файл), чей дескриптор указан в единственном параметре. Теперь возвращаемся к следующей после call команде.

При создании файла, после вызова подпрограммы get_modified, мы очищаем содержимое окна редактирования и устанавливаем fnsaved в ноль, так как имя нового файла пока неизвестно.

При открытии файла, мы опять же вызываем подпрограмму сохранения старого файла (get_modified), а затем вызываем подпрограмму открытия (open_file). Там все почти аналогично подпрограмме get_modified. Устанавливаем флаги OFN_FILEMUSTEXIST (открываемый файл должен существовать), OFN_PATHMUSTEXIST (открываемый путь к файлу должен существовать) и OFN_EXPLORER. Функция GetOpenFileName вызывает диалог открытия файла и возвращает его имя в буфер fname. Открываем выбранный файл функцией CreateFile. Выделяем память. Функция ReadFile аналогична функции WriteFile, только не пишет данные в файл, а читает их. Размер данных для чтения указываем MEMSIZE-1, потому что последний байт в памяти необходимо оставить нулевым, – завершающий строку ноль. Устанавливаем прочитанные данные текстом окна редактирования (WM_SETTEXT). Задвигаем в fnsaved единицу, - файл открыт и его имя нам известно. Освобождаем память. Закрываем файл.

При выборе пункта “Сохранить” подпрограмма сохранения вызывается с метки save_file, дабы избежать вопроса о необходимости сохранения. При выборе пункта “Сохранить как…” – вызываем сохранение с метки выбора файла для сохранения.

Выбор пункта “Выход” или закрытие программы приведет к выполнению get_modified и вызову функции DestroyWindow с дескриптором окна в качестве единственного параметра.

На метке failed ничего не происходит, просто возврат без выполнения каких-либо действий. Здесь вы самостоятельно можете добавить дополнительную обработку ошибок и вывод соответствующего сообщения. Так же можете на свое усмотрение внести проверку успешного завершения после каждой важной функции подпрограмм чтения и записи файла.

Согласен, что некоторые моменты разъяснены не так подробно, как хотелось бы, но тут я уповаю на вашу сообразительность. Если что-то вам непонятно – возможно стоит еще раз прочесть предыдущие уроки. В любом случае не падайте духом и не теряйте уверенности в своих силах и возможностях.

Все приводимые примеры были протестированы на правильность работы под Windows XP и, скорее всего, будут работать под другими версиями Windows, однако я не даю никаких гарантий их правильной работы на вашем компьютере.

Исходные тексты программ вы можете найти на форуме: http://forum.sa-sec.org/index.php?showtopic=766. BarMentaLisk, q@sa-sec.org SASecurity gr.

Скачать





Комментарии

Оставьте отзыв




:mrgreen: :neutral: :twisted: :shock: :smile: :???: :cool: :evil: :grin: :oops: :razz: :roll: :wink: :cry: :eek: :lol: :mad: :sad:

Delphiland
Счётчик тИЦ PR Rambler's Top100 Rating All.BY