Создание отображения файла
Рассмотрим процедуру создания отображения файла на память.
Прежде всего, приложение должно открыть файл при помощи функции CreateFile, известной вам из предыдущего тома “Библиоткеи системного программиста”. Ниже мы привели прототип этой функции:
HANDLE CreateFile(
LPCTSTR lpFileName, // адрес строки имени файла
DWORD dwDesiredAccess, // режим доступа
DWORD dwShareMode,// режим совместного использования файла
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // дескриптор
// защиты
DWORD dwCreationDistribution, // параметры создания
DWORD dwFlagsAndAttributes, // атрибуты файла
HANDLE hTemplateFile); // идентификатор файла с атрибутами
Через параметр lpFileName вы, как обычно, должны передать этой функции адрес текстовой строки, содержащей путь к открываемому файлу.
С помощью параметра dwDesiredAccess следует указать нужный вам вид доступа. Если файл будет открыт только для чтения, в этом параметре необходимо указать флаг GENERIC_READ. Если вы собираетесь выполнять над файлом операции чтения и записи, следует указать логическую комбинацию флагов GENERIC_READ и GENERIC_WRITE. В том случае, когда будет указан только флаг GENERIC_WRITE, операция чтения из файла будет запрещена.
Не забудьте также про параметр dwShareMode. Если файл будет использоваться одновременно несколькими процессами, через этот параметр необходимо передать режимы совместного использования файла: FILE_SHARE_READ или FILE_SHARE_WRITE.
Остальные параметры этой функции мы уже описали в предыдущем томе.
В случае успешного завершения, функция CreateFile возвращает идентификатор открытого файла. При ошибке возвращается значение INVALID_HANDLE_VALUE. Здесь все как обычно, пока никакого отображения еще не выполняется.
Для того чтобы создать отображение файла, вы должны вызвать функцию CreateFileMapping, прототип которой приведен ниже:
HANDLE CreateFileMapping(
HANDLE hFile, // идентификатор отображаемого файла
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // дескриптор
// защиты
DWORD flProtect, // защита для отображаемого файла
DWORD dwMaximumSizeHigh, // размер файла (старшее слово)
DWORD dwMaximumSizeLow, // размер файла (младшее слово)
LPCTSTR lpName); // имя отображенного файла
Через параметр hFile этой функции нужно передать идентификатор файла, для которого будет выполняться отображение в память, или значение 0xFFFFFFFF. В первом случае функция CreateFileMapping отобразит заданный файл в память, а во втором - создаст отображение с использованием файла виртуальной памяти. Как мы увидим позже, отображение с использованием файла виртуальной памяти удобно для организации передачи данных между процессами.
Обратим ваше внимание на одну потенциальную опасность, связанную с использованием в паре функций CreateFile и CreateFileMapping. Если функция CreateFile завершится с ошибкой и эта ошибка не будет обработана приложением, функция CreateFileMapping получит через параметр hFile значение INVALID_HANDLE_VALUE, численно равное 0xFFFFFFFF. В этом случае она сделает совсем не то, что предполагал разработчик приложения: вместо того чтобы выполнить отображение файла в память, функция создаст отображение с использованием файла виртуальной памяти.
Параметр lpFileMappingAttributes задает адрес дескриптора защиты. В большинстве случаев для этого параметра вы можете указать значение NULL.
Теперь займемся параметром flProtect, задающем защиту для создаваемого отображения файла. Для этого параметра вы можете задать следующий набор значений, комбинируя их с дополнительными атрибутами, которые будут перечислены ниже:
Значение |
Описание |
PAGE_READONLY |
К выделенной области памяти предоставляется доступ только для чтения. При создании или открывании файла необходимо указать флаг GENERIC_READ |
PAGE_READWRITE |
К выделенной области памяти предоставляется доступ для чтения и записи. При создании или открывании файла необходимо указать флаги GENERIC_READ и GENERIC_WRITE |
PAGE_WRITECOPY |
К выделенной области памяти предоставляется доступ для копирования при записи. При создании или открывании файла необходимо указать флаги GENERIC_READ и GENERIC_WRITE. Режим копирования при записи будет описан позже в главе, посвященной обмену данными между процессами |
Эти значения можно комбинировать при помощи логической операции ИЛИ со следующими атрибутами:
Атрибут |
Описание |
SEC_COMMIT |
Если указан этот атрибут, выполняется выделение физических страниц в памяти или в файле виртуальной памяти. Этот атрибут используется по умолчанию |
SEC_IMAGE |
Используется при отображении программного файла, содержащего исполнимый код. Этот атрибут несовместим с остальными перечисленными в этом списке атрибутами |
SEC_NOCACHE |
Отмена кэширования для всех страниц отображаемой области памяти. Должен использоваться вместе с атрибутами SEC_RESERVE или SEC_COMMIT |
SEC_RESERVE |
Если указан этот атрибут, вместо выделения выполняется резервирование страниц виртуальной памяти. Зарезервированные таким образом страницы можно будет получить в пользование при помощи функции VirtualAlloc. Атрибут SEC_RESERVE можно указывать только в том случае, если в качестве параметра hFile функции CreateFileMapping передается значение 0xFFFFFFFF |
Заметим, что вы можете указать нулевые значения и для параметра dwMaximumSizeHigh, и для параметра dwMaximumSizeLow. В этом случае предполагается, что размер файла изменяться не будет.
Через параметр lpName можно указать имя отображения, которое будет доступно всем работающим одновременно приложениям. Имя должно представлять собой текстовую строку, закрытую двоичным нулем и не содержащую символов “\”.
Если отображение будет использоваться только одним процессом, вы можете не задавать для него имя. В этом случае значение параметра lpName следует указать как NULL.
В случае успешного завершения функция CreateFileMapping возвращает идентификатор созданного отображения. При ошибке возвращается значение NULL.
Так как имя отображения глобально, возможно возникновение ситуации, когда процесс пытается создать отображение с уже существующим именем. В этом случае функция CreateFileMapping возвращает идентификатор существующего отображения. Такую ситуацию можно определить с помощью функции GetLastError, вызвав ее сразу после функции CreateFileMapping. Функция GetLastError при этом вернет значение ERROR_ALREADY_EXISTS.