Главная » Delphi » Создание DLL с совместно используемой памятью

0

В листинге 6.12 содержится исходный код файла  проекта библиотеки DLL, позво ляющей  приложениям, обращающимся к ее функциям, совместно использовать гло бальные данные.  Эти глобальные данные  хранятся в переменной под именем GlobalData.

Листинг 6.12. ShareLib — совместное использование глобальных данных

library ShareLib;

uses

ShareMem, Windows, SysUtils, Classes;

const

cMMFileName: PChar = ‘SharedMapData';

{$I DLLDATA.INC}

var

GlobalData : PGlobalDLLData;

MapHandle       : THandle;

{ GetDLLData – экспортируемая функция DLL }

procedure GetDLLData(var AGlobalData: PGlobalDLLData); StdCall;

begin{ Указатель AGlobalData указывает на тот же адрес памяти, на который ссылается и указатель GlobalData.}

AGlobalData := GlobalData;

end;

procedure OpenSharedData;

var

Size: Integer;

begin

{ Определение размера отображаемых данных. }

Size := SizeOf(TGlobalDLLData);

{ Теперь получаем объект отображенного в память файла. Обратите внимание: первый параметр передает значение $FFFFFFFF, или Dword (-

1), чтобы пространство выделялось из системного файла подкачки. Необходимо, чтобы имя отображенного в память объекта передавалось в качестве последнего параметра. }

MapHandle := CreateFileMapping(DWord(-1), nil, PAGE_READWRITE,

0, Size, cMMFileName);

if MapHandle = 0 then

RaiseLastWin32Error;

{ Отображение данных в адресное пространство вызывающего

процесса и получение указателя на начало этого адреса. }

GlobalData := MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS,

0, 0, Size);

{ Инициализация этих данных }

GlobalData^.S := ‘ShareLib';

GlobalData^.I := 1;

if GlobalData = nil then begin

CloseHandle(MapHandle);

RaiseLastWin32Error;

end;

end;

procedure CloseSharedData;

{ Эта процедура закрывает отображенный в память файл и освобождает

его дескриптор. }

begin

UnmapViewOfFile(GlobalData);

CloseHandle(MapHandle);

end;

procedure DLLEntryPoint(dwReason: DWord);

begin

case dwReason of

DLL_PROCESS_ATTACH: OpenSharedData;

DLL_PROCESS_DETACH: CloseSharedData;

end;

end;

exportsGetDLLData;

begin

{ Сначала назначить процедуру переменной DLLProc }

DllProc := @DLLEntryPoint;

{ Теперь вызвать процедуру, чтобы продемонстрировать факт

присоединения DLL к процессу. }

DLLEntryPoint(DLL_PROCESS_ATTACH);

end.Переменная GlobalData имеет  тип  PGlobalDLLData, который определен в под ключаемом файле (include file) DllData.inc. Этот  файл  содержит следующее  опреде ление  типа  (обратите внимание: подключение файла  осуществляется с помощью ди рективы подключения $I):

type

PGlobalDLLData = ^TGlobalDLLData; TGlobalDLLData = record

S: String[50]; I: Integer;

end;

В этой  библиотеке DLL используется тот  же процесс, который рассматривался в настоящей главе выше при обсуждении добавления кода инициализации/завершения библиотеки DLL в виде процедуры входа/выхода.  Упомянутая процедура называется DLLEntryPoint(), как показано в листинге. Когда процесс загружает эту DLL, вызы вается   метод   OpenSharedData(),  а  когда  процесс  отгружает ее —   метод   Close- SharedData().

Файлы, отображенные в память, позволяют резервировать некоторую область ад

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

