Сборник по задачам и примерам Assembler



Сборник по задачам и примерам Assembler

         

Работа с файлами в программах на ассемблере

Очевидно, целесообразно рассматривать прикладную систему как некоторую
совокупность данных и операций, определенных па этих данных, а не просто
как набор программ, взаимодействующих между собой посредством
обмена данными. Программы — это всего лишь рабочие инструменты,
в то время как данные — это своего рода исходное сырье,
из которого вырабатывается конечный продукт. Набор данных вне среды
приспособленной для его использования, не представляет
никакой ценности, однако в рамках такой среды именно
набор данных приобретает основное значение.
Динар Нурмухамедович Бибишев

Язык ассемблера не содержит средств для работы с файлами. Если такая необходимость возникает, то программа должна содержать фрагменты кода, в которых производится обращение к средствам операционной системы, осуществляющим взаимодействие с файловой системой. Это лишний раз подтверждает тот факт, что в области взаимодействия с внешним миром программа на ассемблере оказывается привязанной как к конкретной аппаратной, так и конкретной операционной платформам. В сегодняшней ситуации программисту все еще приходится сталкиваться с необходимостью программирования для MS DOS. Поэтому изучение средств для работы с файлами этой операционной платформы не потеряло своей актуальности и эти средства в плане совместимости поддерживаются различными реализациями Windows. В реализации MS DOS 7.0 введена поддержка длинных имен файлов, используемых системой файлового ввода-вывода Win 32. Таким образом можно выделить три аспекта работы с файлами из программ на ассемблере:

работа с системой файлового ввода-вывода MS DOS, использующей короткие имена (по схеме 8.3); работа с системой файлового ввода-вывода MS DOS, использующей длинные имена (длиной до 255 символов);

работа с системой файлового ввода-вывода Win 32; использование файлов особого вида, поддерживаемых Win 32 — проецированных на память.

Целью данной главы является предоставить читателю фрагменты кода, реализующего наиболее часто используемые операции по работе с файлами на различных операционных платформах. При этом нам не обойтись без определенной систематизации, но это будет сделано лишь для того, чтобы создать у читателя общее представление об этом вопросе. Если у вас впоследствии возникнет потребность в реализации файловых функций, чье полное практическое описание отсутствует в материале этой главы, то более подробные сведения о них можно будет найти в других справочных руководствах, например MSDN. Далее, используя общие принципы организации ввода-вывода, рассмотренные ниже, вы сможете без труда решить возникшую проблему. Материалы всех разделов подобраны так, чтобы читатель мог познакомиться с общими принципами организации ввода-вывода в каждом случае, начиная от самых простых.

Работа с файлами в MS DOS (имена 8.3)

В основе файловой системы MS DOS лежит древовидная структура каталогов. Корень этой структуры представляет собой совокупность ограниченного числа дескрипторов, описывающих файлы и каталоги (подкаталоги) следующего уровня. Подкаталог представляет собой файл особого типа, который содержит дескрипторы файлов и подкаталогов очередного нижележащего уровня. В отличие от корневого каталога количество дескрипторов в подкаталоге не ограничено и определяется только размером диска. Дескриптор представляет собой экземпляр структуры размером 32 байта. Поля этой структуры содержат различную информацию о файле: идентификатор файла и его характеристики — дата и время создания (модификации), номер начального кластера, длина файла и его атрибуты.
Для использования файла в программе необходимо выполнить следующие операции:

создание нового файла; открытие существующего файла; запись/чтение в/из файл(а); закрытие файла.

Операционная система MS DOS поддерживает эти операции с помощью набора функций прерывания 21h. Кроме этих функций данное прерывание содержит функции для работы с каталогами:

создать каталог; удалить каталог; сменить каталог.

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

Создание, открытие, закрытие и удаление файла

Прежде чем использовать файл в программе, его необходимо открыть с помощью функции 3dh прерывания 21h. Если файл не существует, то перед открытием
его нужно создать. Оба эти действия выполняются одной из следующих функций: 3ch, 5bh, 5ah, 6ch.

Создание файла с усечением существующего до нулевой длины

Вход: АН = 3Ch; CX = атрибуты файла (значения битов: 0=1 — только чтение; 1= 1 — скрытый файл; 2=1 — системный файл; 3=0 — игнорируется; 4=0 — зарезервирован (каталог), должен быть равен 0; 5 — бит архивации; 6= 0 — резерв; 7=1 — общий файл в системе Novell Netware; 8...15=0 — резерв); DS:DX — ASCIZ-имя файла.
Выход: CF=O — АХ = дескриптор файла; CF=1 — АХ = код ошибки (3 — нет такого пути; 4 — нет свободного дескриптора файла; 5 — доступ отказан).

хогсх.сх :атрибуты файла - обычный файл Ids dx,point_fname:
формируем указатель на имя файла movah.5bh :номер функции DOS
int21h открываем файл
jnc ml : обойдем открытие файла
moval,02h ;режим доступа
movah.3dh ;номер функции DOS
int 21h : открываем файл
jc exit :переход, в случае ошибки
mi: :действия при успешном открытии файла:
mov handle.ax :сохраним дескриптор файла

Открытие или создание файла с расширенными возможностями

Функция 6Ch появилась в последних версиях MS DOS (DOS 4.0+). С ее появлением устраняется необходимость отслеживать существование создаваемого файла. Для корректной работы достаточно задать нужные значения в соответствующих регистрах. Анализ возможных значений показывает, что данная функция фактически заменяет существовавшие до этого функции создания и открытия файлов.
Вход: АХ = 6C00h; BL = флаги — режим открытия (значения битов: 7 — наследование; 4-6 — режим разделения; 3=0 — резерв; 0-2 — режим доступа); ВН = флаги (значения битов: 6=0 — использовать стандартную для MS DOS буферизацию; 6=1 — отменить стандартную для MS DOS буферизацию; 5=0 — использовать обычный обработчик ошибок (int 24h); 5=1 — не использовать обычный обработчик ошибок (int 24h), для выяснения причины ошибки использовать функцию 59h int 21h); CX = атрибуты создаваемого (и только) файла; DL = действия, если файл существует или не существует (значения бит: 0-3 — действие, если файл существует (0000 — вернуть ошибку; 0001 — открыть файл; 0002 — открыть файл без сохранения существующего); 4-7 — действие, если файл не существует (0000 — вернуть ошибку; 0001 — открыть файл; 0002 — создать и открыть файл); DH = 00h — резерв; DS:SI — адрес строки с ASCIZ-именем файла.
Выход: CF = 0 — успешное выполнение функции: АХ = дескриптор файла, СХ = состояние (0 — файл открыт; 1 — файл создан и открыт; 2 — файл открыт без сохранения содержимого существующего файла); CF = 1 — АХ = код ошибки.
Следующий фрагмент программы показывает вариант применения функции 6Ch.

:prg07_04.asm - программа демонстрации открытия или создания файла :с расширенными возможностями в текущем каталоге функцией 6Сп.
.data
handle dw 0 :дескриптор файла
filename db 'my_file.txt'.0
point_fname dd filename
.code
хогсх.сх атрибуты файла - обычный файл
movbx.2 :режим доступа обычный - доступ для чтения-записи
movdx.l :если файл существует, то открыть его. в обратной случае вернуть ошибку
(для эксперимента)
Ids si .point_fname-.формируем указатель на имя файла movah.6ch :номер функции DOS int 21h открываем файл jnc ml ;если файл существовал, то переход movdx.lOh -.открыть файл movah.6ch :номер функции DOS int 21h :открываем файл jc exit -.переход в случае ошибки ml: :действия при успешном открытии файла: mov handle.ах :сохраним дескриптор файла

Закрытие файла

В конце работы с файлом его нужно закрыть. Но это действие не является обязательным, так как функция 4сп, которая завершает выполнение программы, в числе прочих действий выполняет и закрытие всех файлов. Вход: АН = 3Eh; BX = дескриптор файла, полученный при его открытии. Выход: CF = 0 — АХ = не определен; CF = 1 — АХ = код ошибки: 6 — недопустимый
дескриптор.
Во время закрытия файла выполняются все незаконченные операции записи на диск в элементе каталога, соответствующего файлу, модифицируются различные поля, в том числе поля времени и даты устанавливаются в текущее время.

;prg07_05.asm - программа демонстрации закрытия файла функцией 3Eh.

:.........
.data
handle dw 0 :дескриптор файла filename db 'my_file.txt',О point fname dd filename
;......:
.code :*......
хогсх.сх :атрибуты файла - обычный файл
Ids dx.point_fnanve :фориируем указатель на имя файла
movah.5bh :номер функции DOS
int 21h :открываем файл
jnc ml ;обойдем открытие файла
moval.02h :режим доступа
1movah.3dh -.номер функции DOS
int 21h :открываем файл
jc exit :переход в случае ошибки
ml: :действия при успешном открытии файла:
mov handle.ах ;сохраним дескриптор файла
т2: ;закрываем файл:

В случае задания имени, как в примере выше, файл будет создан в корневом каталоге текущего диска. Для того чтобы разместить файл в конкретном каталоге, необходимо указать полный путь к нему с завершающим символом ' \' и 13 нулевыми байтами на конце, например:
filename db 'e:\asm_on_a\'.13 dup(0),0

Чтение, запись, позиционирование в файле

При работе с материалом данного раздела помните, что функции чтения и записи можно использовать не только с дескрипторами заранее открытых файлов, но и с дескрипторами стандартных устройств. Эти дескрипторы имеют постоянное значение и доступны в любое время функционирования системы: 0 — клавиатура; 1 и 2 — экран; 3 — последовательный порт СОМ1; 4 — параллельный порт LPT1.

Установка текущей файловой позиции

Чтение-запись в файле производятся с текущей файловой позиции, на которую указывает файловый указатель. Функция 42h MS DOS предоставляет гибкие возможности как для начального, так и для текущего позиционирования файлового указателя для последующей операции ввода-вывода.
Вход: АН = 42h; BX = дескриптор файла, полученный при его открытии; AL = начальное положение в файле, относительно которого производится операция чтения-записи (OOh — смещение (беззнаковое значение в CX:DX) от начала файла; O1h — смещение (значение со знаком в CX:DX) от текущей позиции в файле; 02h — смещение (значение со знаком в CX:DX) от конца файла); CX:DX = смещение новой позиции в файле относительно начальной.
Выход: CF = 0 — DX:AX = значение новой позиции в байтах относительно начала файла; CF = 1 — АХ = код ошибки: 1 — неверное значение в AL; 6 — недопустимый дескриптор файла.
Методы позиционирования, заданные величиной в AL, по-разному трактуют значение в паре регистров CX:DX. Метод al = 00 трактует значение в CX:DX как абсолютное. Два других метода (al = 01 и al = 02 ) трактуют содержимое CX:DX как значение со знаком. Необходимо быть внимательным при выполнении операции позиционирования для избежания последующих ошибок при операции чтения-записи. Так, значение в СХ: DX, позиционирующее указатель, может указывать за пределы файла. При этом выделяются два случая:

значение в СХ: DX указывает на позицию перед началом файла — в этом случае последующая операция чтения-записи будет выполнена с ошибкой; значение в СХ:DX указывает на позицию за концом файла — в этом случае последующая операция записи приведет к расширению файла в соответствии со значением в CX:DX.

Примеры использования функции 42h приведем при рассмотрении функций чтения-записи.

Запись в файл или устройство

Запись в файл производится функцией 40h с текущей позиции файлового указателя. Вход: АН = 40 h; ВХ = дескриптор файла; СХ = количество байтов для записи;
DS:DX — указатель на область, из которой записываются данные. Выход: CF = 0 — АХ = число действительно записанных байтов в файл или устройство; CF = 1 — АХ = код ошибки: 5 — в доступе отказано; 6 — недопустимый дескриптор.
Если при вызове функции 40h регистр СХ равен нулю, то данные в файл не записываются и он усекается или расширяется до текущей позиции файлового указателя. Если СХ не равен нулю, то данные в файл записываются начиная с текущей позиции файлового указателя. Операция записи также продвигает файловый указатель на число действительно записанных байтов.
Положение файлового указателя можно изменять явно с помощью функции 42h. Вначале приведем пример программы, выводящей данные на экран.

:prg07_08.asm - программа демонстрации вывода на экран строки функцией 40h.
.data
string db 'строка для вывода на экран функцией 40h'
len_string=$-stnng point_fname dd string
..........
.code
movbx.l -.стандартный дескриптор - экран
mov cx.1en_string
Ids dx.point_fname;формируем указатель на строку string
movah.40h -.номер функции DOS
int 21h ;выводим
jc exit ;переход в случае ошибки
пор -.для тестирования

Далее приведем пример программы, которая заполняет файл my_file.txt данными в виде строк символов, вводимых с клавиатуры. Длина строк — не более 80 символов. Нажатие клавиши Enter после ввода каждой строки означает, что эта строка символов должна являться отдельной строкой файла my_file.txt. Для этого перед выводом каждой строки в файл в конце ее необходимо вставлять символы OdOah. При нажатии клавиши Пробел в начале ввода очередной строки (ASCII-код — 3210 или 2016) направление ввода данных в файл изменяется следующим образом: файл расширяется на величину, равную количеству уже введенных символов, и дальнейший ввод осуществляется с конца файла. Завершение работы программы определяется моментом, когда оба введенных потока Ь в файле встречаются (не перекрываясь).

:prg07_09.asm - программа заполнения файла my_file.txt данными в виде строк символов.
:вводимыми с клавиатуры.
buf_Oahstruc
len_buf db 83 ;длина buf_0ah
len_in db 0 действительная длина введенного слова (без учета 0dh)
buf_in db 82 dup (20h) :буфер для ввода Сс учетом 0dh и позднее добавляем Oah)
ends
.data
handle dw 0 :дескриптор файла
filename db 'my_file.txt',0
point_fname dd filename
buf buf_0ah<>
prev_d label dword ;для сохранения длины предыдущей строки при выводе с конца файла prev dw 0
dw 0
middle dd 0 ;позиция в середине файла, при достижении которой снизу выходим :из программы
.code
:-----открываем файл-----...............................--
хогсх.сх ;атрибуты файла - обычный файл
movbx,2 ;режим доступа - доступ для чтения-записи, режим буферизации MS DOS
movdx,12h ;если файл существует, то открыть его без сохранения прежнего содержимого, :в обратном случае создать его
Ids si ,point_fname:формируем указатель на имя файла
movah.6ch ;номер функции DOS
int 21h открываем (создаем) файл
jc exit :если ошибка, то переход на конец ;действия при успешном открытии файла:
mov handle.ax ,-сохраним дескриптор файла ;—позиционируем файловый указатель с начала файла.......
mov ah.42h
хог al,al
хог ex,ex
хог dx.dx
mov bx, handle
int 21h cycl: ;вводим очередную строку с клавиатуры
lea dx.buf
mov ah,Oah
Int 21h ;для красоты ввода выводим на экран символ Oah
mov dl .Oah
mov ah.2
int 21h
emp buf.buf_in.20h;первый символ введенной строки сравниваем с пробелом
je revers ;переход на изменение ввода - добавляем Oah в конец введенной строки
lea si.buf.buf_in
mov al .buf .lenjn
cbw push si
add si ,ax
incsi учитываем неучтенный в lenjn символ 0dh
mov byte ptr [si],Oah H--......вывод в файл:..........................---........
I popdx указатель на область, откуда будем выводить строку
mov bx.handle
add ax,2 учитываем неучтенный в len_in символ 0dh
movcx.ax :длина выводимых данных
mov ah.40h
int 21h
jmp cycl
revers: ;записываем файл с конца, предварительно расширив его ;узнаем. сколько было уже записано до этого: ;для этого вначале сбрасываем буферы на диск
mov bx.handle
mov ah.68h
int 21h ;теперь можно и узнать - определение длины файла:
mov al ,2
хог сх.сх
хог dx.dx ;CX:DX -0 - нулевое смещение
mov ah,42h
int 21h :в DX:AX возвращается длина файла в байтах
jc exit :если ошибка :формируем полную длину в edx
shl eax,16
shld edx.eax,16
mov middle.edx сохраним как условие выхода из программы при достижении снизу расширение файла с помощью функции 42h int 21h и последующей записи :умножаем длину на 2. при первой операции записи файл расширится:
shl edx.l
shld ecx.edx.16
mov al.O
хог сх.сх
mov ah.42h
int 21h расширяем файл, устанавливая указатель
jc exit :если ошибка расширим файл, выведя последнюю введенную строку с пробелом:
cycl2: lea si,buf,buf_in
mov al .buf .lenjn
cbw ptush si
add si.ax
incsi учитываем неучтенный в lenjn символ 0dh
добавляем Oah в конец введенной строки
mov byte ptr [si],Oah ;выводим в файл:
popdx указатель на область, откуда будем выводить строку
add ах.2 учитываем неучтенный в len_in символ 0dh
movcx.ax :длина выводимых данных
movprev.ax .сохраним длину для корректировки при выводе следующей строки
mov bx.handle movah.40h int 21h jc exit
;сбрасываем буфер, чтобы смотреть изменения в файле при работе в отладчике -:легче запретить (см. обсуждение ниже)
mov bx,handle
mov ah,68h Int 21h :вводим очередную строку с клавиатуры
lea dx.buf
mov ah.Oah
Int 21h :для красоты ввода выводим на экран символ Oah
mov dl .Oah
mov ah,2
int21h
;......использование 42h с отрицательным смещением относительно
:текущего значения файлового указателя:
устанавливаем файловый указатель в позицию вывода следующей строки
;с учетом того, что выводим с конца (текущей позиции) файла:
хог есх.есх
mov al.buf,len_in
cbw
add prev.ax
add prev.2 учитываем наличие OdOah
sub ecx.prev_d :получаем отрицательное смещение - сформируем его в паре СХ:DX
shrd edx,ecx,16
shr edx.16 :довернем edx
shr ecx.16 :и есх устанавливаем файловую позицию для записи очередной строки
mov bx,handle
mov ah.42h
moval.l ;смещение от текущей позиции
int 21h :сравним текущую позицию с middle
shl eax.16
shld edx,eax,16
cmp edx,middle
jl exit
jmp cycl2 exit:

