Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
375
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

Последний параметр функции CreateFileMapping pszName — строка с нулевым байтом в конце; в ней указывается имя объекта "проекция файла", которое использу ется для доступа к данному объекту из другого процесса (пример см, в главе 3). Но обычно совместное использование проецируемого в память файла не требуется, и поэтому в данном параметре передают NULL.

Система создает объект «проекция файла» и возвращает его описатель в вызвав ший функцию поток. Если объект создать не удалось, возвращается нулевой описа тель (NULL). И здесь еще раз обратите внимание на отличительную особенность фун кции CreateFile — при ошибке она возвращает не NULL, а идентификатор INVALID_ HANDLE_VALlJE (определенный как - 1).

Этап 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 сначала передаст проецируемому файлу физическую память из страничного файла Однако запись модифицированных страниц в страничный файл происходит только при необходимости.

Этап 4: отключение файла данных от адресного пространства процесса

Когда необходимость в данных файла (спроецированного на регион адресного про странства процесса) отпадет, освободите регион вызовом:

BOOL UnmapViewOfFile(PVOID pvBaseAddress);

Ее единственный параметр, pvBaseAddress, указывает базовый адрес возвращаемо го системе региона. Он должен совпадать со значением, полученным после вызова MapViewOfFile. Вы обязаны вызывать функцию UnmapViewOfFile. Если Вы не сделаете

этoro, регион не освободится до завершения Вашего процесса. И еще: повторный вызов MapVietvOfFile приводит к резервированию нового региона в пределах адрес ного пространства процесса, но ранее выделенные регионы не освобождаются.

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

BOOL FlushViewOfFile( PVOID pvAddress, SIZE_T dwNuuiberOfBytesToFlush);

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

В случае проецируемых файлов, физическая память которых расположена на се тевом диске, FlushViewOfFile гарантирует, что файловые данные будут перекачаны с рабочей станции. Но она не гарантирует, что сервер, обеспечивающий доступ к это му файлу, запишет данные на удаленный диск, так как он может просто кэшировать их. Для подстраховки при создании объекта «проекция файла» и последующем про ецировании его представления используйте флаг FILE_FLAG_WRITE_THROUGH. При открытии файла с этим флагом функция FlushViewOfFile вернет управление только после сохранения на диске сервера всех файловых данных.

У функции UnmapViewOfFile есть одна особенность. Если первоначально представ ление было спроецировано с флагом FILE_MAP_COPY, любые изменения, внесенные Вами в файловые данные, на самом деле производятся над копией этих данных, хра нящихся в страничном файле. Вызванной в этом случае функции UnmapViewOfFile нечего обновлять в дисковом файле, и она просто инициирует возврат системе стра ниц физической памяти, выделенных из страничного файла. Все изменения в данных на этих страницах теряются.

Поэтому о сохранении измененных данных придется заботиться самостоятель но. Например, для уже спроецированного файла можно создать еще один объект «про

екция файла» с атрибутом PAGE_READWRITE и спроецировать его представление на адресное пространство процесса с флагом FILE_MAP_WRITE. Затем просмотреть пер вое представление, отыскивая страницы с атрибутом PAGE_READWRITE. Найдя стра ницу с таким атрибутом. Вы анализируете ее содержимое и решаете: записывать ее или нет Если обновлять файл не нужно, Вы продолжаете просмотр страниц. А для сохранения страницы с измененными данными достаточно вызвать MoveMemory и скопировать страницу из первого представления файля во второе. Поскольку второе представление создано с атрибутом PAGE_READWRITE, функция MoveMemory обновит содержимое дискового файла. Так что этот метод вполне пригоден для анализа изме нений и сохранения их в файле.

WINDOWS 98

Windows 98 нс поддерживает атрибут защиты «копирование при записи», по этому при просмотре первого представления файла, проецируемого в память, Вы не сможете проверить страницы по флагу PAGE_READWRITE Вам придется разработать свой метод.