Этап 3: проецирование файловых данных на адресное пространство процесса
Когда объект "проекция файла"создан, нужно, чтобы система, зарезервировав реги он адресного пространства под данные файла, передала их как физическую память, отображенную на регион. Это делает функция MapViewOfFile
PVOID MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap);
Параметр hFileMappingObject идентифицирует описатель объекта "проекция фай ла", возвращаемый предшествующим вызовом либо CreateFtleMapping, либо OpenFile Mapping (ее мы рассмотрим чуть позже) Параметр dwDesiredAccess идентифицирует вид доступа к данным Bce правильно придется опять указывать, как именно мы хо тим обращалься к файловым данным Можно задать одно из четырех значений, опи санных в следующей таблице
Значение |
Описание |
FILE_MAP_WRITE |
Файловые данные можно считывать и записывать, Вы должны были передать функции CreateFileMapping атрибут PAGE_READWRITE |
FILE MAF_READ |
Файловые данные можно только считывать Вы должны были вызвать CreateFileMapping с любым из следующих атрибутов PAGE_READONLY, PAGE_READWRITE или PAGE_WRITECOPY |
FILE_MAP_ALL_ACCESS |
То же, что и FILE_MAP_WRITE |
FILE_MAP_COPY |
Файловые данные можно считывать и записывать, но запись приводит к созданию закрытой копии страницы Вы должны были вызвать CrealeFileMapping с любым из следующих атрибу тов PAGE_READONIY, PAGE_READWRITE или РАСЕ_WRITECOPY (Windows 98 требует вызывать CreateFileMapping с атрибутом PACE_WRITECOPY) |
Кажется странным и немного раздражает, что Windows требует бесконечно ука зывать все эти атрибуты защиты Могу лишь предположить, что это сделано для того, чтобы приложение максимально полно контролировало защиту данных
Остальные три параметра относятся к резервированию региона адресного про странства и к отображению на него физической памяти При этом необязательно проецировать на адресное пространство весь файл сразу Напротив, можно спроеци ровать лишь малую его часть, которая в таком случае называется представлением (view) — теперь-то Вам, наверное, понятно, откуда произошло название функции MapViewOfFile
Проецируя на адресное пространство процесса представление файла, нужно сде лать двс вещи Во-первых, сообщить системе, какой байт файла данных считать в представлении первым Для этого предназначены параметры dwFileOffsetHigh и dwFile OffsetLow Поскольку Windows поддерживает файлы длиной до 16 экзабайтов, прихо дится определять смещение в файле как 64 разрядное число старшие 32 бита пере даются в параметре dwFileOffsetHigh, а младшие 32 бита — в параметре dwFileOffsetLow Заметьте, что смещение в файле должно быть кратно гранулярности выделения па мяти в данной системе (В настоящее время во всех реализациях Windows она состав ляет 64 Кб) О гранулярности выделения памяти см раздел "Системная информация" в ]лаве 14
Во-вторых, от Baс потребуется указать размер представления, т.e. сколько байтов файла данных должно быть спроецировано на адресное пространство Это равносиль но тому, как если бы Вы задали размер региона, резервируемого в адресном простран стве Размер указывается впараметре dwNumberOfBytesToMap Если этот параметр ра вен 0, система попытается спроецировать представление, начиная с указанного сме щения и до конца файла
WINDOWS 98
Windows 98, если MapViewOfFile не найдет регион, достаточно большой для размещения всего объекта «проекция файла», возвращается NULL — независи мо от того, какой размер представления был запрошен
WINDOWS 2000
B Windows 2000 функция MapViewOfFile ищет регион, достаточно большой для размещения запрошенного представления, не обращая внимания на размер самого объекта "проекция файла".
Если при вызове MapViewOfFile указан флаг FILE_MAP_COPY, система передает физическую память из страничного файла. Размер передаваемого пространства оп ределяется параметром dwNumberOfBytesToMap. Пока Вы лишь считываете данные из представления файла, страницы, переданные из страничного файла, пе используют ся, Но стоит какому-нибудь потоку в Вашем процессе совершить попытку записи по адресу, попадающему в границы представления файла, как система тут же берет из страничного файла одну из переданных страниц, копирует на нее исходные данные и проецирует ее на адресное пространство процесса. Так что с этого момента пото ки Вашего процесса начинают обращаться к локальной копии данных и теряют дос туп к исходным данным.
Создав копию исходной страницы, система меняет ее атрибут защиты с PAGE_WRI TECOPY на PAGE_READWRITE. Рассмотрим пример:
// открываем файл, который мы собираемся спроецировать
HANDLE hFile = CreaTeFile(pszFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// создаем для файла объект "проекция файла"
HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0, NULL);
// Проецируем представление файла с атрибутом "копирование при записи";
// система передаст столько физической памяти из сфаничного файла,
// сколько нужно для размещения всего файла. Первоначально все страницы
// в представлении получат атрибут PAGE_WRITECOPY.
PBYTE pbFile = (PBYTE) MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0, 0, 0);
// считываем байт из представления файла
BYTE bSomeByte = pbFile[0];
// при чтении система не трогает страницы, переданные из страничного файла;
// страница сохраняет свой атрибут PAGE_WRITECOPY
// записываем байт в представление файла
pbFile[0] = 0;
// При первой записи система берет страницу, переданную из страничного файла,
// копирует исходное содержимое страницы, расположенной по запрашиваемому адресу
// в памяти, и проецирует новую страницу (копию) на адресное пространство процесса.
// Новая страница получает атрибут PAGE_READWRITE.
// записываем еще один байт в представление файла
pbFile[1] = 0;
// поскольку теперь байт располагается на странице с атрибутом PAGE_RFADWRITE,
// система просто записывает его на эту страницу (она связана со страничным файлом)
// закончив работу с представлением проецируемого файла, прекращаем проецирование;
// функция UnmapViewOfFile обсуждается в следующем разделе
UnmapViewOfFile(pbFile);
// вся физическая память, взятая из страничного файпа, возвращается системе;
// все, что было записано на эти страницы, теряется
// "уходя, гасите свет"
CloseHandle(hFileMapping);
CloseHandle(hFile);
WINDOWS 98
Как уже упоминалось, Windows 98 сначала передаст проецируемому файлу физическую память из страничного файла Однако запись модифицированных страниц в страничный файл происходит только при необходимости.