Программа выглядит не очень эстетично, но главная ее цель достигнута — показать работу с файловым указателем при записи в файл. Мы попробовали разные варианты: позиционирование на конец файла (при этом можно узнать длину файла); использование отрицательного смещения (задавая нулевое значение в CX:DX при al = 1 можно получить в DX:AX текущую позицию в файле); расширение файла путем задания в СХ: DX заведомо большего значения, чем длина файла. Как видно из программы выше, все эти и другие эффекты достигаются за счет манипулирования значениями в парах СХ :DX и DX:AX, а также в регистре AL, где задается начальное положение в файле, относительно которого производится операция чтения-записи.
В заключение рассмотрения функции 40h записи в файл отметим то, для чего мы использовали функцию сброса буферов на диск 68h. Для этого коротко необходимо коснуться проблемы буферизации ввода-вывода в MS DOS. MS DOS ис-
пользует буферизацию ввода-вывода для ускорения работы с диском. При этом, р частности, данные, записываемые на диск, не записываются на него сразу, а по-щешаются вначале в буфер. Запись буфера на диск производится при его заполнении- Буферизацию эффективно использовать при интенсивной работе с одними и теми же данными. Тогда при необходимости чтения данных с диска они 6уДУт читаться из буфера. В нашей программе буферизация нам только мешала, так как при работе в отладчике мы не могли своевременно наблюдать за изменениями выходного файла my_file.txt Для этого нам приходилось использовать функцию 68h для принудительного сохранения буферов на диск. Вход: АН = 68h; BX = дескриптор файла. Выход: CF = 0 в случае успеха; CF = 1 — АХ = код ошибки.
В результате работы функции все данные из буферов дисков DOS немедленно записываются на диск, при этом модифицируется соответствующий файлу
элемент каталога.
Для нашей задачи буферизацию лучше вовсе запретить, тогда отпадет необходимость в принудительном сохранении строк в файле для того, чтобы в динамике отслеживать его изменения. Для этого при вызове функции 6ch в регистре ВН необходимо установить бит 6 следующим образом: 6 = 0 — использовать стандартную для MS DOS буферизацию; 6 = 1 — отменить стандартную для MS DOS буферизацию. В нашем примере это можно сделать так:

:......открываем файл-------------------------------------
хогсх.сх атрибуты файла - обычный файл
mov bx.4002h :режим доступа - доступ для чтения-записи, запрет буферизации
movdx,12h :если файл существует, то открыть его без сохранения прежнего
содержимого, в обратном случае создать файл Ids si.point_fname:формируем указатель на имя файла movah.6ch :номер функции DOS int21h открываем (создаем) файл jc exit :если ошибка, то переход на конец
--------------------------------------------------------------------------

Все вызовы функции 68h в приведенной выше программе можно закомментировать.

Чтение из файла или устройства

Чтение из файла в область памяти осуществляется функцией 3Fh.
Вход: АН = 3Fh; BX = дескриптор файла; СХ = количество байтов для чтения; DS-.DX — указатель на область памяти, в которую помещаются прочитанные байты. Выход: CF = 0 — АХ = число действительно прочитанных байтов из файла; CF = 1 — АХ = код ошибки: 5 — в доступе отказано; 6 — недопустимый дескриптор.

Чтение данных производится начиная с текущей позиции в файле, которая после успешного чтения смещается на значение, равное количеству прочитанных байтов. Если в качестве файла используется стандартная консоль (клавиатура), то чтение производится до первого символа CR (carriage return) с кодом 0dh, соответствующего нажатию клавиши Enter. Это, кстати, еще один способ ввода " Данных с клавиатуры в программу. Кроме символов введенной строки в ее конец помещаются символы 0dh и Oah. Это необходимо учитывать при задании размера буфера для ввода. Способ ввода данных с экрана с помощью функции 3Fh . стрирует приведенный ниже пример программы.

:prg07_10.asm - программа демонстрации ввода данных с экрана с помощью функции 3Fh.
.data
string db 80 dup Г ") 1en_string=$-string point_fname dd string
.code
:.........вводим с экрана......-----.....----------------
movbx.O стандартный дескриптор - клавиатура
mov cx.len_string
Ids dx.point_fname:формируем указатель на строку string
movah,3fh ;номер функции DOS
int 21h
jc exit :переход в случае ошибки ;---------выводим на экран---------------------...........
movbx.l стандартный дескриптор - экран :две строки ниже в данном случае можно опустить
mov ex.len_string
Ids dx.point_fname;0opMnpyeM указатель на строку string
movah.40h ;номер функции DOS
int 21h открываем файл
jc exit :переход в случае ошибки

Для демонстрации работы функции с дисковым файлом приведем программу чтения и вывода на экран содержимого файла, имя которого вводится в командной строке. Побочная цель этой программы — научиться обрабатывать в программе командную строку DOS. Поясним последний момент. Содержимое командной строки, следующее за именем программы при ее вызове и называемое хвостом команды, помещается в префикс программного сегмента (PSP) со смещением 80h от его начала и максимально имеет размер 128 байт. Первый байт этой области содержит длину хвоста команды, а первый символ хвоста, при его наличии, располагается со смещением 81h от начала PSP. Последний символ хвоста команды — всегда 0dh. Начало PSP найти очень легко — когда программа загружается в память для исполнения, то загрузчик устанавливает регистры ES и DS равными адресу PSP.