Для работы с отображенным в память  файлом необходимо сначала  получить де скриптор существующего  на диске файла, для которого будет создан  объект ото бражения в память.  Затем  этот  объект связывается с указанным  файлом. Ранее  в на стоящей главе обсуждалось, как система позволяет нескольким приложениям со вместно использовать библиотеки DLL. Вначале  библиотека загружается в память, а затем   каждому  приложению  предоставляется  его  собственный  образ   этой   DLL. В результате создается впечатление, что  каждое  приложение загрузило отдельный экземпляр библиотеки. Но  в действительности в памяти находится только  один  эк земпляр файла  DLL. Эффект множественности достигается за счет  использования механизма отображенных файлов в память.  Тот  же процесс можно  использовать и для предоставления доступа к файлам данных.  Для этого  достаточно вызвать необ ходимые функции API Win32,  которые обеспечивают создание и доступ к файлам, отображенным в память.Теперь рассмотрим следующий  сценарий. Предположим, что  некоторое приложе ние  (назовем его App1) создает  отображенный в память  файл,  который связывается с дисковым файлом MyFile.dat. Приложение App1 может  теперь считывать и записы вать данные в этот  файл.  Если во время  работы приложения App1 другое приложение, App2, также  будет выполнять отображение в тот  же  файл,  то  изменения, внесенные App1, будут видны  App2. На самом деле все обстоит несколько сложнее: для немедлен ного  переноса на диск  внесенных в файл  изменений необходимо установить  опреде ленные флаги, а также  выполнить некоторую другую подготовительную работу.  Но  в данный момент все эти подробности не имеют  значения. Достаточно сказать, что изме нения будут восприняты обоими приложениями, поскольку такое возможно.

Одним  из вариантов использования отображенных в память  файлов является созда ние  механизма отображения файлов на основе файла  подкачки (страничного обмена) Win32,  а не обычного файла  данных.  Это означает, что  вместо  отображения в память файла, реально существующего  на диске, есть возможность зарезервировать некоторую область  памяти, куда затем  можно  ссылаться как на дисковый файл.  Подобный подход избавит от необходимости создания и уничтожения временного файла, если необходи мо всего  лишь  создать  некоторое адресное пространство, доступное нескольким про цессам.  Система  Win32 автоматически управляет своим  файлом подкачки, поэтому,  ко гда память больше не требуется, она освобождается системой.

Выше был предложен сценарий, иллюстрирующий, как два приложения могут по лучить доступ к одним и тем же файловым данным  с помощью файла, отображенного в память.  Тот  же сценарий подходит и для совместного использования данных  при ложений и DLL. Действительно, если  библиотека DLL, загружаемая некоторым при ложением, создает  отображенный в память  файл,  то после  загрузки  этой  библиотеки другим приложением она будет продолжать использовать все тот же отображенный в память  файл.  При этом будут существовать два образа библиотеки DLL (по одному для каждого  вызывающего приложения), использующих один  и тот же экземпляр файла, отображенного в память.  Функции  библиотеки DLL могут обеспечить доступ  к дан ным отображенного в память  файла  любому вызывающему их приложению. Когда од но приложение внесет  в эти  данные изменения, они  будут видны  другому приложе нию,  поскольку  оба  приложения обращаются к одним  и тем  же данным, но  отобра женным в память  двумя различными экземплярами библиотеки. Описанный метод используется в примере, представленном в листинге 6.12.

В этом примере создание отображенного в память  файла  возложено на процедуру OpenSharedData(). Для создания исходного объекта отображения файла  в ней  ис пользуется функция CreateFileMapping(), которая передает созданный объект функции  MapViewOfFile(). Эта  функция отображает образ  файла  в адресное про странство вызывающего процесса и возвращает адрес начала  выделенного адресного пространства. Теперь вспомним, что  это адресное пространство принадлежит вызы вающему процессу.  Для двух различных приложений, использующих данную библио теку DLL, эти пространства адресов могут быть различными, несмотря на то, что дан ные, на которые они ссылаются, одни и те же.НА ЗАМЕТКУ

Первым параметром, передаваемым функции CreateFileMapping(), является деск- риптор отображаемого в память файла. Но если отображение выполняется для ад- ресного   пространства   системного   файла   подкачки,   то   передается   значение

$FFFFFFFF, что равносильно значению DWord (-1) — как в данном примере. В качест- ве второго параметра функции CreateFileMapping() нужно передать имя объекта отображения файла в память. Это имя система будет использовать для ссылки на со- ответствующее файловое отображение. Если несколько процессов одновременно соз- дадут отображение в память одноименного файла, то объекты отображения будут ссылаться на одну и ту же область системной памяти.

После  обращения к функции MapViewOfFile() переменная GlobalData будет указывать на адресное пространство файла, отображенного в память.  В результате выполнения экспортируемой функции GetDLLData() параметр AGlobalData будет указывать на ту же область  памяти, что и указатель  GlobalData. Параметр AGlobalData передается из вызывающего приложения, следовательно, вызывающее приложение получит возможность считывать и записывать общие данные.

Процедура CloseSharedData() закрывает отображение общего  файла  для  дан ного  вызывающего процесса и освобождает его объект отображения файла. Это  ни как не влияет на другие объекты отображения файла  и на отображение глобального файла  со стороны других приложений.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии