Delphi: обмен данными между приложениями
Не менее мощным и гибким методом организации обмена данными между приложениями является метод, который базируется на проецируемых в память файлах (Files Mapping). Главная идея этого механизма основывается на использовании динамической разделяемой памяти системы для хранения в ней данных. Как известно, каждый процесс имеет свой участок памяти, называемый виртуальным адресным пространством. При использовании механизма проецируемых в память файлов данные становятся доступны из любого процесса, который использует этот файл. В этом случае говорят, что файл отображается в виртуальное адресное пространство процесса, поэтому данные, хранимые в файле, доступны процессу, который этот файл открыл. Механизм проецирования файлов в память используется, например, для исполняемых файлов приложений, а также для DLL.
Для работы с проецируемыми в память файлами существует целый ряд API-функций. Но прежде чем их рассматривать, разберемся в процессе организации обмена данными через проецируемые файлы. На первом этапе необходимо создать объект (файл, отображаемый в память), затем "отобразить" созданный объект в адресное пространство процесса приложения, получая возможность записи и чтения данных их этого файла. При отображении файла на определенный участок памяти (адресного пространства процесса) манипуляции с данными этого участка памяти отражаются на содержимом файла. После произведенных над объектом манипуляций необходимо закрыть доступ к данным файла (удалить проекцию и закрыть файл).
Рассмотрим некоторые функции для работы с проецируемым в память файлом. Для того чтобы создать объект файла, проецируемого в память, можно использовать функцию CreateFileMapping. Ее синтаксис выглядит следующим образом:
- hFile - должен содержать дескриптор открытого файла, для которого будет создаваться объект, отображающий этот файл в память процесса.
- lpFileMappingAttributes - указатель на структуру TSecurityAttributes. Если указателю присвоить nil, то атрибуты защиты устанавливаются по умолчанию.
- flProtect - содержит флаги, которые задают режимы доступа к виду файла в памяти процесса. Этот параметр может принимать одно из следующих значений:
- PAGE_READONLY — из вида файла можно только читать данные;
- PAGE_READWRITE — разрешает чтение и запись данных в вид файла;
- PAGE_WRITECOPY — разрешает чтение и запись данных в вид файла, но при записи создается новая копия вида файла.
В случае успешного завершения эта функция возвращает дескриптор объекта (THandle), отображающего файл в память, а в случае неудачи — 0.
После того как проецируемый файл был создан, необходимо отобразить его в адресное пространство процесса. Для этого предназначена функция MapViewOfFile, имеющая следующий синтаксис:
- hFileMappingObject - должен содержать дескриптор объекта, отображающего файл в память, который был предварительно создан функцией CreateFileMapping.
- dwDesiredAccess - задает режим доступа к виду файла и может принимать одно из следующих значений:
- FILE_MAP_WRITE - чтение и запись в вид файла;
- FILE_MAP_READ — только чтение из вида файла;
- FILE_MAP_ALL_ACCESS — чтение и запись в вид файла;
- FILE_MAP_COPY — при записи в вид файла создается его копия, а исходный файл не изменяется.
В случае успешного завершения функция возвращает указатель на вид файла в адресном пространстве процесса, а случае неудачи — nil. Параметры этой функции имеют следующее назначение.
Следующей функцией, противоположной по производимым действиям функции MapViewOfFile, является UnMapViewOfFile. Она отключает проецируемый файл от текущего процесса:
Функция принимает указатель, возвращаемый MapViewOfFile, и использует его для отмены проекции файла на адресное пространство процесса. В случае успешной выгрузки функция возвращает True, в противном случае — False.
И последняя функция, которую необходимо рассмотреть, — это CloseHandle. Она используется для закрытия дескриптора (многих системных объектов, а не только проекции файла).
Как видно из синтаксиса функции, она принимает описатель объекта файлового отображения, полученный в результате выполнения функции CreateFileMapping и освобождает его. Для правильного завершения работы с объектом файлового отображения сначала следует применить функцию UnMapViewOfFile, а затем CloseHandle.
Сама проекция файла будет удалена только после того, как будут закрыты все дескрипторы во всех использующих эту проекцию процессах.
Для демонстрации работы проецируемых в память файлов создадим приложение, которое будет записывать в такой файл строку и спустя некоторое время считывать ее оттуда. Для этого нам понадобится стандартный TextBox, кнопка, метка и таймер. Программа будет работать следующим образом: строка, записанная в поле редактора, после нажатия кнопки помещается в проецируемый файл. Далее, спустя некоторое время (задается таймером = 1 сек.), содержимое файла считывается и задается в качестве заголовка метки.
В секцию описания переменных программы помещаем следующие объявления:
Создание проецируемого файла, его отображение в адресное пространство процесса и копирование данных в проецируемый файл выполняется в момент щелчка по кнопке.
После того как будет нажата кнопка, данные помещаются в проецируемый файл. По истечении 1 секунды, заданного таймером, строка устанавливается в качестве текста метки Label2.
В момент завершения приложения необходимо отключить проецируемый файл от адресного пространства процесса и закрыть объект файла. Эти действия можно выполнять в момент уничтожения формы.
Используемая литература: Программирование в Delphi. Трюки и эффекты. Александр Чиртик