:prg07_ll.asm - программа чтения и вывода на экран содержимого файла. ;имя которого вводится в командной строке.
.data
filejiame db 128 dup (" ") ;буфер, в который будет помещен путь к файлу
point_fname dd file_name
string db 80 dup (" ")
len_stnng=$-string
point_string dd string
>handle dw 0 дескриптор файла
[size_f dd 0 :размер файла
.code
main: :копируем командную строку в filejiame
;вначале уберем (установкой указателя) ведущие пробелы в командной строке
:перед путем к файлу: movdi ,81h mov al," " mov ex. 128 repe scasb
dec di push di pop si
movax.@data -.адрес сегмента данных - в регистр АХ
mov es.ax :ax в es iTOvcl.ds:[80h] deccl
lea di .filejiame rep movsb push es pop ds
:--------открываем файл--......-----------------.........
moval.OOh :режим доступа - только чтение
Ids dx.point_fname:формируем указатель на имя файла
movah.3dh ;номер функции DOS
int 21h открываем файл
jc exit :переход в случае ошибки
mov handle.ax
;--------определяем размер файла-------------------------
raovbx.ax -.дескриптор файла - в bх mov al .2 xor ex. ex
xordx.dx :CX:DX =0 - нулевое смещение mov ah.42h
int 21h ;в DX:AX возвращается длина файла в байтах jc exit
:если ошибка :формируем полную длину в
edx shl eax.16 shld edx.eax.16 mov size_f.edx сохраним как условие выхода из программы при достижении снизу
;--------устанавливаем указатель на начало файла---.......
mov Ьх.handle :дескриптор файла - в Ьх
mov al .0
xor ex.ex
xordx.dx ;CX:DX =0 - нулевое смещение
mov ah,42h
int 21h :текущий указатель в начале файла
jc exit :если ошибка
;.........читаем файл по lenjstring байт................---
cycl: mov bx.handle :дескриптор файла в Ьх mov cx.lenjsthng
Ids dx.pointjstring :формируем указатель на строку string movah.3fh
:номер функции DOS int 21h :открываем файл jc exit ;переход в случае ошибки
;.........выводим на экран целиком.....---------.......----------
movbx.l стандартный дескриптор - экран
mov cx.len_string
Ids dx.point_string .формируем указатель на строку string movah.40h
;номер функции DOS
int 21h открываем файл
jc exit :переход в случае ошибки
cwde расширяем количество выведенных байт
sub size_f.eax cmp size_f.О
jleexit :достигли конца файла
. jmp cycl
exit: :выход из программы
mov al .1 int 21h
.......

He забывайте после определения размера файла возвращать файловый указатель в нужное место файла.

Получение и изменение атрибутов файла

MS DOS позволяет получить для анализа и при необходимости изменить имя файла, байт атрибутов файла, время и дату его последней модификации в элементе каталога, соответствующего этому файлу. Для этого предназначены функции 43h, 56h, 57h. Подфункция 00 функции 43h прерывания 21h предназначена для получения слова атрибутов файла.

Получить атрибуты файла

Вход: АХ = 4300h; DS:DX — ASCIZ-строка с именем (путем) файла.
Выход: CF = 0 — СХ = слово атрибутов файла; CF = 1 — АХ = код ошибки: 1 — неверное значение в AL; 2 — файл не найден; 3 — несуществующий путь; 5 — доступ запрещен.

:prg07_12.asm - программа демонстрации получения атрибутов файла.
.data
fname db "maket.asm".
point_fname dd fname
.code
:----.....получим атрибуты файла-----------------........-
Ids dx.point_fname:формируем указатель на строку string movax.4300h ;номер функции DOS int 21h
jc exit :переход в случае ошибки :в сх атрибуты (см. ниже)

Напомним формат байта атрибутов:

Биты Описание
7 Разделяемый в Novell NetWare
6 Не используется
5 Архивный
4 Каталог
3 Метка тома (только исполнение Novell NetWare)
2 Системный
1 Скрытый
0 Только чтение

Установить атрибуты файла

Подфункция 01 функции 43h прерывания 21h предназначена для установления
слова атрибутов файла.
Вход: АХ = 4301п; СХ = новое слово атрибутов файла; DS:DX — ASCIZ-строка с именем (путем) файла.
Выход: CF = 0 — АХ = не определен; CF = 1 — АХ = код ошибки: 1 — неверное значение в AL; 2 — файл не найден; 3 — несуществующий путь; 5 — доступ запрещен.

Переименовать файл

Для переименования файла используется функция 56h.
Вход: АН = 56h; DS:DX — ASCIZ-имя существующего файла; ES:DI — ASCIZ-имя
нового файла; CL = маска атрибутов.
Выход: CF = 0 — при успешном переименовании; CF = 1 — АХ = код ошибки: 2 — файл не найден; 3 — несуществующий путь; 5 — доступ запрещен; 1 lh — устройства для старого и нового файлов не совпадают.
Функция 56h позволяет произвести перемещение между каталогами, не изменяя устройства.

;prg07_13.asm - программа перемещения между каталогами.
;не изменяя устройства функцией 56h.
¦
.data
fname_s db "maket.asm".О
point_fname_s dd fname_s
fname_d db "e:\maket.asm".0
point_fname_d dd fname_d
.code
;.....переместим файл из текущего в корневой каталог------
Ids dx.point_fname_s :формируем указатель на строку fname_s (исх. файл)
1 es di,point_fname_d ;формируем указатель на строку fname_d (целевой файл)
Imov ah.56h ;номер функции DOS int 21h
jc exit ;переход в случае ошибки

Получить дату и время создания или последней модификации файла
Получить/изменить дату и время создания или модификации файла можно с помощью подфункций функции 57h.
Вход: АХ = 5700h; ВХ = дескриптор файла.
Выход: если CF = 0: СХ = время, DX = дата. Если CF = 1: АХ = код ошибки (CF = п. 1 — недопустимый номер подфункции в А1; 6 — недопустимый дескриптор Время и дата файла получаются в следующих форматах.

Время Дата
Биты Описание Биты Описание
15-11 Часы (0-23) 15-9 Год
10-5 Минуты 8-5 Месяц
4-0 Секунды 4-0 День

Установить дату и время создания или последней модификации файла

Вход: АХ = 5701п; ВХ - дескриптор файла; СХ - новое время, DX = новая дата. Выход: если CF = 0: СХ = время, DX = дата. Если CF = 1 — АХ = код ошибки: 1 — недопустимый номер подфункции в А1; 6 — недопустимый дескриптор.
Работа с дисками, каталогами и организация поиска файлов
Задача поиска традиционно является актуальной. При рассмотрении вопроса работы с файлами ее также не обойти. Мы рассмотрим номенклатуру средств, предлагаемых MS DOS для поиска файла и определения его местоположения в древовидной структуре каталогов текущего диска.
Во время работы с предыдущими программами вы заметили, что при задании имен файлов мы практически не указывали имен дисководов и путей к этим файлам. MS DOS имеет средства для установки текущего диска и каталога, в котором выполняются все текущие операции с файлами. При необходимости можно изменить текущий диск и каталог. Ниже приведено несколько функций для работы с текущими диском и каталогом — определение, изменение, получение информации.

Получить номер заданного по умолчанию дисковода

Вход: АН = 19h.
Выход: AL - номер дисковода (00h - A:, 01h - В: и т. д.).

:prg07_14.asm - программа получения номера текущего (по умолчанию) дисковода функцией 19h.

I .code
m ;.....Получить номер текущего (по умолчанию) дисковода ---
movah.l9h :номер функции DOS
1nt2lh
jc exit -.переход в случае ошибки :в al номер текущего диска

Выбрать заданный по умолчанию диск

Вход: АН = OEh; DL = номер нового диска по умолчанию (00h = A:, 01h = В: и т. д.).
Выход: AL = максимально возможный в данной системе номер дисковода (00h =
A:, 01h = В: и т. д.) определяется на основе параметра LASTDRIVE в файле
CONFIG.SYS.

Получить информацию о свободном дисковом пространстве

Вход: АН = 36h; DL = номер диска (00h- текущий,01h = А: и т. д.).
Выход: АХ = FFFFh — неправильный номер устройства в DL,
иначе: АХ = число секторов в одном кластере; ВХ - число свободных кластеров; СХ = размер сектора (в байтах); DX = общее число кластеров на диске.

Используя информацию, возвращаемую функцией 36h, можно подсчитать как свободное пространство на диске — произведение АХ*ВХ*СХ, так и полный объем диска — произведение AX*CX*DX.
MS DOS предоставляет следующие возможности для манипулирования каталогами: создание и удаление каталога, получение информации о текущем каталоге и его смена.

Создание каталога

Вход: АН = 39h; DS:DX — ASCIZ-строка пути к создаваемому каталогу. Выход: АХ = не определен (CF ¦ 0); АХ - код ошибки (CF = 1): 3 — несуществующий путь; 5 — доступ запрещен.
Путь к каталогу должен содержать перечисление всех каталогов начиная от корневого на пути к создаваемому каталогу, при этом они, естественно, должны существовать. Последнее имя каталога — имя создаваемого каталога.

;prg07_15.asm - программа демонстрации создания каталога функцией 39h.
.data
dname db "c:\windows\my_diг".0
point_dname dd dname
.code
;.....создадим каталог в каталоге c:\windows.......-.......
Ids пате;формируем указатель на строку с именем нового каталога
movah,39h :номер функции DOS
int 21h
jc exit ;переход в случае ошибки

Удаление каталога

Вход: АН = 3Ah; DS:DX — ASCIZ-строка пути к удаляемому каталогу. Выход: CF = 0 — АХ = не определен; АХ = код ошибки (CF = 1): 3 — несуществующий путь; 5 — доступ запрещен; 10h — попытка удаления текущего каталога. Удаляемый каталог должен быть пустым.

:prg07_16.asm - программа демонстрации удаления каталога функцией ЗАп.
.data
dname db "c:\windows\my_diг",О point_dname dd dname
.code
:----удалим каталог my_dir в каталоге c:\windows---------
Ids dx.point_dname;формируем указатель на строку с именем нового каталога movah.3ah :номер функции DOS *
int 21h
jc exit ;переход в случае ошибки

Изменить текущий каталог

MS DOS позволяет установить текущий каталог для того, чтобы не указывать полный путь для последующих операций с файлами. При необходимости можно получить полный путь к текущему каталогу в виде ASCIZ-строки. Вход: АН = 3Bh; DS:DX — указатель на буфер, содержащий полный путь от корневого каталога в виде ASCIZ-строки (до 64 байт). Выход: CF = 0 — АХ = не определен; CF = 1 — АХ = код ошибки: 03h — путь не найден.

:prg07_17.asm - программа демонстрации изменения текущего каталога функцией ЗВп.
.data
dname db "c:\windows",0
point_dname dd dname
.code
|.........
:.....изменим текущий каталог на каталог c:\windows--------
Ids dx.point_dname:формируем указатель на строку с именем нового каталога
movah.3bh :номер функции DOS
int21h
jc exit . :переход в случае ошибки
;.........

Получение текущего каталога

Вход: Ан = 47h;
DL = номер устройства (00h= текущее (по умолчанию),01h = А: и т. д.) DS:SI — указатель на 64-байтный буфер для записи полного пути от корневого каталога (ASCIZ-строка).
рыход: АХ = не определен или 0100h(CF=0);
АХ = код ошибки (CF=1): OFh — недопустимый дисковод.

:prg07_18.asm - программа демонстрации получения текущего каталога функцией 47h.
.data
dname db "e:\tools".О
point_dname dd dname
d_cur_name db 64 dup (20h).0
point_d_cur_name dd d_cur_name
.code
:.....изменим текущий каталог на каталог \tools ...........
Ids dx,point_dname;формируем указатель на строку с именем нового каталога
movah,3bh ;номер функции DOS
int 21h
jc exit :переход в случае ошибки
:----получим текущий каталог......-----.....
Ids si,point_d_cur_name ;формируем указатель на строку с именем нового каталога
mov ah.47h ;номер функции DOS
int 21h
jc exit :переход в случае ошибки

Возвращаемый путь не содержит имени диска и первого символа \.
Последняя проблема, на которой мы остановимся в этом разделе, — проблема поиска файлов. Для поиска в каталогах используется пара функций 4eh и 4fh. В имени искомого файла можно указывать символы шаблона * и ?. Совместное использование функций 4eh и 4fh подчинено следующему алгоритму. Первой вызывается функция 4eh. В качестве параметров ей передаются адрес ASCIZ-строки с путем к искомому файлу и комбинация его атрибутов. Имя файла может быть задано в виде шаблона. В случае успеха (cf=0), то есть при обнаружении первого подходящего шаблону файла, данная функция помещает его имя и расширение в область DTA со смещением leh от ее начала (см. таблицу ниже). Далее можно либо открыть файл, либо продолжить поиск, но уже функцией 4fh. При работе с шаблоном функцию 4fh можно вызывать циклически, до тех пор пока в процессе перебора не будут просмотрены имена всех подходящих файлов. Об этом можно узнать по состоянию флага cf, которое должно стать равным 1 в случае, когда файлов, удовлетворяющих шаблону, в данном каталоге больше нет.

Поиск первого соответствующего шаблону файла

Вход: АН = 4Eh; СХ = атрибуты файла (биты 0 и 5 игнорируются); DS:DX — ASCIZ-имя файла (возможно, с путем к нему и символами шаблона * и ?).
Выход: если CF - 0, то в DTA возвращается блок данных для первого найденно го файла (см. ниже). Если CF - 0, то в АХ - код ошибки: 2 — файл не най" ден; 3 — несуществующий путь; 12h — больше файлов в каталоге нет Область DTA (Data Transfer Area) располагается в префиксе программист
сегмента со смещением 80h от его начала и занимает 128 байт. При успешном
окончании поиска функция 4Eh (и 4Fh тоже) помещает блок данных, имеющий
приведенный ниже формат.

Смещение
Размер в байтах
Описание
00h
1
Буква логического диска, если бит 7 = 0, то удаленный диск
01h
И
Поисковый шаблон
0Сh
1
Атрибуты поиска
0Dh
2
Порядковый номер файла в каталоге
0Fh
2
Номер кластера начала каталога предыдущего уровня
11h
4
Резерв
15h
1
Атрибуты найденного файла
16h
2
Время создания (модификации) файла
18h
2
Дата создания файла
1Ah
4
Размер файла
1Eh
13
ASCIZ-имя файла с расширением

После анализа данной области в программе принимается решение об окончании или продолжении поиска.
В качестве шаблона можно задать символы *.*, тогда мы сможем получить имена и проанализировать все файлы в текущем каталоге. Это может понадобиться при программировании операции перемещения или копирования каталога.

Найти следующий соответствующий шаблону файл

Вход: АН = 4Fh; в области DTA должен содержаться блок данных, заполненный единственным вызовом 4eh в начале поиска.
Выход: если CF = 0 — успех; если CF = 1 — в АХ = код ошибки: 12h — больше файлов в каталоге нет.
Для работы с DTA в системе MS DOS существуют две функции lah и 2fh. После старта программы текущей DTA является область по адресу PSP:OO8Oh. Мы уже имели с ней дело, когда рассматривали проблему обработки содержимого командной строки.

Получить адрес области DTA

Для выполнения работы, связанной с файлами, MS DOS предоставляет возможность установить свою область DTA.
Вход: АН = 2Fh.
Выход: ES:BX — адрес области, которую впоследствии функцией lah можно сделать текущей областью DTA для последующих операций ввода-вывода.
установить текущую область DTA
Вход: АН - 1Ah; DS:DX — адрес области, которая будет областью DTA для последующих файловых операций.
Понятно, что даже если мы устанавливаем свою область DTA, все смещения и данные, формируемые функциями 4Eh 4Fh, остаются актуальными.

Работа с файлами в MS DOS (длинные имена)

Перечисленные выше функции работают в различных версиях «чистой» системы MS DOS, вплоть до версии 6.22 включительно. Операционные системы Windows 95/98/Mil также поддерживают свою версию MS DOS, которая имеет номер 7.0. Операционная система Windows 95/98/Mil организует для программ MS DOS специальную среду для работы, называемую сеансом DOS. Система MS DOS 7.0, будучи созданной для работы в среде Windows 95/98/Mil, имеет в своем составе средства для работы с файловой системой Windows. Эта файловая система, как известно, отличается тем, что полное имя файла может достигать длины 255 символов. MS DOS 7.0 также умеет работать с длинными именами файлов. В данном разделе мы рассмотрим предназначенные для работы с файловой системой Windows средства среды MS DOS, работающей под управлением
Windows.
Определить факт того, в какой системе работает программа, можно по результатам работы функций 30h — получить версию DOS (прерывания 21п) и 4аЗЗп (прерывания 2fh).
Вход: АН = 30h; AL = определяет значение, возвращаемое в ВН: 00h— OEM-номер (как для DOS 2.0-4.0x);01h — номер версии.
Выход: AL = главный номер версии; АН - младший номер версии; BL:CX = 24-битный серийный номер пользователя (необязательно).


:prg07_19.a$m - программа демонстрации определения факта того. ;в какой системе работает программа.
.code
;.....определим номер версии ОС MS DOS
mov al .00
movah.30h ;номер функции DOS
int21h ;А1-главный номер версии. АН-младший номер версии
]с exit ;переход в случае ошибки

В регистрах AL и АН возвращаются главный и младший номера версии MS DOS. При функционировании под Windows эти номера равны 07h и Oah соответственно. Задание значения AL = 01 дает такой же эффект.

:prg07_20.asm - программа демонстрации определения факта работы в среде MS DOS 7.0.
.code
:-----определить факт работы в среде MS DOS 7.0
movax.4a33h ;номер функции DOS int 2fh
cmp ax, 0
jneexit ;переход, если работа не в среде MS DOS 7.0

Последняя функция возвращает 0 для MS DOS версии 7.0 и выше. Установить факт того, что система поддерживает длинные имена файлов, можно вызовом функции 71a0h прерывания 21п — получить информацию о томе. Если она возвращает ошибку (CF = 1), то текущая файловая система не поддерживает длинных имен файлов. Для вызова этой функции необходимо указать корневой каталог тома, о котором необходимо получить информацию. Вход: АХ = 71A0h; DS:SI — ASCIZ-имя корневого каталога тома, о котором необходимо получить информацию (например, "С:\"); ES:DI — буфер для имени файловой системы; СХ ¦= размер буфера, адрес которого задан в ES: DI (32 байта).
Выход: CF = 0 в случае успеха, следующие регистры установлены: ВХ = флаги файловой системы: 0 — при поиске учитывать регистр букв в именах файлов; 1 — сохранять регистр букв в элементах каталога; 2 — использование символов Unicode в именах каталогов и файлов; 3-13 — резерв (0); 14 — поддержка DOS-функций для длинных имен файлов; 15 — сжатый том; СХ = максимальная длина файловых имен (обычно 255); DX = максимальная длина пути (обычно 260); ES: DI — в буфере по этому адресу ASCIZ-имя файловой системы, например "FAT", "FAT32", "NTFS", "CDFS"; CF = 1 в случае неудачи, при этом АХ = код ошибки или AX=7100h, если функция не поддерживается.
В Windows 95/98 появились дополнительные возможности как самой файловой системы, так и средств по ее управлению. Основное нововведение — поддержка длинных имен файлов. Основа файловой системы та же — таблица разрешения файлов FAT, но любой файл в этой системе имеет два имени — длинное имя и его псевдоним, который соответствует формату 8.3. Данный псевдоним создается системой Windows 95/98 автоматически.
Нужно правильно понимать различие в способах использования длинных имен файлов в приложениях MS DOS и Win32. Приложения MS DOS получают до-ступ к длинным именам файлов с помощью дополнительных функций прерывания 21h. Приложения Windows используют для этого соответствующие функции API.
Длинное имя файла представляет собой ASCIIZ-строку длиной до 255 символов. Система формирует псевдоним для этого имени форматом 8.3 в соответствии со следующим правилом: берутся первые 6 символов длинного имени, после них добавляется символ тильда (-), за тильдой ставится некий порядковый номер. Для первого имени формата 8.3 это 1. Если такой псевдоним уже существует, то порядковый номер очередного псевдонима будет на 1 больше. Расширение псевдонима формируется из первых трех символов расширения длинного имени (если оно существует). Если похожих имен много, то номер в псевдониме может быть двузначным, при этом первая (символьная) часть псевдонима сокращается
до 5 символов, и т. д.
Рассмотренные выше функции MS DOS для работы с файлами и каталогами не поддерживают длинных имен. Для этого система Windows 95/98 предоставляет приложениям MS DOS аналогичные функции, но имеющие другие номера. Впрочем, при внимательном рассмотрении большинства из этих номеров, видно, какой из старых функций они соответствуют. Новые номера состоят из четырех цифр: первые две — 071h, последние две — номер старой функции. Для некоторых функций существуют особенности в их работе. Так, для поиска файлов по-прежнему используются две функции (по новой нумерации — 714eh и 714fh) прерывания 21h. Новые функции теперь возвращают информацию о файлах через специальную структуру WI N32_F INDDATA, адрес которой возвращается в качестве
результата их работы.
При работе с функциями, поддерживающими длинные имена файлов, используются еще две структуры: by handle_f 11 e_information и filetime. Назначение структуры by_hand1e_file_iinformation и работу с ней мы рассмотрим при обсуждении функции MS DOS 71a6h. Структура filetime содержит 64-разрядное значение, которое определяет число 100-наносекундных интервалов, прошедших с 12:00 утра 1 января 1901 года.

FILETIME Struc
DwLowDateTime dd ? :младшие 32 бита значения времени DwHighDateTime dd ? хтаршие 32 бита значения времени FILETIME ends

Теперь приведем перечень функций прерывания 21h, работающих с файлами, которые имеют длинные имена. Для удобства дальнейшего рассмотрения в следующей таблице приведены соответствующие функции API WIN32 и «старые» функции прерывания 21h.

Новая
функция int 21h
Старая функция int 21h
Назначение
Функция API Win32
5704h
Получить дату и время последнего доступа
GetFileTime
5705h
Установить дату и время
SetFileTime
последнего доступа
5706h
Получить дату и время создания
GetFileTime
5707h
Установить дату и время создания
SetFileTime
7139h
39h
Создать каталог
CreateDirectory
713Ah
3ah
Удалить каталог
RemoveDirectory
713Bh
3bh
Изменить текущий каталог
SetCurrentDi rectory
7141h
41h
Удалить файл
DeleteFile
7143h
43h
Получить или установить
GetFileAttributes,
атрибуты файла
SetFileAttributes
7147h
47h
Получить текущий каталог
GetCurrentDirectory
714Eh
4Eh
Найти первый файл
FindFirstFile
714Fh
4Fh
Найти следующий файл
FindNextFile
7156h
56h
Переименовать файл
MoveFile
7160h
Получить полный путь
GetFullPathName
7160h
Получить полный путь
GetShortPathName
с-краткими именами
7160h
Получить полный путь
Отсутствует
с длинными именами
716Ch
3ch, 3dh, 5bh
Создать или открыть файл
CreateFile, OpenFile
71A0h
Получить информацию о томе
GetVolumelnfonnati on
71Alh
Завершить поиск
FindClose
71A6h
Получить информацию о файле
GetFi1 elnformationByHandle
по описателю
71A7h
Преобразовать время файла
Fi1eTi meToDOSDateTime
в DOS-время
71A7h
Преобразовать DOS-время во время файла
00SDateTi meToFi1eTi me
71A8h
Создать псевдоним
Отсутствует
71A9h
Создать или открыть файл
Отсутствует
на сервере
71AAh
Провести подмену
Отсутствует
71AAh
Отменить подмену
Отсутствует
71AAh
Получить информацию
Отсутствует
о подмене

Рассмотрим наиболее интересные в контексте нашего изложения функции этой таблицы. Информацию по остальным функциям можно получить, в частности, из MSDN. Порядок рассмотрения будет от простых функций к сложным, так как это было в предыдущем разделе, посвященном функциям работы с файлами ДО DOS, имеющими короткие имена.

Создание, открытие, закрытие и удаление файла

функции MS DOS, поддерживающие длинные имена файлов, имеют номера из четырех цифр — первые две равны 71h, последние две соответствуют номеру аналогичной старой функции MS DOS. В программах старые и новые функции применяются вместе по принципу: там, где функция должна работать непосредственно с длинными именами файлов и каталогов, применяются новые функции; там, где функция работает с дескриптором файла, используются старые функции. Новые функции также используются для реализации новых возможностей по работе с файловой системой.

Открытие или создание файла

Для создания или открытия файла с длинным именем используется функция 716Ch (создать или открыть файл). Эта функция аналогична функции 6ch, которая появилась в последних версиях MS DOS (DOS 4.0+). Мы уже обсуждали ее в разделе, посвященном функциям работы с файлами с короткими именами.
Вход: АХ = 716Ch; BX = режимы доступа и флаги:
режим доступа: 0000h — файл только для чтения; 0001h — файл только для записи; 0002h — файл для чтения и записи; 0003h — резерв; 0004п — открыть файл для чтения без изменения даты последнего доступа к файлу; режим разделения: 0000h — режим эмуляции — файл можно открывать любой программе любое количество раз; 00Wh — файл открыт в монопольном режиме доступа; 0020h — файл открыт в монопольном режиме доступа по записи; 0030h — файл открыт в монопольном режиме доступа по чтению; 0040И — открыть файл, разрешая другим процессам доступ по чтению-записи, но с запретом режима эмуляции; флаги: 0080h — дочерний процесс не наследует дескриптор файла, его при необходимости нужно передавать явно; Ol00h — не использовать буферизацию или кэширование средствами ОС, операции чтения-записи выполняются напрямую с диском в соответствии с текущим положением файлового указателя; 0200h — файл нельзя сжимать; 0400h — содержимое регистра 01 следует использовать как порядковый номер в псевдониме файла; 2000h — не вызвать обработчик критической ошибки (int 24h), MS DOS вернет программе код ошибки; 4000h — после каждой операции записи MS DOS будет отправлять данные на диск без их кэширования; СХ - атрибуты создаваемого (и только) файла: 0000h — файл доступен по записи и чтению; 0001h — файл доступен по чтению; 0002h — скрытый файл; 0004п — системный файл; 0008h — метка тома; 0020h — архивный
файл;
DX ~ действия, если файл существует или не существует, значения битов: 00lOh — вернуть ошибку, если файл существует, иначе создать файл; 0001h — открыть файл, если он существует, иначе вернуть ошибку;

0002h — открыть файл без сохранения существующего, иначе вернуть ошибку (если файл не существует); DS:SI — ASCIZ-имя файла;
DI — порядковый номер, который добавляется к концу имени в псевдониме файла (для этого должен быть задан флаг 0400h в регистре ВХ) Номер будет десятичным письмом, то есть если DI=0010h, то конец псевдонима -----16.
Выход: CF=0 — успешное выполнение функции: АХ = дескриптор файла, СХ = состояние: 1 — файл открыт; 2 — файл создан и открыт; 2 — файл открыт без сохранения содержимого существующего файла; CF=1: AX = код ошибки.
После того как файл открыт или создан функцией 716ch, с ним можно работать, используя старые функции чтения-записи и позиционирования. Следующий фрагмент программы показывает вариант применения функции 716Ch.
Закрытие файла производится функцией 3Eh, которая использовалась для файловых функций MS DOS с короткими именами.

Удаление файла

Удаление файлов, имеющих длинные имена, производится функцией 7141h прерывания 21п. Имя файла может быть задано с использованием символов шаблона * и ?, при этом в результате работы функции будут удалены все файлы, чье имя удовлетворяет заданному шаблону.

Получить дату и время создания файла

Вход: АХ = 5706h; ВХ - дескриптор файла. ; . М
Выход: CF = 0 — успешное выполнение функции: СХ = биты установлены следующим образом: 0..4 - секунды, деленные на 2; 5..10 = минуты 0..59; 11..15 -часы; DX - биты установлены следующим образом: 0..4 = день месяца в диапазоне 1..31; 5..8 = месяц в диапазоне 1..12; 9..15 = число лет начиная с 1980 года; SI - двоичное значение количества 10-миллисекундных интервалов, добавляемых ко времени MS DOS в диапазоне 0..199; CF = 1: АХ = код ошибки.
Данная функция реализована в полном объеме.

Установить дату последней модификации файла

Вход: АХ = 5705И; ВХ = дескриптор файла; СХ = 0000h; DX - биты установлены следующим образом: 0..4 - день месяца в диапазоне 1..31; 5..8 = месяц в диапазоне 1..12; 9..15- число лет, начиная с 1980 года.
Выход: CF = 0 — успешное выполнение функции; CF = 1: АХ код ошибки.

Аналогично функции 5704h данная функция позволяет установить только дату создания файла.

Установить дату и время создания или последней модификации файла

Вход: АХ = 5707h; ВХ = дескриптор файла; СХ - биты установлены следующим образом: 0..4 - секунды, деленные на 2; 5..10 = минуты 0..59; 11..15 - часы; DX " биты установлены следующим образом: 0..4 = день месяца в диапазоне 1..31; 5..8 = месяц в диапазоне 1..12; 9..15 = число лет начиная с
1980 года;
SI - двоичное значение количества 10-миллисекундных интервалов, добавляемых к времени MS DOS в диапазоне 0..199.
Выход: CF = 0 — успешное выполнение функции; CF = 1: АХ - код ошибки.

Данная функция реализована в полном объеме.
Кроме дополнительных функций для работы с различными временными характеристиками файла Windows-версия MS DOS содержит две функции для преобразования форматов времени. Дело в том, что Windows работает со временем в 64 разрядном формате. При этом точкой отсчета является 00 часов 00 минут 1 января 1601 года. Значение времени содержит число 100-наносекундных интервалов, прошедших с этой даты. По расчетам разработчиков этого значения должно хватить на 400 лет. Для того чтобы манипулировать этим 64-разрядным «средневековьем» с целью представления его в виде, воспринимаемом человеком (DOS-время), введена функция 71a7h.
Вход: АХ = 71a7h; BL = 0 — преобразовать 64-разрядное время в DOS-время; DS:SI = указатель на экземпляр структуры FILETIME, содержащей 64-битное значение времени.
Выход: CF = 0 — успешное выполнение функции, при этом регистры устанавливаются следующим образом: ВН = число 10-миллисекундных интервалов, добавляемых к времени MS DOS (значение в диапазоне 0..199); СХ - время в упакованном формате со значением бит: 0..4 — секунды, деленные на 2; 5..10 — минуты в диапазоне 0..59; 0..4 — часы в диапазоне 0..23; DX = дата в упакованном формате со значением бит: 0..4 — день месяца в диапазоне 1.31; 5..8 — месяц в диапазоне 1..12; 9..15 — число лет начиная с 1980 года (для получения истинного значения прибавьте 1980); CF = 1: АХ - код ошибки. (Структура filetime описывается в программе следующим образом:

FILETIME struc
DwLowOateTime dd ? :младшие 32 бита значения времени
DwHighDateTime dd ? :старшие 32 бита значения времени
FILETIME ends

Вход: АХ = 71a7h; BL - 1 — преобразовать DOS-время в 64-разрядное время; ВН = число 10-миллисекундных интервалов, добавляемых ко времени MS DOS (значение в диапазоне 0..199); СХ = время в упакованном формате со значением бит: 0..4 — секунды, деленные на 2; 5..10 — минуты в диапазоне 0..59; 0..4 — часы в диапазоне 0..23; DX - дата в упакованном формате со значением бит: 0..4 — день месяца в диапазоне 1..31; 5..8 — месяц в диа пазоне 1..12; 9..15 — число лет начиная с 1980 года (для получения истинного значения прибавьте 1980) DS:SI = указатель на экземпляр структуры FILETIME, в которой вернется 64-битное значение времени.
Выход: CF=O — успешное выполнение функции, при этом в области памяти, адресуемой DS:SI, возвращается 64-битное значение времени; CF=1: AX - код ошибки.

Получить атрибуты файла

Вход: АХ ¦ 7143h; BX = действие:
0 -- получить атрибуты, на выходе СХ = атрибуты файла: 0000h — файл доступен по записи и чтению; 0001h — файл доступен по чтению; 0002h — скрытый файл; 0004И — системный файл; 0008h — метка тома; 00lOh — каталог; 0020h — архивный файл;
2 — получить размер сжатого файла — на выходе DX:AX = размер сжатого файла в байтах на диске;
4 — получить дату и время последней записи — на выходе; СХ = время в формате: 0..4 = секунды, деленные на 2; 5.. 10 = минуты (0..59); 11..15 = часы(0..23);
DI дата в формате: 0..4 = день месяца (1..31); 5..8 = месяц (1..12); 9..15 = число лет с 1980 года;
6 — получить дату последнего доступа — на выходе: DI = дата в формате (см. ВХ = 4);
8 — получить дату и время создания — на выходе СХ - время в формате, DI - дата в формате (см. ВХ « 4), SI = двоичное значение количества 10-миллисекундных интервалов, добавляемых ко времени MS DOS в диапазоне 0..199;
DS:DX — ASCIZ-строка с именем (путем) файла.
Выход: CF = 0 в случае успеха, информация в регистрах определяется значением ВХ на входе (см. выше):
АХ = код ошибки (CF = 1): 1 — неверное значение в AL; 2 — файл не найден; 3 — несуществующий путь; 5 — доступ запрещен.

Установить атрибуты файла

Вход: АХ = 7143h; ВХ = действие:
1 — установить атрибуты на входе СХ = атрибуты файла: 0000h — файл доступен по записи и чтению; 0001h — файл доступен по чтению; 0002h — скрытый файл; 0004h — системный файл; 0020h — архивный файл; 3 — установить дату и время последней записи: СХ = время в формате: 0..4 " секунды, деленные на 2; 5..10 = минуты (0..59); П..15 - часы (0..23); 01 = дата в формате: 0..4 = день месяца (1..31); 5..8 = месяц (Т.. 12); 9..15 =" число лет с 1980 года;
5 — установить дату последнего доступа (см. ВХ = 3); 7 — установить дату и время создания: СХ = время в формате (см. ВХ - 3), DI = дата в формате (см. ВХ = 3), SI = двоичное значение количества 10-миллисекундных интервалов, добавляемых ко времени MS DOS в диапазоне 0..199; DS:DX — ASCIZ-строка с именем (путем) файла.
Выход: CF = о — СХ = слово атрибутов файла; CF=1 — АХ=код ошибки: 1 — неверное значение в AL; 2 — файл не найден; 3 — несуществующий путь; 5 — до-ступ запрещен.

Переименовать файл

Вход: АН = 7156h; DS:DX — ASCIZ-имя существующего файла; ES:O1
имя нового файла; CL - маска атрибутов. Выход: CF = 0 — при успешном переименовании; CF = 1 — АХ = код ошибки: 2 —
файл не найден; 3 — несуществующий путь; 5 — доступ запрещен;
устройства для старого и нового файлов не совпадают.

Работа с дисками, каталогами и организация поиска файлов

Получить информацию о томе

Вход: АН = 71A0h; DS:DX — адрес ASCIZ-строки с именем корневого каталога диска, о котором необходимо получить информацию (С:\); ES:DI — адрес буфера, в который будет помещена ASCIZ-строка с именем файловой системы; СХ = размер буфера, в который будет помещена ASCIZ-строка с именем файловой системы.
Выход: CF = 0 — успешное выполнение, при этом в буфер по адресу в ES-.DI помешается ASCIZ-строка с именем файловой системы и устанавливаются следующие регистры: ВХ =* флаги файловой системы (комбинация значений: 0001 — при поиске учитывается регистр букв в именах файлов; 0002 — файловая система сохраняет регистр букв в элементах каталога; 0004 — использование символов Unicode в именах каталогов и файлов; 4000 — файловая система поддерживает длинные имена файлов и функции для работы с ними; 8000 — том сжат); СХ = максимально допустимая длина имени файла на данном томе без последнего нулевого символа (до 255); DX = максимально допустимая длина пути для данного тома, включая последний нулевой символ (до 260); ;1. _ .,

Создание каталога

Вход: АН = 7139h; DS:DX — адрес строки с ASCIZ-именем существующего файла. Выход: CF = 0 — при успешном переименовании; CF = 1 — АХ = код ошибки: 3 — несуществующий путь; 5 — доступ запрещен.
Удаление каталога
Удаляемый каталог должен быть пуст.
Вход: АН = 713Ah; DS:DX — ASCIZ-строка пути к удаляемому каталогу. Выход: CF = 0 — АХ = не определен; CF = 1 — АХ = код ошибки: 3 — несуществующий путь; 5 — доступ запрещен; 10h — попытка удаления текущего каталога.

Изменить текущий каталог

Понятие текущего каталога аналогично тому, что приводилось выше при рассмотрении функций для работы с файлами, имеющими короткие имена.
АН = 713Bh; DS:DX — указатель на буфер, содержащий полный путь от кор. невого каталога в виде ASCIZ-строки и в качестве последнего элемента включающий имя нового текущего каталога (естественно, что допустимы длинные имена с ограничениями по максимальной длине (см. функцию 71a0h)). Выход: CF = 0 — АХ - не определен; CF=0 — АХ = код ошибки: 03h — путь не найден

Получение текущего каталога

Вход: АН = 7147h; DL - номер устройства (00h = текущее (заданное по умолчанию), 01h = А: И т. д.); DS:SI — указатель на буфер для записи полного пути от корневого к текущему каталогу (длина буфера должна быть не менее длины, возвращаемой в регистре DX функцией 71a0h). Выход: CF = 0 — успешное выполнение функции, в результате чего полный путь от корневого каталога в виде ASCIZ-строки без имени диска и символа \ записывается в буфер, адрес которого указан в DS:SI; АХ - код ошибки (CF = 1): OFh — недопустимый дисковод. Среди новых функций, работающих в том числе с длинными именами файлов, существует функция 7160h, позволяющая получить полные пути для указанных файлов или относительных путей: получить полный путь (сх = 0), получить полный путь с краткими именами (сх = 1), получить полный путь с длинными именами (сх = 2).

Получить полный путь

Вход: АН = 7160h; CL = 0; СН — содержимое результата (СН = 80 — получить имя диска; СН = 0 — получить полный путь); DS:SI — адрес ASCIIZ-строки с именем файла или каталога, для которых необходимо получить полный путь. Допускаются оба типа имен — длинные и короткие; ES:DI — адрес строки, в которую необходимо записать полный путь. Размер буфера должен быть достаточным для размещения пути максимальной длины (функция 71a0h).
Выход: CF = 0 — успешное выполнение функции, в результате чего полный путь от корневого каталога в виде ASCIZ-строки записывается в буфер, адрес которого указан в ES:DI; CF = 1 — АХ = код ошибки.

;prg07_24.asm - программа демонстрации применения функции 7160h (CL=0) прерывания 21h для получения полного пути.
.data
filename db 'my_file with long name.txt'.O
point_fname dd filename
PathFull db 260 dup (0)
point Path dd PalhFull
.code
Ids si .pointfname:формируем указатель на имя файла
les di,point_Path Нормируем указатель на буфер для полного пути

mcvax.7l60h ;номер функции DOS
movch,80h :CH=80h - получить имя : диска; СН=0 - получить полный путь
movCL.O ;получить полный путь
int 21h
jc exit

Данная функция работает очень принмитивно — при указании имени файла или относительного пути (с символами *«.» и «..») она не проверяет его существование, а лишь добавляет к нему имя тсекущего диска и каталога. Поэтому при использовании этой функции требуютсяя другие средства, позволяющие контролировать реальное наличие файла или шути на диске.

Получить полный путь с краткими именами (в формате 8.3)

Вход: АН = 7160h; CL = 1; СН — содержимоое результата (СН = 80 — получить имя диска; СН = 0 — получить полный путь); DS:SI — адрес ASCIIZ-строки с именем файла или каталога, для ксоторых необходимо получить путь в короткой форме. Допускаются оба . типа имен — длинные и короткие: ES:DI — адрес строки, в которую необходцимо записать полный путь. Размер буфера должен быть достаточным длят размещения пути максимальной длины
(функция 71a0h).
Выход: CF = 0 — успешное выполнение функции, в результате чего полный путь от корневого каталога в виде /ASCIZ-строки записывается в буфер, адрес которого указан в ES: DI; CF ' = 1 — АХ = код ошибки.

:prg07_25.asm - программа демонстрации применения функции 7160h (CL=1) прерывания 21h для получения полного путии с краткими именами (в формате 8.3)
filename db 'my_file with lorg name.:.txt' .0
point_fname dd filename
PathFUll db 260 аир (О)
pointjath dd PathFull
* Ids si .pointjfname формирует указатель на имя файла lesdi.point_Path сформируем учазатель на буфер для полного пути movax.7160h :номер функции DOS
movch.80h ;CH»80h - попучить « имя диска; СН=0 - получить полный путь
movCL.l :получить пспный пууть с краткими именами

На выходе функция формирует стрроку, содержащую полный путь, причем все I Длинные компоненты этого пути замееняются их краткими псевдонимами, удовлетворяющими схеме 8.3. Данный вариант функции (при CL = 1) в отличие от ее Предыдущего варианта, производит прроверку наличия файла или пути.

Получить полный путь с длинными именами

Вход: АН = 7160h; CL = 2; СН — содержимое результата (СН = 80 — получить имя лиска; СН = 0 — получить полный путь); DS:SI — адрес ASCIIZ-строки с именем файла или каталога, для которых необходимо получить путь в длинной форме. Допускаются оба типа имен — длинные и короткие; ES:DI — адрес строки, в которую необходимо записать полный путь. Размер буфера должен быть достаточным для размещения пути максимальной длины (функция 71a0h).
Выход: CF = 0 — успешное выполнение функции, в результате чего полный путь от корневого каталога в виде ASCIZ-строки записывается в буфер, адрес которого указан в ES:DI; CF = 1 — АХ = код ошибки.

Получить информацию о файле по описателю

Вход: АН = 71A6h; флаг cf = 1; ВХ = дескриптор файла; DS:DX — адрес структуры
BYHANDLEFILEINFORMATION.
Выход: CF = 0 — успешное выполнение функции; CF = 1 — АХ = код ошибки. Формат структуры BYHANDLEFILEINFORMATION приведен ниже.

Y_HANDLE_FILE_INFORMATION StuiC
"DwFiieAttributes dd ?
FtCreationTimedd 2 dup(?)
FtLastAccessTime dd 2 dup(?)
FtLastWriteTime dd 2 dup(?)
DwVolumeSeria 1 Number dd ?
NFileSizeHigh dd ?
NfileSizeLow dd ?
NnunberOfLinksdd ?
NFilelndexHighdd ?
NFilelndexLow dd ?
BY_HANDLE_FILE_INFORMATION ends

Поля этой структуры описаны в следующей таблице.

Поле
Описание
dwFileAttributes
Атрибуты файла. Этот элемент может быть комбинацией следующих значений: FI LE_ATTR IBUTENORMAL (00000000H) - файл доступен по чтению и записи; этот атрибут нельзя комбинировать с другими; FILE_ATTRIBUTE_READONLY (00000001Н) - файл только для чтения; FILE_ATTRIBUTE_HIDDEN (00000002H) - скрытый файл; FILE_ATTRIBUTE_SYSTEM (00000004H) - системный файл; FI LE_ATTR IBUTEDI RECTORY (00000010H) - каталог; FILE ATTRIBUTE ARCHIVE (00000020H) - архивный файл
CreationTime
Время создания файла в 64-разрядном формате
ftLastAccessTime
Время последнего доступа к файлу в 64-разрядном формате
ftLastWriteTime
Время последней записи в файл в 64-разрядном формате
dwVolumeSeri alNumber
Серийный помер тома, на котором находится файл
NFileSizeHigh
Старшее слово значения, определяющего размер файла
NFiieSizeLow
Младшее слово значения, определяющего размер файла
NNumberOfLinks
Число связей с данным файлом. В файловых системах FAT и HPFS этот элемент всегда равен 1. В файловой системе NTFS число связей может превышать 1
NFilelndexHigh
Старшее слово уникального дескриптора, связанного с файлом
NFilelndexLow
Младшее слово уникального дескриптора, связанного с файлом. Файл однозначно определяется дескриптором
и серийным номером тома

:prg07_26.asm - программа демонстрации применения функции 71A6h прерывания 21п :для получения информации о файле по описателю.
BY_HANDLE_FILE_INFORMATION struc "DwFileAttributes dd ? FtCreationTime dd 2 dup(?) FtLastAccessTime dd 2 dup(?) FtLastWriteTime dd 2 dup(?) DwVolumeSerial Number dd ? NFileSizeHigh dd ? NfileSizeLow dd ? NnumberOfLinks dd ? NFilelndexHigh dd ? NFilelndexLow dd ? BY_HANDLE_F1LE_INFORMATION ends
.data
file_info_ BY_HANDLE_FILE_INFORMATION <>
poir,t_find_ dd file_info_
filename db 'my_file with long name.txt'.O
point_fname dd filename
handle dw 0
:.........
.code

.файл, о котором будем получать информацию

mov bx.0100h+0400h;не использовать буферизацию
содержимое 01 в псевдоним
movdx.l юткрыть файл, если он существует, иначе вернуть ошибку Ids si .point_fname-.формируем указатель на имя файла
mov di.7 repeat:mov ax.716ch
xor ex.ex
int21h
jnc ml
mov dx.10h
jmp repeat ml: mov handle.ax
действия при успешном открытии файла:
добавить в конец псевдонима символ 7 ; номер функции DOS атрибуты файла - обычный файл - доступ для чтения-записи
открываем файл
.если файл существовал, то переход
;создать файл
:переход - повторим открытие файла
:сохраним дескриптор файла
.получаем информацию о файле mov bx. handle
stc ;это обязательно
Idsdx.point_find_;формируем указатель на структуру BY_HANDLE_FILE_INFORMATION

Создать псевдоним

Функция 71A8h предназначена для генерации короткого (в формате 8.3) имени для заданного файла с длинным именем.
Вход: АН = 71A8h; DS:SI — адрес строки (с нулевым символом в конце), содержащей длинное имя нужного файла без указания пути; ES:DI — адрес буфера, в котором возвращается псевдоним; DH — формат псевдонима (0—11 -символьное имя элемента каталога; 1 — имя файла в формате 8.3); DL — набор символов для длинного имени и псевдонима. Это значение — упакованная величина в формате: биты 0..3 — набор символов в prpprg0дном имени файла (0 — Windows ANSI; I — OEM; 2 — Unicode); биты 4..7 — набор символов в создаваемом коротком имени (0 — Windows ANSI; I - OEM; 2 - Unicode).
Выход: CF ¦ 0 — успешное выполнение функции; CF = 1 — АХ = код ошибки.

:prgO7_27.asm - программа демонстрации применения функции 71A8h прерывания 21h ;для создания псевдонима.
.'data'"
fi1enamejong db 'my_file with long name.txt'.0
point_fname_long dd fi1enamejong
filename_short db 11 dup (20h)
point_fname_short dd filename short
handle dw 0
:.........
.code
mov bx.0100h+0400h;He использовать буферизацию + содержимое DI в псевдоним
movdx.l :открыть файл, если он существует, иначе вернуть ошибку
Ids si,point fname_long ;формируем указатель на имя файла
movdi.7 :добавить в конец псевдонима символ 7 repeat:mov ax,716ch ;номер функции DOS
хогсх.сх атрибуты файла - обычный файл - доступ для чтения-записи
int 21h открываем файл
jnc ml :если файл существовал, то переход
movdx.lOh :создать файл
jmp repeat ;переход - повторим открытие файла ml: mov handle.ax :сохранин дескриптор файла создадим псевдоним
Ids si.point_fname_long
les di,point_fname_short
mov dh. 1:prg07_27.asm - программа демонстрации применения функции 71A8h прерывания 21h ;для создания псевдонима.
mov dl. 0
mov ax,7la8h int 21h действия при успешном открытии файла

Действие данной функции несколько отличается от процесса формирования псевдонима файла операционной системой и заключается в том, что длинное имя попросту обрезается по границам 8.3. В этом несложно убедиться, проанализировав работу приведенной выше программы в отладчике.

Поиск файлов и каталогов

В Windows-версии MS DOS процесс поиска несколько отличается от рассмотре-ного выше. Для этого используются три функции и структура WIN32_FIND_DATA в памяти, в которой возвращается информация о файле. Для запуска процесса поиска вызывается функция 714eh — найти первый файл.
Вход: АН = 714eh; CL — атрибуты искомых файлов (0000h — файл доступен по записи и чтению; 0001h — файл доступен по чтению; 0002h — скрытый файл; 0004И — системный файл; 0008И — метка тома; 00lOh — каталог; 0020h — архивный файл); СН — дополнительные атрибуты искомых файлов (0000h — файл доступен по записи и чтению; 0001h — файл доступен по чтению; 0002h — скрытый файл; 0004h — системный файл; 0008h — метка тома; 00lOh — каталог; 0020h — архивный файл); DS:DX — адрес ASCIIZ-строки с именем искомого файла или каталога. Допускаются оба типа имен — длинные и короткие. В именах допустимы символы шаблона * и ?; ES-.DI — адрес структуры WI N32_F I ND_DATA, в которой будет возвращена ин-_ формация о файле; SI — формат, в котором возвращается дата и время
(О — дата и время возвращаются в 64-разрядном формате; 1 — дата и время возвращаются в формате MS DOS).
Выход: CF = 0 — успешное выполнение функции, в результате в регистрах АХ и СХ возвращается следующая информация: АХ = дескриптор, использующийся далее для процесса поиска; СХ = возможные значения: 0000 — все символы структуры WIN32_FIND_DATA, составляющие основное и альтернативное имя файла, успешно преобразованы из Unicode; 0001 — основное имя, возвращенное в структуре WIN32_FIND_DATA, содержит знаки подчеркивания на месте символов, не преобразованных из Unicode; 0002 — альтернативное имя, возвращенное в структуре WIN32_FIND_DATA, содержит знаки подчеркивания на месте символов, не преобразованных из Unicode; CF = 1 — АХ = код ошибки при неудачном выполнении функции. Вызов функции 714eh приводит к заполнению полей структуры WIN32_FIND_ DATA, после чего можно проанализировать ее поля. Основной интерес представляют поля основного (CfileName) и альтернативного (CaHernateFiieName) имен. Их можно анализировать на предмет удовлетворения условиям поиска. Если необходимо продолжить поиск, вызывается функция 714fh — найти следующий файл. Если же поиск считается удачным либо его необходимо прекратить, то вызывается функция 71alh — прекратить поиск. Ниже приведены порядок вызова функций 714fh и 71alh и формат структуры WIN32_FIND_DATA.
Вход: АН = 714fh; ВХ = дескриптор, полученный функцией 714eh; ES:DI — адрес структуры WIN32FINDDATA, в которой будет возвращена информация о файле; SI — формат, в котором возвращается дата и время (0 — дата и время возвращаются в 64-разрядном формате; 1 — дата и время возвращаются в формате MS DOS).
Выход: CF = 0 — успешное выполнение функции, в результате в регистрах АХ и СХ возвращается следующая информация: СХ = возможные значения: 0000 — все символы структуры WIN32FINDDATA, составляющие основное и альтернативное имя файла, успешно преобразованы из Unicode; 0001 — основное имя, возвращенное в структуре WIN32FINDDATA, содержит знаки подчеркивания на месте символов, не преобразованных из Unicode; 0002 — альтернативное имя, возвращенное в структуре WIN32FINDDATA, содержит знаки подчеркивания на месте символов, не преобразованных из Unicode; CF = 1 — АХ = код ошибки при неудачном выполнении функции. Функция 714eh в отличие от аналогичных функций «старой» MS DOS использует не область DTA, а некоторый блок в памяти. Этот блок важно своевременно освобождать, для этого и предназначена функция 71alh.
Вход: АН = 71Alh; ВХ = дескриптор, полученный функцией 714eh. Выход: CF = 0 — успешное выполнение функции; CF = 1 — АХ = код ошибки при неудачном выполнении функции.

Ниже приведена структура WI N32_FIND_DATA, в которую в процессе поиска записывается информация о файлах.

WIN32_FIND_DATA struc
DwFlleAttributes dd ?
FtCreationTime dd 2 dup(?)
FtLastAccessTime dd 2 dup(?)
FtLastWriteTime dd 2 dup(?)
NFileSizeHigh dd ? .размер файла в байтах (старшее слово)
NFiieSizeLow dd ? ;размер файла в байтах (младшее слово)
DwReservedO dd 0 ;резерв
OwReservedl dd 0 ;резерв
CFileName db MAX_PATH dup(?)
CAlternateFileName db 14 dup(?) WIN32_FIND_DATA ends

Поля этой структуры описаны в следующей таблице.

dwFileAttributes
Атрибуты найденного файла (см. описание аналогичного элемента структуры BY HANDLE FILE INFORMATION)
ftCreationTime
Время создания файла в одном из двух форматов: MS DOS или в 64-разрядном, в зависимости от параметров, указанных при вызове функций 714eh (найти первый файл) и 714fh (найти следующий файл)
ftLastAccessTime
Время последнего доступа к файлу в одном из двух форматов: MS DOS или в 64-разрядном, в зависимости от параметров, указанных при вызове функций 714eh и 714fh
fUastWrUeTime
MS DOS или в 64-разрядном, в зависимости от параметров, указанных при вызове функций 714eh и 714fh
CFileName
ASCIIZ-строка, содержащая имя файла. Размер строки должен быть не менее 256 символов
cAlternateFileName
ASCIIZ-строка, содержащая альтернативное имя файла в стандартном формате 8.3. Если элемент cFileName содержит имя в формате 8.3 или файловая система не поддерживает альтернативные имена в формате 8.3, то элемент cAlternateFileName равен нулю

Приведем пример поиска файла по шаблону. Для этого предварительно создадим несколько файлов в соответствии с шаблоном file*.*. Среди этих файлов должен быть файл file_O5.txt. В отладчике проследим за тем, как изменяется
содержимое области памяти, отведенное для экземпляра структуры WIN32_FIND_ DATA. Выход из программы — при обнаружении файла file_5.txt

:prgO7_28.asm - программа демонстрации поиска файла по шаблону.

WIN32_FIND_DATA -uc
DwFlleAttributes dd ?
FtCreationTime dd 2 dup(?)
FtLastAccessTime dd 2 dup(?)
FtLastWriteTime dd 2 dup(?)
NFileSizeHigh dd ? .размер файла в байтах (старшее слово)
NFileSizeLow dd ? .размер файла в байтах (младшее слово)
DwReservedO dd 0 ;резерв
DwReservedl dd 0 :резерв
CFileName db 260 dup(?)
CAlternateFileName db 14 dup(?)
WIN32_FIND_DATA ends
.data
find_ WIN32_FIND_DATA <>
point_find_ dd find_
f_name_pattern db 'file_*.*'.O
point_f_name_pattern dd f_name_pattern
filename db 'file_05.txt',0 :искомый файл
1e*n_fi1ename=$-fi1ename
handle dw 0
movCL.O ;атрибуты искомого файла
movch.O ;дополнителные атрибуты для поиска
Ids dx,point_f_name_pattern ;формируем указатель на строку с шаблоном
les di.point_find_;формируем указатель на экземпляр структуры WIN32_FIND_DATA
movax.714eh :номер функции DOS
int 21h
jc exit
;в ах был возвращен дескриптор - если нужно, то его необходимо сохранить:

mov handle.ax
:проверяем, тот ли это файл: ml: mov ex.1en_fi1ename
lea di.find_.CfileName
lea si .filename repe empsb
jz exit ;продолжаем поиск - в Ьх дескриптор, полученный от 714eh:
mov bx.handle
les di.point_find_ :формируем указатель на экземпляр структуры WIN32_FIND_DATA
mov ax.714fh :номер функции DOS
хог si.si :формат даты
int 21h
jnc ml exit: завершить поиск
mov ax.71alh
mov bx.handle
int 21h

В отладчике хорошо видно, что выход из данной программы происходит в двух случаях:

когда файл найден, выход из программы производится в результате сравнения командой empsb (флаг ZF устанавливается в 1); когда файлов, удовлетворяющих шаблону, нет, функция поиска 714еп и 714fh завершается неудачей (флаг CF устанавливается в 1).

В качестве шаблона можно задать символы *.*, тогда мы сможем получить имена и проанализировать все файлы в текущем каталоге. Это может понадобиться при программировании операции перемещения или копирования каталога.
Остальные функции работы с файлами, предназначенные для записи/чтения/позиционирования, остались прежними.

В этом разделе будут приведены

В этом разделе будут приведены минимальные сведения, необходимые для выполнения простых операций с файлами. В отличие от MS DOS среда Win32 способна поддерживать несколько файловых систем. Главные требования к этим системам — иерархичность и соблюдение определенных правил присвоения имен каталогам и файлам.
Перечислим функции API Win32, имеющие отношение к работе с файловой системой. Полное их описание можно получить в MSDN.

Функция Назначение
AreFileApisANSI Определение набора символов файла — ANSI или OEM
CancelIo Отменить все ждущие обработки операции (I/O) ввода и вывода
CloseHandle Закрыть открытый дескриптор файла
CopyFile, CopyFileEx CopyProgressRoutine Копирование cуществующего файла в новый
CreateDi rectory, CreateDirectoryEx Определенная приложением функция обратного вызова, используемая с функциями CopyFileEx и MoveFileWithProgress. Она вызывается, когда завершается часть операции копирования или пересылки
CreateFile Создать каталог
DefineDosDevice Создать файл или объект специального типа
DeleteFile Определить, переопределить или удалить имена устройства MS DOS
FindCiose Удалить файл
Fi ndCloseChangeNoti fi cati on Закрыть указанный поисковый дескриптор (см. функции FindFirstFile и FindNextFile)
FindFi rstChangeNoti fication Закрыть объект-уведомление об изменении файла
FindFirstFile, FindFirstFileEx, FindNextFile Создать объект-уведомление об изменении файла
F1ndNextChangeNoti fi cati on Поиск файлов
FlushFileBuffers Сброс объекта-уведомления в занятое состояние
GetBinaryType Очистка буфера для указанного файла и запись всех буферизированных данных в файл
GetCurrentDirectory Определить, является ли файл исполняемым, и если это так, то для какой подсистемы — Win32, MS DOS, OS/2, POSIX и т. д.
GetDiskFreeSpace, GetDiskFreeSpaceEx Получить текущий каталог
GetDriveType Информация относительно указанного диска, включая количество свободного пространства на нем
GetFileAttributes, GetFileAttributesEx Определить тип диска — съемный, фиксированный, CD-ROM, электронный или сетевой
GetFi1elnformati onByHandle Получить атрибуты файла или каталога
GetFi1eSi ze, GetFi1eSi zeEx Найти информацию относительно указанного файла
GetFileType Получить размер указанного файла
GetFullPathName Получить тип указанного файла
GetLogical Drives, GetLogi calDri veStri ngs Получить полный путь и имя для указанного файла
GetLongPathName Определить доступные в настоящее время дисководы
GetShortPathName Преобразовать указанный путь к его длинной форме
GetTempFileName Получить псевдоним файла
GetTempPath Создать имя для временного файла
LockFile, LockFileEx Получить путь каталога для временных файлов Блокировка файла
Далее на примерах конкретных программ разберемся с тем, как использовать в программах на ассемблере наиболее интересные и часто применяемые функции из перечисленных выше для работы с файлами API Win32. В целях экономии места все примеры реализованы в виде консольных приложений. Основное внимание уделено не полноте описания параметров для вызова той или иной функции и результатов ее работы (эту информацию можно найти в справочниках по функциям API), а деталям практической реализации файловых операций в программах на языке ассемблера. Для изучения подробностей работы функций API Win32 необходимо использовать какой-либо отладчик для Windows, напри-MepTD32.EXE.

Обработка ошибок

Прежде чем рассматривать функции API Win32, относящиеся к файловому вводу-выводу, отметим, как можно выяснить причину их ошибочного завершения. Для этого Windows предоставляет функцию GetLastError.

DWORD GetLastError(void):

Для вызова функции GetLastError не нужно передавать никаких параметров. Эту функцию необходимо вызывать сразу после функции API Win32, успешность работы которой мы проверяем.

;.........
push offset info
push hFile
call GetFilelnformationByHandle
call GetLastError ;в регистре ЕАХ возвращается код ошибки

В регистре ЕАХ возвращается код ошибки. Расшифровать его можно с помощью файла Winerror.h, где вместе с кодами ошибок приведены короткие сообщения о причине их возникновения.

Создание, открытие, закрытие и удаление файла

Создание и открытие файла в Win32 производится одной функцией CreateFile. HANDLE CreateFi1eCLPCTSTR ipFileName, DWORD dwDesiredAccess. DWORD dwShareMode. LPSECURITY_ATTRIBUTES ipSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes. HANDLE hTemplateFile):
Параметры данной функции имеют размер двойного слова. Их назначение следующее (параметры описаны в порядке, обратном их записи в стек):

lpFileName — указатель на ASCIIZ-строку с именем (путем) открываемого или создаваемого файла; dwDesiredAccess — тип доступа к файлу: GENERICREAD = 80000000b - доступ по чтению; GENERIC_WRITE = 40000000b - доступ по записи; GENERIC_READ+GENERIC_WRITE = 0C0000000h - доступ по чтению-записи; DwShareMode — режим разделения файлов между разными процессами, данный параметр может принимать значения:
0 — монополизация доступа к файлу; FILE_SHARE_READ = 0000000th — другие процессы могут открыть файл, но только по чтению, запись в файл монополизирована процессом, открывшим файл;
FILESHAREWRITE = 00000002b — другие процессы могут открыть файл, но только по записи, чтение в файл монополизировано процессом, открывшим файл; FILE_SHARE_READ+FILE_SHARE_WRITE = 00000003b - другие процессы могут
открывать файл по чтению-записи; IpSecurityAttributes — указатель на структуру SecurityAttributes (файл winbase.h), определяющую защиту связанного с файлом объекта ядра, при отсутствии защиты заносится NULL;
ш dwCreationDistribution — определяет действия для случаев, когда файл существует или не существует (аналог этого параметра используется при вызове описанных выше функций MS DOS 6ch и 716ch), данный параметр может принимать значения: CREATE_NEW= 1 — создать новый файл, если файл не существует; если файл существует, то функция завершается формированием ошибки; CREATE_ALWAYS=2 — создать новый файл, если файл не существует; если он существует, то заместить новым; 0PEN_EXISTING=3 — открыть файл, если он существует; если файл не существует, то формируется ошибка; 0PEN_ALWAYS=4 — открыть файл при его существовании и создать его если файла нет;
TRUNCATE_EXISTING=5 — открыть файл с усечением его до нулевой длины; если файл не существует, то формируется ошибка;
DwFlagsAndAttributes — флаги и атрибуты; этот параметр используется для задания характеристик создаваемого файла: FILE_ATTRIBUTE_READ0NLY=OOOO0OOlh - файл только для чтения; FILE_ATTRIBUTE_HIDDEN=00000002h - скрытый файл; FILE_ATTRIBUTE_SYSTEM=00000004h - системный файл; FILE_ATrRIBUTE_DIRECTORY=OO0000lOh - каталог; FILE ATTRIBUTE ARCHIVE=00000020h - архивный ф'айл; FILE_ATTRIBUTE_N0RMAL=00000080h - обычный файл для чтения-записи (этот атрибут нельзя комбинировать с другими); FILE_ATTRIBUTE_TEMPORARY=0000Ol00h - создается временный файл (преимущество этого файла в том, что система стремится не записывать этот файл на диск, а работать с ним в памяти; этот атрибут выгодно комбинировать с флагом FILE_FLAG_DELETE_ON_CLOSE, тогда после закрытия файла в программе он будет удален, не оставив следов на диске, иначе, как и bMS DOS, программе придется «подчищать» за собой содержимое диска); FILE_FLAG_WRITE_THR0UGH=80000000h - не использовать промежуточное кэширование при записи на диск, а все изменения записывать прямо на диск; FILE_FLAG_NO_BUFFERING=20000000h - не использовать средства буферизации операционной системы; FILE_FLAG_RANDOM_ACCESS=10000000h - прямой доступ к файлу (установка этого флага или флага ILE_FLAG_SEQUENTIAL_SCAN позволяет оптимизировать системе процесс кэширования); FILE_FLAG_SEQUENTIAL_SCAN=08000000h - последовательный доступ к файлу; 0 ILE_FLAG_DELETE_0N_CL0SE=04000000h - удалить файл после его закрытия (см. описание атрибута ILEATTRIBUTETEMPORARY); FILE_FLAG_0VERLAPPED=40000000h - асинхронный доступ к файлу (синхронность означает то, что программа, вызвавшая функцию для доступа к файлу, приостанавливается до тех пор, пока не закончит работу функция ввода-вывода); hTemplateFile — параметр используется только при создании нового файла, его значением является дескриптор другого существующего и предварительно открытого файла, а новый файл создается с теми же значениями атрибутов и флагов, что и у файла, дескриптор которого указан в параметре hTemplateFile. При удачном завершении функция возвращает в регистре ЕАХ дескриптор нового файла. В случае неудачи функция возвращает в регистре ЕАХ значение NULL.

Закрытие файла

Закрытие файла производится функцией Cl oseHandl e:
B00L C1oseHandle( HANDLE hObject );
Функция имеет один параметр размером в двойное слово — дескриптор, полученный при открытии файла функцией CreateFile.
При удачном завершении функция возвращает ненулевое значение в регистре ЕАХ. В случае неудачи функция возвращает в регистре ЕАХ значение NULL.
Win32 поддерживает несколько функций для часто используемых операций над файлами: копирование, перемещение и переименование файлов.

Копирование файла

Для копирования файлов в Win32 используется функция CopyFile:
B00L CopyFile(LPCTSTR lpExistingFileName. LPCTSTR ipNewFileName. B00L bFailIfExists): Параметрами этой функции являются:

lpExistingFileName — указатель на ASCIIZ-строку с именем файла-источника; lpNewFileName — указатель на ASCIIZ-строку с именем файла-приемника, который может и не существовать; bFailIfExists — параметр, задаваемый равным 0 или 1, в зависимости от условий копирования: 0 — при наличии файла он удаляется и создается новый с содержимым файла-источника; 1 — при наличии файла копирование не производится, а функция CopyFile
возвращает ошибку. При удачном завершении функция возвращает ненулевое значение в регистре ЕАХ. В случае неудачи функция возвращает в регистре ЕАХ значение NULL.

;prg07_29.asm - Win32-nporpaMMa консольного приложения для исследования
;работы функции CopyFile API Win32.
;..........................................................
.data
TitleText db 'Копирование файлов в Win32'.О
s_file db "p".O ;имя входного файла
d_file db "pi".0 ;имя выходного файла
.code
mov eax.l
push eax
push offset d_file
push offset s_file
call CopyFileA
cmp eax.O
jz exit .выход в случае неудачи
:.........

Перемещение файла

Для перемещение файла Win32 содержит две функции MoveFile и MoveFi 1 еЕх:
BOOL MoveFile(LPCTSTR lpExistingFileName, LPCTSTR lpNewFileNam):
BOOL MoveFileEx(LPCTSTR TpExistingFileName. LPCTSTR ipNewFileName. DWORD dwFlags):
Параметрами функции MoveFile являются указатели на ASCIIZ-строки с именами файла-источника и файла-приемника. Функция MoveFi 1 еЕх обладает дополнительными свойствами благодаря наличию третьего параметра, который определяет особенности перемещения:

MOVEFILE REPLACE_EXISTING=00000001h - при существовании целевого файла он замещается содержимым файла-источника; MOVEFILE_COPY_AL10WED=00000002h - если не указывать специально, то функция MoveFi 1 еЕх не перемещает файлы на другой диск, а если перемещение требуется, необходимо устанавливать этот флаг; . MOVEFILE_DELAY_UNTIL_REBOOT=00000004h - (только для Windows NT и выше) файл-источник не удаляется до перезагрузки системы; MOVEFILE_WRITE_THROUGH=00000008h — установка флага гарантирует, что возврат из функции не произойдет до фактического перемещения и удаления файла. Кроме этого, функция MoveFi 1 еЕх допускает указание на месте второго параметра значения NULL, тем самым моделируя вызов функции Del eteFi I e.
При удачном завершении функции MoveFile и MoveFi 1 еЕх возвращают ненулевое значение в регистре ЕАХ. В случае неудачи функции возвращают в регистре ЕАХ значение NULL.

:prg07_30.asm - Win32-nporpaMMa консольного приложения для исследования :работы функции MoveFile(Ex) API Win32.
:
.data
TitleText db 'Перемещение файлов в Win32'.О
s_file db "p",0 ;имя входного файла
d_file db "pi".0 :имя выходного файла
.code
:.........
push offset d_file
push offset s_file
call MoveFileA
cmp eax.O
jz exit :выход в случае неудачи

Переименование файла

Специальной функции для переименования файла нет, так как она и не нужна — перемещение файла в пределах одного каталога по сути и является его переименованием.

Удаление файла

Для удаления файла применяется функция Del eteFi I e:
BOOL DeleteFile(LPCTSTR TpFileName);
У нее единственный параметр — указатель на ASCIIZ-строку с именем (путем) удаляемого файла. Перед удалением файл необходимо закрыть, хотя в некоторых версиях Windows это не является обязательным.
При удачном завершении функция возвращает ненулевое значение в регистре ЕАХ. В случае неудачи функция возвращает в регистре ЕАХ значение NULL.

Чтение, запись, позиционирование в файле

Необходимо сразу отметить, что Win32 допускает два режима доступа к файлу — синхронный и асинхронный. Необходимость введения этих двух режимов в архитектуру Win32 вызвано тем, что файловый ввод-вывод относится к наиболее медленным операциям и способен значительно ухудшить впечатление от компьютера с хорошей центральной частью (процессором и материнской платой) и плохой дисковой подсистемой. Поэтому разработчики Win32 уделяют много внимания моделированию файловых операций с использованием памяти компьютера. Это и упомянутые выше временные файлы и гибкая система кэширования вводимых и выводимых данных, а также файлы, отображенные в память, работу с которыми мы рассмотрим в конце данного раздела. Наше дальнейшее изложение будет посвящено организации синхронного ввода-вывода. Для обычных несложных приложений Win32 его вполне достаточно.

Установка текущей файловой позиции

Доступ к содержимому файла может быть произвольным (прямым) и последовательным. Как обычно, функции ввода-вывода работают с файловым указателем. Но необходимо иметь в виду, что файловый указатель связан только с описателем файла. Его значение равно текущему номеру позиции в файле, с которой будет'производиться чтение-запись данных при очередном вызове функции ввода-вывода. В первый момент после открытия значение указателя равно 0, то есть он указывает на начало файла. Функции, производящие чтение-запись в файле, меняют значение файлового указателя на количество прочитанных или записанных байт. При необходимости, а при организаций прямого доступа к файлу без этого не обойтись, значение файлового указателя можно изменять с помощью функции SetFilePointer:

DWORD SetFilePointer( HANDLE hFile, LONG IDistanceToMove. PLONG lpDistanceToMoveHigh. DWORD dwMoveMethod );

Параметры этой функции имеют размер двойного слова и следующее назначение:

cmp eax.O
jz exit :если неуспех
eld
mov edi,p_start
mov esi.p_start
mov ecx.FileSize cycl: moval.Odh repne scasb
cmp byte ptr [edi].0ah
jne $-5
inc edi
dec ecx
jeexz exit :весь файл прочитан
mov eax.edi
sub eax.esi :в еах - длина строки для вывода на экран, а в esi - ее адрес ;вывести очередную строку
call WriteConsoleA
cmp eax,0
jz exit :если неуспех
add esi,eax
jmp cycl закрываем файлы exit: :выход из приложения
return: ¦

При небольшой модификации программы можно построчно выводить содержимое любого текстового файла. Для небольших файлов совсем необязательно отслеживать конец каждой строки — можно выводить из буфера сразу весь файл одним вызовом функции WriteConsoleA.

Получение и изменение атрибутов файла

Аналогично группе функций MS DOS для работы с файловой системой файловая подсистема Win32 содержит ряд функций, с помощью которых можно определить характеристики конкретного файла.
Начальные значения атрибутов файла назначаются при создании файла. Впоследствии их можно изменить вызовом функции SetFi I eAttributes.
BOOL SetFileAttributestLPCTSTR ipFileName. DWORD dwFi1eAttributes);
Параметры этой функции означают следующее:
ш ipFileName — указатель на ASCIIZ-строку, содержащую имя файла;
Ш dwFil eAttri butes — двойное слово, определяющее, какие атрибуты файла могут быть установлены.
Планируя использование этой функции, необходимо иметь в виду, что не все возможные атрибуты файлов могут быть установлены с ее помощью. Перечислим те атрибуты, комбинацию которых можно задавать для изменения атрибутов файла, специфицированного параметром lpFileName: FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTENORMAL,
FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_
SYSTEM, FILEATTRIBUTETEMPORARY.
При удачном завершении функция SetFi 1 eAttri butes возвращает ненулевое значение в регистре ЕАХ. В случае неудачи функция возвращает в регистре ЕАХ значение NULL.
Для получения атрибутов файла используется функция GetFil eAttri butes.
DWORD GetFileAttributes(LPCTSTR lpFileName):
Функция имеет один параметр lpFileName, который является указателем на ASCIIZ-строку, содержащую имя файла.
При удачном завершении функция GetFil eAttri butes возвращает значение в регистре ЕАХ, которое является комбинацией атрибутов файла, специфицированного параметром lpFileName. Выделить эти атрибуты можно, используя логические команды ассемблера или команды обработки битов. В случае неудачи функция возвращает в регистре ЕАХ значение NULL.
В приложениях очень часто требуется определить размер файла. Для этого Win32 содержит отдельную функцию GetFileSize. DWORD GetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh ): Параметры функции означают следующее:

