КОМПЬЮТЕРНЫЕ КУРСЫ "ПОИСК"
[Главная страница] [Delphi] [Контакты]
Не менее мощным и гибким методом организации обмена данными между приложениями является метод, который базируется на проецируемых в память файлах (Files Mapping). Главная идея этого механизма основывается на использовании динамической разделяемой памяти системы для хранения в ней данных. Как известно, каждый процесс имеет свой участок памяти, называемый виртуальным адресным пространством. При использовании механизма проецируемых в память файлов данные становятся доступны из любого процесса, который использует этот файл. В этом случае говорят, что файл отображается в виртуальное адресное пространство процесса, поэтому данные, хранимые в файле, доступны процессу, который этот файл открыл. Механизм проецирования файлов в память используется, например, для исполняемых файлов приложений, а также для DLL.
Для работы с проецируемыми в память файлами существует целый ряд API-функций. Но прежде чем их рассматривать, разберемся в процессе организации обмена данными через проецируемые файлы. На первом этапе необходимо создать объект (файл, отображаемый в память), затем "отобразить" созданный объект в адресное пространство процесса приложения, получая возможность записи и чтения данных их этого файла. При отображении файла на определенный участок памяти (адресного пространства процесса) манипуляции с данными этого участка памяти отражаются на содержимом файла. После произведенных над объектом манипуляций необходимо закрыть доступ к данным файла (удалить проекцию и закрыть файл).
Рассмотрим некоторые функции для работы с проецируемым в память файлом. Для того чтобы создать объект файла, проецируемого в память, можно использовать функцию CreateFileMapping. Ее синтаксис выглядит следующим образом:
function CreateFileMapping( hFile: THandle; // дескриптор файла lpFileMappingAttributes: PSecurityAttributes; // атрибуты защиты flProtect, // флаги доступа к файлу dwMaximumSizeHigh, // старшее двойное слово размера объекта dwMaximumSizeLow: DWORD; // младшее двойное слово размера объекта lpName: PWideChar // имя объекта отображения ): THandle; stdcall;
Параметры:
В случае успешного завершения эта функция возвращает дескриптор объекта (THandle), отображающего файл в память, а в случае неудачи — 0.
После того как проецируемый файл был создан, необходимо отобразить его в адресное пространство процесса. Для этого предназначена функция MapViewOfFile, имеющая следующий синтаксис:
function MapViewOfFile( hFileMappingObject: THandle; // дескриптор объекта, отображающего файл dwDesiredAccess: DWORD; // режим доступа dwFileOffsetHigh, // старшее двойное слово смещения dwFileOffsetLow, // младшее двойное слово смещения dwNumberOfBytesToMap: DWORD // количество отображаемых байт ): Pointer; stdcall;
Параметры:
В случае успешного завершения функция возвращает указатель на вид файла в адресном пространстве процесса, а случае неудачи — nil. Параметры этой функции имеют следующее назначение.
Следующей функцией, противоположной по производимым действиям функции MapViewOfFile, является UnMapViewOfFile. Она отключает проецируемый файл от текущего процесса:
function UnmapViewOfFile(lpBaseAddress: Pointer): BOOL; stdcall;
Функция принимает указатель, возвращаемый MapViewOfFile, и использует его для отмены проекции файла на адресное пространство процесса. В случае успешной выгрузки функция возвращает True, в противном случае — False.
И последняя функция, которую необходимо рассмотреть, — это CloseHandle. Она используется для закрытия дескриптора (многих системных объектов, а не только проекции файла).
function CloseHandle(hObject: THandle): BOOL; stdcall;
Как видно из синтаксиса функции, она принимает описатель объекта файлового отображения, полученный в результате выполнения функции CreateFileMapping и освобождает его. Для правильного завершения работы с объектом файлового отображения сначала следует применить функцию UnMapViewOfFile, а затем CloseHandle.
Сама проекция файла будет удалена только после того, как будут закрыты все дескрипторы во всех использующих эту проекцию процессах.
Для демонстрации работы проецируемых в память файлов создадим приложение, которое будет записывать в такой файл строку и спустя некоторое время считывать ее оттуда. Для этого нам понадобится стандартный TextBox, кнопка, метка и таймер. Программа будет работать следующим образом: строка, записанная в поле редактора, после нажатия кнопки помещается в проецируемый файл. Далее, спустя некоторое время (задается таймером = 1 сек.), содержимое файла считывается и задается в качестве заголовка метки.
В секцию описания переменных программы помещаем следующие объявления:
var Form1: TForm1; //Глобальные переменные //Описатель объекта проецируемого файла hFileMapMapObj: THandle; //Указатель на начальный адрес данных lpBaseAddress: PChar;
Создание проецируемого файла, его отображение в адресное пространство процесса и копирование данных в проецируемый файл выполняется в момент щелчка по кнопке.
procedure TForm1.Button1Click(Sender: TObject); begin //Создаем проецируемый файл с именем FileMemory //и передаем полученный в результате описатель //в глобальную пеменную hFileMapObj hFileMapMapObj := CreateFileMapping(MAXDWORD, nil, PAGE_READWRITE, 0, 4, 'FileMemory'); if hFileMapMapObj = 0 then ShowMessage('Не могу создать проецируемый файл') else //Подключаем файл к адресному пространству //и получаем начальный адрес данных lpBaseAddress := MapViewOfFile(hFileMapMapObj, FILE_MAP_WRITE, 0, 0, 0); if lpBaseAddress = nil then ShowMessage('Не могу подключить проецируемый файл!') else begin //Считываем данные в проецируемый файл StrPCopy(lpBaseAddress, Edit1.Text); //Через 2 секунды сработает таймер Timer1.Enabled := True; end; end;
После того как будет нажата кнопка, данные помещаются в проецируемый файл. По истечении 1 секунды, заданного таймером, строка устанавливается в качестве текста метки Label2.
procedure TForm1.Timer1Timer(Sender: TObject); begin Label2.Caption := PChar(lpBaseAddress); Label2.Color := clRed; Timer1.Enabled := False; end;
В момент завершения приложения необходимо отключить проецируемый файл от адресного пространства процесса и закрыть объект файла. Эти действия можно выполнять в момент уничтожения формы.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin //Отключим файл от адресного пространства UnmapViewOfFile(lpBaseAddress); //Освобождаем объект файла CloseHandle(hFileMapMapObj); //Закрываем форму Action := caFree; end;
Исходный код проекта (Delphi XE)
Используемая литература: Программирование в Delphi. Трюки и эффекты. Александр Чиртик