Работа с файлами в программах на ассемблере (Часть 2)

Файловый ввод-вывод в Win32

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

Функция
Назначение
AreFileApisANSI
Определение набора символов файла — ANSI или OEM
CancelIo
Отменить все ждущие обработки операции (I/O) ввода и вывода
CloseHandle
Закрыть открытый дескриптор файла
CopyFile,
CopyFileEx CopyProgress
Routine
Копирование cуществующего файла в новый
Определенная приложением функция обратного вызова, используемая с функциями CopyFileEx и MoveFileWithProgress. Она вызывается, когда завершается часть операции копирования или пересылки
CreateDi rectory, CreateDirectoryEx
Создать каталог
CreateFile
Создать файл или объект специального типа
DefineDosDevice
Определить, переопределить или удалить имена устройства MS DOS
DeleteFile
Удалить файл
FindCiose
Закрыть указанный поисковый дескриптор (см. функции FindFirstFile и FindNextFile)
Fi ndCloseChange
Noti fi cati on
Закрыть объект-уведомление об изменении файла
FindFi rstChange
Noti fication
Создать объект-уведомление об изменении файла
FindFirstFile,
FindFirstFileEx, FindNextFile
Поиск файлов
F1ndNextChange
Noti fi cati on
Сброс объекта-уведомления в занятое состояние
FlushFileBuffers
Очистка буфера для указанного файла и запись всех буферизированных данных в файл
GetBinaryType
Определить, является ли файл исполняемым, и если это так, то для какой подсистемы — Win32, MS DOS, OS/2, POSIX и т. д.
GetCurrentDirectory
Получить текущий каталог
GetDiskFreeSpace, GetDiskFreeSpaceEx
Информация относительно указанного диска, включая количество свободного пространства на нем
GetDriveType
Определить тип диска — съемный, фиксированный, CD-ROM, электронный или сетевой
GetFileAttributes, GetFileAttributesEx
Получить атрибуты файла или каталога
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 dd 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льнoe приложение для исследования работы функций ;работы с каталогами 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.
  4. 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);
  5. 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 ТЕ).
  6. Параметры dwFileOffsetHigh, dwFileOffsetLow и dwNumberOfBytesToMap предназначены для указания позиции в файле, с которой начинать отображение, и количества отображаемых байт (dwNumberOfBytesToMap). Параметр dwFileOffsetHigh — старшие 32 бита этого смещения, а параметр dwFileOffsetLow — младшие 32 бита этого смещения. Таким образом, с файлом можно работать не целиком, а по частям, эффективно используя при этом оперативную память. Заметим, что если задать параметр dwNumberOfBytesToMap равным NULL, то система будет пытаться отобразить содержимое файла с указанной парой dwFileOffsetHigh:dwFileOffsetLow смещения и до конца файла. В случае успеха функция формирует адрес отображения в памяти (регистр ЕАХ), в обратном случае ЕАХ = 0. После получения в ЕАХ адреса начала отображения в памяти приложение может работать с данными файла обычными командами работы с памятью. При необходимости функция MapViewOfFile может быть вызвана повторно с другими параметрами dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow и dwNumberOfBytesToMap. При этом (запомните!) резервируется новый регион в памяти.
    После выполнения необходимых действий приложение должно корректно завершить работу с отображением файла.
  7. Требуется выполнить разрыв связи данных в файле и соответствующими данными, отображенными на адресное пространство процесса. Это дейст-
    I вие выполняет функция UnmapViewOfFile. BOOL UnmapViewOfFile( LPCVOID ipBaseAddress);
    Эта функция имеет единственный параметр — IpBaseAddress, который является значением, возвращенным функцией MapViewOfFile. С помощью функции UnmapViewOfFile необходимо разрывать каждое из отображений, созданных последовательностью вызовов MapViewOfFile, сохраняя при этом их соответствия. Также имейте в виду, что если функция MapViewOfFile была вызвана с параметром FILEMAPCOPY, то после вызова UnmapViewOfFile теряются все внесенные в отображенные данные изменения.
  8. Далее нужно закрыть объект ядра проекция файла. В принципе, этот и сле-ivmmuu шяг нр яиляютг.я обязательными, так как система в процессе за-
    вершения работы приложения освободит все ресурсы. Освобождение
    объекта ядра проекция файла производится функцией CloseHandle.
    BOOL CloseHandle( HANDLE hObject):
    Функции CloseHandle передается единственный параметр hObject — де.
    скриптор, полученный как результат вызова функции CreateFileMapping.
  9. Требуется закрыть объект ядра файл. Освобождение объекта ядра файл также производится функцией CloseHandle.
    BOOL CloseHandle( HANDLE hObject );
    Функции CloseHandle передается единственный параметр hObject — дескриптор, полученный как результат вызова функции CreateFile.
    Пример программы (prg07_36.asm), демонстрирующей порядок использования файлов, отображаемых в адресное пространство процесса, достаточно велик и по этой причине вынесен на дискету. Работа программы проста и заключается в следующем: необходимо вывести содержимое некоторого файла на экран — в окно консоли. Имя исходного файла вводится с клавиатуры.