hFile — дескриптор файла, размер которого требуется определить; lpFileSizeHigh — адрес области памяти, куда помещаются старшие 32 бита значения размера файла, младшие 32 бита возвращаются функцией в регистре ЕАХ. При удачном завершении функция GetFil eSize возвращает значение младших 32 бит размера файла в регистре ЕАХ. В случае неудачи функция возвращает в регистре ЕАХ значение Offffffffh.
Особого разговора заслуживают возможности получения информации о временных характеристиках файлов. По сравнению с аналогичными средствами MS DOS в Win32 этот вопрос проработан значительно глубже. Хотя если посмотреть номенклатуру и описание функций MS DOS для работы с длинными именами файлов, то видно, что у них уже есть общие идеи, реализованные рассматриваемыми ниже функциями Win32.
Как уже отмечалось выше, в Win32 с файлом связаны три значения времени: время создания, время последнего доступа и время последней модификации. Получить эти значения можно с помощью функции GetFileTime.

BOOL GetFileTime( HANDLE hFile, LPFILETIME ipCreationTime. LPFILETIME ipLastAccessTime,
LPFILETIME ipLastWhteTime);

Перед вызовом данной функции, необходимо открыть файл, о значениях времени которого мы хотим получить информацию. Функции GetFileTime передается дескриптор этого файла и указатели на три экземпляра структуры FILETIME, в которые будут записаны время создания (IpCreationTime), время последнего доступа (lpLastAccessTime) и время последней записи (lpLastWriteTime).
Аналогично функции MS DOS 71a7h Win32 предоставляет две функции для взаимного преобразования DOS-времени файла в 64-битное представление времени:

BOOL FileTimeToDosDateTime(CONST FILETIME *lpFileTime, LPWORD lpFatDate.
LPWORD ipFatTime): BOOL DosDateTimeToFileTimetWORD wFatDate.
WORD wFatTime. LPFILETIME ipFiieTime);

Функция FileTimeToDosDateTime в качестве входного параметра принимает указатель *lpFi1eTime на экземпляр структуры FILETIME. Этот указатель содержит представление времени в виде 64-битного значения. На выходе данная функция формирует два значения в переменных размером в слово, адреса которых указаны параметрами lpFatDate и lpFatTime. Формат этих слов совпадает с форматом соответствующих параметров, которыми манипулирует функция 71a7h.
Функция DosDateTimeToFileTime, наоборот, преобразует время в формате DOS представленное в виде двух слов wFatDate, wFatTime (для времени и даты соответственно), в 64-битное значение 1 pFi I eTime.
Установить время создания, последнего доступа или модификации файлов можно с помощью функции SetFileTime.

BOOL SetFileTime( HANDLE hFile. const FILETIME *lpCreationTime.
const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime ):

В качестве входных параметров функция SetFil eTime принимает указатели на три экземпляра структуры FILETIME и дескриптор файла. Экземпляры структур уже заполнены необходимыми значениями времени. Если какое-либо из значений устанавливать не нужно, то вместо указателя на соответствующую структуру передается NULL. В случае успешного завершения функция возвращает ненулевое значение в регистре ЕАХ.
Из вышеизложенного видно, что для получения различных характеристик файла используются множество различных функций. Работа с ними может утомить кого угодно. Нельзя ли чего-нибудь попроще? Можно. Win32 предоставляет функцию GetFi I elnformationByHandl e:

BOOL GetFileInformationByHandle( HANDLE hFile.
LPBY_HANDLE_FILE_INFORMATION lpFilelnformation );

На вход данной функции передается дескриптор файла, о котором необходимо получить Информацию, и указатель на экземпляр структуры BYHANDLEFI LE_ INFORMATION, который заполняется этой функцией. Как видно из названия полей (см. код ниже), в этой структуре сосредоточена вся информация о файле. Ниже приведен пример кода, использующего данную структуру.

;prg07_32.asm - Win32-nporpaMMa консольного приложения для
Win32 для исследования работы
функции GetFilelnformationByHandle API Win32.
;описание структур
FILETIME struc
DwLowDateTime dd ? ;младшие 32 бита значения времени
DwHighDateTime dd ? :старшие 32 бита значения времени
FILETIME ends
BY_HANDLE_FILE_INFORMATION struc
DwFileAttributes dd 0 атрибуты файла
struc
FtCreationTime_DwLowDateTime dd ? ;младшие 32 бита
значения времени создания файла FtCreationTime_
DwHighDateTiirie dd ? :старшие 32 бита значения времени создания файла
ends
struc
FtLastAccessTime_DwLowDateTime dd ? ;младшие 32 бита значения времени поел,
доступа FtLastAccessTime_DwHighDateTime dd ? :старшие 32 бита значения времени поел, доступа
ends
struc
^¦LastWriteTime_DwLowOateTime dd ? :младшие 32 бита значения времени поел, записи
^¦LastWnteTimeJDwHighDateTime dd ? :старшие 32 бита значения времени поел, записи ends
. .".-rialNumber dd С ;серийный номер тома, на котором находится файл
| nfTleSizeHigh d
d 0 :старшие 32 бита размера файла ¦nFiieSizeLow dd 0
:младшие 32 бита размера файла I nNumberOftinks dd 0 ;
число ссылок на файл | nFilelndexHigh dd 0 ;старшие 32 бита идентификатора файла nFilelndexLow dd 0 ; младшие 32 бита идентификатора файла
ends .data
t info BY_HANDLE_FILE_INFORMATION <> TitleText db 'Получение информации о файле в
Win32',О lpBuf db "p",0 I hFile dd 0 .code
¦-------------------------------------CreateFi 1 e
Нгкрываем файл
push О
push 0 -.атрибуты (они игнорируются)
push OPEN_EXISTING :открыть существующий файл, если его нет - ошибка
push 0 : защита файла не требуется
push FILE_SHARE_READ разрешено совместное использование файла (по чтению)
push GENERIC_READ разрешено чтение из файла
push offset lpBuf
call CreateFileA
emp eax.Offffffffh
je exit :если неуспех
mov hFile.eax :дескриптор файла №
GetFilelnformationByHandle
push offset info
push hFile
call GetFilelnformationByHandle
emp eax.O
jz exit :выход в случае неудачи ¦"^
результат смотрим в отладчике TD32.exe

Результат работы данной программы можно посмотреть и проанализировать в отладчике.

Работа с дисками, каталогами и организация поиска файлов

Win32 располагает большим набором функций для получения информации о структуре файловой системы конкретного компьютера. Часть этих функций раз-вивает идеи работы с файловой подсистемой, появившиеся в последних версиях WAS DOS. Другие функции являются уникальными для платформы Win32. Рас-Рассмотрим наиболее интересные из них.
Программа, предназначенная для исследования файловой системы, прежде всего должна знать, какие логические диски присутствуют в системе. Среди
нескольких функций, выполняющих эту работу, наиболее удобной для процесса обработки является GetLogicalDrivesString.

DWORD GetLogicalDriveStrings(DWORD nBufferLength, LPTSTR lpBuffer);

Данной функции передаются два параметра: lpBuffer — адрес буфера, в который помешаются имена корневых каталогов логических дисков, установленных в системе; nBufferLength — длина буфера, заданного указателем lpBuffer. В качестве возвращаемого значения функция формирует длину буфера, действительно необходимую для размещения строки с именами корневых каталогов логических дисков. Например, при наличии трех логических дисков структура заполненного буфера будет следующей: А:\0В:\0С:\0. Заметьте, что имена корневых каталогов разделены нулевыми байтами. Более эффективно вызывать эту функцию два раза: первый раз с нулевым значением первого параметра, при этом функция вернет потребное количество байт для размещения буфера; второй раз функцию уже можно вызывать, подставив на место первого параметра значение, возвращенное при первом вызове.

:prg07_33.asm - Win32-консольное приложение для Win32 для исследования работы :функции GetLogicalDriveStrings API Win32.
.data
TitleText db 'Получение информации о дисках в Win32',0 '
infojmf db 10 duo (0)
.code
:.......----GetLogi cal Dri veStri ngs................-........
push offset info_buf
push 0
call GetLogicalDriveStringsA
cmp eax.O
jz exit ;выход в случае неудачи
;вызываем функцию второй раз. когда известно количество байт, потребное :для записи списка корневых каталогов
push offset info_buf
push eax
call GetLogicalDriveStringsA
cmp eax.O
jz exit :выход в случае неудачи результат смотрим в отладчике TD32.exe

Недостаток функции GetLogi cal Dri veStri ngs состоит в том, что она работает не во всех версиях Windows. Альтернативным вариантом получения информации о наличии дисков в системе является функция GetLogi cal Drives.
DWORD GetLogicalDrives(VOID);
Эта функция возвращает в регистре ЕАХ битовую маску, в которой установленные биты указывают на существование логического диска: бит 0 — А, бит 1 — В, бит 2 — С... Таким образом, с помощью функции GetLogi cal Drives можно достичь того же самого результата, что и с помощью функции GetLogi cal Dri veStri ngs, но несколько большими трудами.

;prg07_34.asm - Win32-консольное приложение для исследования
;работы функции GetLogicalDrives API Win32.
.data
TitleText db 'Получение информации о дисках в Win32'.0
info_buf db 10 dup (0)
.code
call GetLogicalDrives cmp eax.O
jz exit ;выход в случае неудачи результат смотрим з отладчике TD32.exe

После того как информация о номенклатуре логических дисков в системе получена, можно получить информацию о каждом из них. Для этого используется функция GetVolumelnformation.

BOOL GetVolumeInformation(LPCTSTR ipRootPathName.
LPTSTR lpvolumeNameBuffer. DWORD nVolumeNameSize, LPDWORD ipVolumeSerialNumber, LPDWORD
ipMaximumComponentLength. LPDWORD lpFileSystemFlags.
LPTSTR ipFileSystemNameBuffer. DWORD nFileSystemNameSize);

На вход функции GetVolumelnformation подаются следующие параметры:

IpRootPathName — указатель на строку с именем корневого каталога диска, информацию о котором необходимо получить (если параметр равен NULL, функция формирует информацию о текущем диске). Формат задания имени корневого каталога диска — имя_диска:\. Это единственный параметр, значение которого нужно задавать, остальные параметры — адреса областей памяти, в которые будут помещены значения, формируемые функцией; lpVolumeNameBuffern и nVolumeNameSize — указатель на буфер и размер буфера, в который будет записано имя диска; IpVolumeSerial Number — адрес двойного слова, куда будет записан серийный номер. Если информация о серийном номере диска не нужна, то при вызове функции значение этого параметра необходимо сделать равным NULL; lpMaximumComponentLength — адрес двойного слова, куда будет записано значение максимальной длины пути, возможное в данной файловой системе; lpFileSystemFlags — флаги с дополнительной информацией о файловой системе: • FS_CASE_SENSITIVE=FILE_CASE_SENSITIVE_SEARCH
=00000001h - поддержка со стороны файловой системы поиска с сохранением регистра букв; • FS_CASE_IS_PRESERVED=FILE_CASE_PRESERVED_NAMES
=00000002h - при записи на диск сохранить регистр букв в имени файла; • FS_UNICODE_STORED_ON_DISK=FILE_UNICODE_ON_DISK
=00000004h - файловая система поддерживает хранение имен файлов в Unicode; • FSPERSI STENT_ACLS=FI LEPERS I STENT_ACLS
=00000008h - файловая система способна оперировать со списками контроля доступа (ACL) — только для NTFS;
• FS_FILE_COMPRESSION=FILE_FILE_COMPR?SSION
=00000010h — файловая система поддерживает сжатие файлов;
• FS_VOL_IS_COMPRESSED=FILE_VOLUME_IS_COMPRESSED
=00008000h - том, о котором запрашивается информация, был сжат;
a lpFileSystemNameBuffer и nFileSystemNameSize — указатель и размер буфера в который будет записано имя файловой системы. Если TpFiieSystemName-Buffer=NULL, то в эти параметры ничего не записывается. Изменить метку диска может вызов функции SetVolumeLabel.
BOOL SetVolumeLabel(LPCTSTR IpRootPathName. LPTSTR lpVolumeName):
Параметр IpRootPathName задает адрес строки с именем корневого каталога диска, метку которого меняем. Второй параметр 1 pVol umeNarae — строка с меткой тома. Для удаления метки тома с диска параметр lpVolumeName нужно задать равным NULL.

Получить информацию о свободном дисковом пространстве

Информацию о свободном дисковом пространстве, а заодно и о разбиении диска на сектора и кластеры позволяет получить функция GetDiskFreeSpace.
BOOL GetDiskFreeSpaceCLPCTSTR IpRootPathName.
LPDWORD ipSectorsPerCluster, LPDWORD lpBytesPerSector,
LPDWORD ipNumDerOfFreeClusters. " LPDWORD ipTotalNumberOfClusters):

На вход функции нужно подать строку с именем корневого каталога диска, о котором необходимо получить информацию (NULL для текущего диска), и адреса буферов, куда будет помещена следующая информация: общее количество кластеров на диске (1 pTotal NumberOfCl usters), общее количество свободных кластеров (TpNumberOfFreeCI usters), количество байт в секторе (lpBytesPerSector), количество секторов в кластере (IpSectorsPerCluster).

Создание и удаление каталога

Создание каталога выполняет функция CreateDi rectory.
BOOL CreateDi rectory (LPCTSTR lpPathName. LPSECURITYJVTTRIBUTES.IpSecurityAttributes ¦:
Первый параметр этой функции lpPathName — указатель на ASCIIZ-строку с путем, последний элемент которого является именем нового каталога. Параметр ipSecurityAttributes — указатель на экземпляр структуры Security_Attributes.

SECURITY_ATTRIBUTES stoic
nLength dd. 0
lpSecurityDeschptor dd 0
blnheritHandle dd
ends

С помощью структуры SecurityAttributes можно ограничить доступ пользователя к каталогу. Параметр IpSecurityAttributes обычно задается равным NULL. Более подробную информацию о параметрах структуры можно получить в MSDN.
Удаление каталога выполняет функция RemoveDi rectory.
BOOL RemoveDirectory(LPCTSTR lpPathName);
единственный параметр этой функции ipPathName — указатель на ASCIIZ-стро-^Вс путем, последний элемент которого является именем удаляемого каталога. ^Удаляемый каталог не должен быть пустым.

Определение и изменение текущего каталога

Аналогично принципам организации файловой системы MS DOS в Win32 также Иуществует понятие текущего каталога, то есть каталога, в котором выполняются ^шеущие операции по работе с файлами. В отличие от MS DOS понятие текуще-^^Италога относится к текущему процессу. При запуске процесса текущим бу-I дет являться каталог, из которого этот процесс был запущен. Определяет текущий налог процесса функция GetCurrentDirectory.
RD GetCurrentDirectory(OWORD nBufferLength, LPTSTR ipBuffer);
it Параметры TpBuffern и BufferLength определяют соответственно адрес и длину I буфера, в который помещается путь с текущим каталогом (строка с завершаю-Нцим нулем). Функция возвращает NULL в случае ошибки и число байтов, необходимо для записи данных в буфер, в случае удачного завершения. Завершающий ^ нуль в возвращаемом функцией числе не учитывается. Если буфер мал, то с помощью возвращаемого значения можно изменить его размер. [ Изменить текущий каталог процесса можно с помощью функции SetCurrent-^Brectory.
¦6001 SetCurrentDi rectory (LPCTSTR IpszPathName): "
j" Параметр IpszPathName — адрес ASCIIZ-строки с путем, последний элемент ко-I торою — новый текущий каталог данного процесса.
[i Платформа Win32 также поддерживает понятие системного и основного ка-^ВДога Windows. Для определения системного каталога существует специальная |; функция GetSystemDi rectory.
[ GetSystemDirectory(LPTSTR ipszBuffer, UINT uSize):
Два параметра этой функции определяют адрес и размер буфера, в который I записывается путь к системному каталогу Windows.
„Для определения основного каталога Windows существует специальная функция
GetWindowsDi rectory.-
UINT GetWindowsDirectorydPTSTR IpBuffer. UINT uSize);
Два параметра этой функции определяют адрес и размер буфера, в которыйзаписывается путь к основному каталогу Windows. Возвращаемое значение количество реально записанных в буфер байтов. Его можно использовать для г корректировки параметра uSize, если он был задан слишком маленьким, и повторного вызова функции GetWindowsDi rectory.
Для демонстрации применения вышеприведенных функций рассмотрим комплексный пример, в ходе которого продемонстрируем порядок вызова и анализа Е возвращаемых значений функциями API Win32 для работы с каталогами. Опре-
делим текущий каталог процесса, создадим новый каталог, сделаем его текущим удалим новый каталог, определим системный каталог и каталог Windows.

:prg07_35.asm - Win32-KOHCo/ibHoe приложение для исследования работы функций ;работы с каталогами API Win32.
.data
TitleText db 'Работа с каталогами в Win32',0
NewOir db "Новый каталог".0
dirjbuf db 50 dup ("?")
size_dir_buf=$-dir_buf
Parent db "..".0
.code
:определив текущий каталог
push offset dirjwf
push size_dir_buf
call GetCurrentDirectoryA
cmp eax.0
jz exit ;выход в случае неудачи :создадим каталог
push 0
push offset NewDir .
call CreateDirectoryA
cmp eax,0
jz exit :выход в случае неудачи ¦.сделаем новый каталог текущий
push offset NewDir
call SetCurrentDirectoryA
cmp eax.0
jz exit ;выход в случае неудачи
;проверим новый текущий каталог
push offset dir_buf
push size_dir_buf
call GetCurrentDirectoryA
cmp eax.0
jz exit .-выход в случае неудачи
;------.....SetCurrentDi rectory-..................-.........
:вернемся в родительский каталог
push offset Parent
call SetCurrentDirectoryA
cmp eax.0
jz exit ;выход в случае неудачи
;проверил новый текущий каталог
push offset dir_buf
push size_dir_buf
call GetCurrentDirectoryA
cmp eax.O
jz exit :выход в случае неудачи :удалим новый текущий каталог
push offset NewDir
call RemoveDirectoryA
cmp eax.O
jz exit ;выход в случае неудачи I определив системный каталог mov eax.size_dir_buf push eax
push offset dir_buf call GetSystemDirectoryA cmp eax.O
jz exit :выход в случае неудачи ¦.определим основной каталог Windows mov eax.size_d1r_buf push eax
push offset dir_buf call GetWindowsDirectoryA cmp eax.O
jz exit -.выход в случае неудачи результат смотрим в отладчике TD32.exe

Среди функций Win32, работающих с текущим каталогом, существует функция GetFuT I PathName, которая по имени файла формирует его полное имя, состоящее из пути от корневого каталога к текущему. Последний элемент этого имени — имя входного файла.
DWORD GetFulIPathNameCLPCTSTR ipFileName. DWORD nBufferLength, LPTSTR ipBuffer.
LPTSTR *lpFilePart): I На входе функция принимает имя файла в виде ASCIIZ-строки. На выходе —
три параметра:

IpBuffer — адрес буфера, в который помещается полный путь с именем
файла; nBufferLength — длина буфера, на который указывает параметр IpBuffer,
в символах; lpFilePart — адрес ячейки размером с двойное слово, в которое помещается указатель на позицию внутри буфера, идентифицированную параметром 1 pBuf fег и соответствующую первому символу имени файла после имен всех каталогов. Самое интересное в этой функции — механизм ее работы. Суть его в том, что
реально функция GetFul I PathName не ищет файл, ка имя которого указывает параметр IpBuffer. Результат своей работы — полный путь — она формирует из двух
компонент: полного пути к текущему каталогу данного процесса и имени файла,
наличие которого на диске функция GetFul I PathName даже не проверяет. Для подобной работы ей даже не нужно обращаться к диску. С аналогичной функцией
' мы уже имели дело, когда рассматривали функции MS DOS для работы с файлами, имеющими длинные имена.

Поиск файлов

При последовательном изучении материала данного раздела читатель кроме знакомства со средствами по работе с файлами операционных систем фирмы Microsoft поневоле должен был оценить процесс эволюции этих средств. Особенно очевиден этот процесс при поиске файлов.
Платформа Win32 предлагает два способа поиска файлов:

с использованием функции SearchPath; с использованием функций FindFirr,tFile, FindNExtFile и структуры WIN32 FIND DATA. Поиск файлов с помощью функции SearchPath

Функция SearchPath ищет файлы в указанном при ее вызове списке каталогов.
DWORD SearchPathtLPCTSTR lpPath. LPCTSTR ipFileName. LPCTSTR lpExtension, DWORD nBufferiength. LPTSTR ipBuffer, LPTSTR *lpFilePart):
Первый параметр lpPath определяет список каталогов, в которых будет осуществляться поиск файла. Параметры lpFileName и lpExtension указывают на ASCIIZ-строки с именем и расширением искомого файла. Наличие пары этих параметров позволяет задавать имя и расширение файла двумя способами:

одной ASCIIZ-строкой — на нее указывает параметр lpFileName, при этом параметр ipExtension равен NULL; отдельными ASCHZ-строками — в этом случае параметр ipFileName содержит указатель на ASCIIZ-строку с именем файла, а второй парамет lpExtension — содержит указатель на ASCIIZ-строку с расширением файла; строка с расширением должна начинаться с символа . (точка). Параметр IpBuffer указывает на буфер, куда записывается ASCHZ-строка с полным путем к искомому файлу. Длина этого буфера определяется параметром nBufferLength. Если эта длина слишком мала, то ее можно подкорректировать значением, возвращаемым функцией в регистре ЕАХ. Это значение является личеством символов, действительно необходимых для записи полного имени найденного файла в буфер. Если в ЕАХ возвращается NULL, то это говорит об ошибке вызова функции.
Последний параметр lpFilePart является указателем на символ в буфере, с которого начинается собственно имя файла.
При вызове функции SearchPath параметр lpPath можно задать равным NULL. В этом случае поиск файла будет осуществляться в следующих каталогах (порядок перечисления соответствует порядку просмотра при поиске):

каталог, из которого запущено приложение; текущий каталог; системный каталог; основной каталог Windows; каталоги, перечисленные в переменной окружения PATH. Поиск файлов с помощью функций FindFirstFile и FindNExtFile Предыдущий способ поиска обладает существенным недостатком — ограниченным числом каталогов диска, подвергающихся просмотру в процессе поиска. По этой причине он не может быть использован для поиска в пределах всего диска. Этот недостаток устраняется при втором способе поиска — с использованием функций FindFirstFile, FindNExtFile и структуры WIN32FINDDATA. Этот способ реализует определенный алгоритм поиска. Вначале вызывается функция FindFirstFile, которая имеет два параметра: lpFileName — указатель на ASCII-строку с именем файла; lpFindFileData — указатель на экземпляр структуры WIN32_FIND_OATA.
HANDLE FindFirstFiletLPCTSTR lpFileName. LPWIN32_FIND_DATA lpFindFileData): Имя файла может содержать символы шаблона * и ?. Кроме того, имя может Вырожать путь, с которого нужно начинать поиск. Выше, при знакомстве с функциями MS DOS для работы файлами, имеющими длинные имена, приводилось Иписание структуры WIN32_FIND_DATA и ее полей.
В случае успеха функция FindFirstFile заполняет поля структуры WIN32_FIND_ DATA и возвращает значение дескриптора внутренней структуры в памяти, который впоследствии может быть использован функциями FindNextFile или FindClose. В случае неудачи функция не изменяет содержимое структуры WIN32_FIND_DATA и возвращает значение
INVALID_HANDLE_VALUE (EAX=-llo=Offffffffh). 1 Проанализировав результаты поиска, программа может продолжить или прекратить его. Для продолжения поиска необходимо вызвать функцию Fi ndNExtFi I e. I BOOL FindNextFile
( HANDLE hFindFile. LPWIN32_FIND_DATA lpFindFileData ):

В качестве параметров используются дескриптор, полученный в регистре ЕАХ в результате поиска функцией FindFirstFile, и указатель на экземпляр структуры WIN32_FIND_DATA. В случае успеха функция FindNextFile возвращает ненулевое значение в регистре ЕАХ и заполняет структуру WIN32FINDDATA. При неудаче —
I ЕАХ = 0.
Для продолжения поиска при неизменных исходных параметрах поиска функ-
ция FindNextFile вызывается циклически.
Для окончания процесса поиска необходимо вызвать функцию FindClose.
BOOL FindCloset HANDLE hFindFile ):
i Функция FindClose имеет один параметр — дескриптор, полученный функци-Нй FindFirstFile в начале поиска. В случае успеха функция FindClose возвращает Е ненулевое значение в регистре ЕАХ, при неудаче — ЕАХ = 0.

Файлы, отображаемые в память

¦Платформа Win32 позволяет организовать работу с содержимым файла как с ^Властью оперативной памяти, без использования операций файлового ввода-Лывода. Этот механизм отображает (проецирует) содержимое файла на область Императивной памяти. Программе передается адрес этой области, после этого ра-Ибота с содержимым файла осуществляется командами работы с памятью.
Для «проецирования» файла необходимо выполнить следующие действия.

1. Требуется создать (для несуществующего файла) или открыть (для существующего файла) объект ядра файл. Цель этого шага — сообщить системе, где находится физическое представление файла. Создание или открытие объекта ядра файл производится с помощью функции CreateFile (см. выше). Все параметры этой функции задаются обычным образом. На выходе в случае успеха функция формирует дескриптор (в регистре ЕАХ), в обратном случае - значение INVALID_HANDLE_VALUE (ЕАХ—llo=Offffffffh).
2. Требуется создать объект ядра проекция файла. Цель этого шага — сообщить системе размер проецируемого файла. Для этого используется функция CreateFi I eMappi ng:
HANDLE CreateFileMapping
(HANDLE hFile. LPSECURITY_ATTRIBUTES
ipFileMappingAttributes DWORD flProtect.
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow. LPCTSTR ipName);
Параметр hFile является дескриптором файла, полученным функцией Create-File. Параметр 1 pFi 1 eMappingAttributes — указатель на экземпляр структуры SECURITYATTRIBUTES, которая служит для установки защиты. Присвойте параметру lpFil eMappi ngAttri butes значение NULL. Параметр flProtect предназначен для установки атрибутов защиты страниц физической памяти в адресном пространстве процесса, на которые отображается файл. Используют один из следующих атрибутов:
PAGE_READONLY=02 — доступ к файлу только по чтению (при использовании этого параметра вызов CreateFile должен был производиться с флагом GENERIC_READ);
€ PAGEREADWRI TE=04 — доступ к файлу только по записи (при использовании этого параметра вызов CreateFile должен был производиться с флагом GENERICREAD | GENERICWRITE);
a PAGE_WRITECOPY=08 — доступ к файлу по чтению-записи с созданием копии данных из файла, при этом исходный файл не изменяется, изменения касаются лишь модифицированных страниц копии в страничном файле (при использовании этого параметра вызов CreateFile должен был производиться с флагом GENERIC_READ или GENERIt_READ|GENERIC_WRITE).
Параметры dwMaximumSizeHigh и dwMaximumSizeLow предназначены для того, чтобы сообщить системе максимальный размер файла в байтах. При этом в dwMaximumSizeLow указываются младшие 32 бита этого значения, а в dwMaximumSizeHigh — старшие 32 бита. Если предполагается размер файла, равный текущей его длине, то следует при вызове функции передать dwMaxi ¦ mumSizeLow=dwMaximumSizeHigh=NULL.
Последний параметр IpName — указатель на ASCIIZ-строку с именем объекта проецируемый файл для обеспечения доступа к нему других процессов. Обычно задают равным NULL.
3. Требуется выполнить проецирование файла на адресное пространство процесса. В этом шаге две цели. Первая цель — сообщить системе порядок отображения (проецирования) файла на адресное пространство процесса — полный или частичный. Вторая цель — получить адрес этого отображения в памяти. Реализация этих целей достигается функцией MapViewOfFile: LPVOID MapViewOfFi1e(HANDLE hFileMappingObject,
DWORD dwDesiredAccess. DWORD dwFileOffsetHigh. DWORD dwFileOffsetLow.
DWORD dwNumberOfBytesToMap);
Параметр hFil eMappi ngObject — дескриптор, возвращенный функцией Create-Fi 1 eMapping на предыдущем шаге. Параметр dwDesiredAccess определяет вид доступа к данным:
FILE_MAP_COPY=01 — данные в файле доступны по чтению, хотя отображенные данные доступны по чтению и по записи; операция записи приводит к созданию копии страницы в страничном файле, в которую производится запись, поэтому после первой операции записи теряется соответствие между реальными данными на диске и данными, с кото рыми работает приложение (при использовании этого значения параметра dwDesiredAccess функция CreateFil eMappi ng должна была быть вызвана с одним из атрибутов: PAGE_READONLY, PAGE_READWRITE или PAGEWRITECOPY);
• FILE_MAP_WRITE=02 — данные в файле доступны по чтению-записи (при использовании этого значения параметра dwDesiredAccess функция CreateFil eMapping должна была быть вызвана с атрибутом PAGE_READWRITE);
ш FILEMAPRE AD=04 — данные в файле доступны по чтению (при использовании этого значения параметра dwDesiredAccess функция CreateFile-Mapping должна была быть вызвана с одним из атрибутов: PAGE_READONLY, PAGE_READWRITE или PAGE_WRITECOPY);
• FILE_MAP_ALL_ACCESS=OOOFO00Oh + OOOOOOOlh + 00000002h +
00000004h + 00000008h + OOOOOOlOh — данные в файле доступны по чтению-записи (при использовании этого значения параметра dwDesiredAccess функция CreateFile-Mapping должна была быть вызвана с атрибутом PAGERE ADWRI ТЕ).
Параметры dwFileOffsetHigh, dwFileOffsetLow и dwNumberOfBytesToMap предназначены для указания позиции в файле, с которой начинать отображение, и количества отображаемых байт (dwNumberOfBytesToMap). Параметр dwFileOffsetHigh — старшие 32 бита этого смещения, а параметр dwFileOffsetLow — младшие 32 бита этого смещения. Таким образом, с файлом можно работать не целиком, а по частям, эффективно используя при этом оперативную память. Заметим, что если задать параметр dwNumberOfBytesToMap равным NULL, то система будет пытаться отобразить содержимое файла с указанной парой dwFileOffsetHigh:dwFileOffsetLow смещения и до конца файла. В случае успеха функция формирует адрес отображения в памяти (регистр ЕАХ), в обратном случае ЕАХ = 0. После получения в ЕАХ адреса начала отображения в памяти приложение может работать с данными файла обычными командами работы с памятью. При необходимости функция MapViewOfFile может быть вызвана повторно с другими параметрами dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow и dwNumberOfBytesToMap. При этом (запомните!) резервируется новый регион в памяти.
После выполнения необходимых действий приложение должно корректно завершить работу с отображением файла.
4. Требуется выполнить разрыв связи данных в файле и соответствующими данными, отображенными на адресное пространство процесса. Это дейст-
I вие выполняет функция UnmapViewOfFile. BOOL UnmapViewOfFile( LPCVOID ipBaseAddress);
Эта функция имеет единственный параметр — IpBaseAddress, который является значением, возвращенным функцией MapViewOfFile. С помощью функции UnmapViewOfFile необходимо разрывать каждое из отображений, созданных последовательностью вызовов MapViewOfFile, сохраняя при этом их соответствия. Также имейте в виду, что если функция MapViewOfFile была вызвана с параметром FILEMAPCOPY, то после вызова UnmapViewOfFile теряются все внесенные в отображенные данные изменения.
5. Далее нужно закрыть объект ядра проекция файла. В принципе, этот и сле-ivmmuu шяг нр яиляютг.я обязательными, так как система в процессе за-
вершения работы приложения освободит все ресурсы. Освобождение
объекта ядра проекция файла производится функцией CloseHandle.
BOOL CloseHandle( HANDLE hObject):
Функции CloseHandle передается единственный параметр hObject — де.
скриптор, полученный как результат вызова функции CreateFileMapping.
6. Требуется закрыть объект ядра файл. Освобождение объекта ядра файл также производится функцией CloseHandle.
BOOL CloseHandle( HANDLE hObject );
Функции CloseHandle передается единственный параметр hObject — дескриптор, полученный как результат вызова функции CreateFile.
Пример программы (prg07_36.asm), демонстрирующей порядок использования файлов, отображаемых в адресное пространство процесса, достаточно велик и по этой причине вынесен на дискету. Работа программы проста и заключается в следующем: необходимо вывести содержимое некоторого файла на экран — в окно консоли. Имя исходного файла вводится с клавиатуры.