Главная » Delphi » Функция входа/выхода динамически компонуемых библиотек

0

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

Функции инициализации и завершения процессов и потоков

К типичным операциям инициализации относятся: регистрация классов  Windows, инициализация глобальных переменных и функции входа/выхода. Все указанные операции выполняются в методе входа в библиотеку DLL, который реализуется в виде функции DLLEntryPoint. На самом деле эта функция представлена блоком  be- gin..end файла  проекта DLL. Именно здесь целесообразно было бы поместить про цедуру обработки входа/выхода.  Такой  процедуре должен  передаваться один  пара метр типа DWord.

Глобальная переменная DLLProc представляет собой процедурный указатель, ко

торому  можно  присвоить адрес  процедуры входа/выхода.  Сначала  эта  переменная

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

Таблица 6.1. События входа/выхода библиотеки  DLL

Событие                                               Назначение

DLL_PROCESS_ATTACH  Библиотека  DLL  присоединяется  к  адресному   прост ранству  текущего  процесса при  запуске  процесса или  в результате вызова  функции LoadLibrary(). При  обра ботке  этого  события в библиотеке DLL инициализиру ются экземпляры всех типов данных

DLL_PROCESS_DETACH  Библиотека DLL отсоединяется от адресного пространст ва вызывающего процесса. Эта ситуация возникает в результате полного завершения процесса или при обра щении к функции FreeLibrary(). При  обработке этого события в библиотеке DLL могут быть удалены экземпля ры данных любых типов

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

Событие                                               Назначение

DLL_THREAD_DETACH Это  событие происходит,  когда  работа  потока  завер шается.  В процессе обработки такого  события в библи отеке DLL могут освобождаться любые инициализиро ванные данные  конкретного потокаНА ЗАМЕТКУ

В потоках, работа которых завершается ненормально (например, при вызове функции

TerminateThread()), передача события DLL_THREAD_DETACH не гарантируется.

Пример функции входа/выхода

Листинг 6.7 демонстрирует назначение переменной DLLProc процедуры входа/

выхода DLL.

Листинг 6.7. Исходный код файла DllEntry.dpr

library DLLEntryLib;

uses

SysUtils, Windows, Dialogs, Classes;

procedure DLLEntryPoint(dwReason: DWord);

begin

case dwReason of

DLL_PROCESS_ATTACH: ShowMessage(‘Attaching to process’);

DLL_PROCESS_DETACH: ShowMessage(‘Detaching from process’);

DLL_THREAD_ATTACH:        MessageBeep(0);

DLL_THREAD_DETACH:        MessageBeep(0);

end;

end;

begin

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

DllProc := @DLLEntryPoint;

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

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

DLLEntryPoint(DLL_PROCESS_ATTACH);

end.Процедура входа/выхода  назначается переменной DLLProc библиотеки DLL  в блоке   begin..end файла   проекта  самой   библиотеки.  Эта  процедура,  DLLEntry- Point(), проверяет значение параметра типа  word, чтобы  определить, какое  собы тие  явилось причиной ее вызова.  Возможные события перечислены в табл. 6.1. Для большей наглядности загрузка,  выгрузка  этой  библиотеки DLL, а также  каждое  собы тие в данном проекте будут сопровождаться выводом соответствующего окна сообще ния.  При  создании и удалении  потока в вызывающем приложении  одновременно  с сообщением будет подан звуковой сигнал.

Для иллюстрации использования этой  библиотеки DLL рассмотрим программный код, представленный в листинге 6.8.

Листинг 6.8. Пример кода процедуры входа/выхода библиотеки  DLL

unit MainFrm;

interface uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs, StdCtrls, ComCtrls, Gauges;

type

{ Определение потомка класса TThread } TTestThread = class(TThread)

procedure Execute; override;

procedure SetCaptionData;

end;

TMainForm = class(TForm) btnLoadLib: TButton; btnFreeLib: TButton; btnCreateThread: TButton; btnFreeThread: TButton; lblCount: TLabel;

procedure btnLoadLibClick(Sender: TObject); procedure btnFreeLibClick(Sender: TObject); procedure btnCreateThreadClick(Sender: TObject); procedure btnFreeThreadClick(Sender: TObject); procedure FormCreate(Sender: TObject);

private

LibHandle          : THandle;

TestThread         : TTestThread;

Counter            : Integer;

GoThread           : Boolean;

end;

var

MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TTestThread.Execute;

begin

while MainForm.GoThread do begin

Synchronize(SetCaptionData);Inc(MainForm.Counter);

end;

end;

procedure TTestThread.SetCaptionData;

begin

MainForm.lblCount.Caption := IntToStr(MainForm.Counter);

end;

procedure TMainForm.btnLoadLibClick(Sender: TObject);

{ Эта процедура загружает библиотеку DllEntryLib.DLL }

begin

if LibHandle = 0 then begin

LibHandle := LoadLibrary(‘DLLENTRYLIB.DLL’);

if LibHandle = 0 then

raise Exception.Create(‘Unable to Load DLL’);

end else

MessageDlg(‘Library already loaded’, mtWarning, [mbok], 0);

end;

procedure TMainForm.btnFreeLibClick(Sender: TObject);

{ Эта процедура освобождает библиотеку }

begin

if not (LibHandle = 0) then begin

FreeLibrary(LibHandle);

LibHandle := 0;

end;

end;

procedure TMainForm.btnCreateThreadClick(Sender: TObject);

{ Эта процедура создает экземпляр класса TThread. Если DLL

загружена, то будет подан звуковой сигнал. }

begin

if TestThread = nil then begin

GoThread          := True;

TestThread := TTestThread.Create(False);

end;

end;

procedure TMainForm.btnFreeThreadClick(Sender: TObject);

{ При освобождении экземпляра TThread будет подан звуковой сигнал,

если DLL загружена.}

begin

if not (TestThread = nil) then begin

GoThread          := False;

TestThread.Free;

TestThread := nil;

Counter           := 0;

end;

end;

procedure TMainForm.FormCreate(Sender: TObject);begin

LibHandle       := 0;

TestThread := nil;

end;

end.Данный проект состоит из главной формы с четырьмя кнопками (компонент TButton).  По   щелчку   на  кнопке  BtnLoadLib загружается  библиотека  DllEn- tryLib.dll. Кнопка BtnFreeLib предназначена для удаления  этой  библиотеки из процесса. С помощью кнопки BtnCreateThread создается объект, класс которого является производным от класса  TThread. Этот  объект используется для создания нового потока. По  щелчку  на  кнопке BtnFreeThread объект TThread удаляется. Метка lblCount используется только  для демонстрации работы потока.

Обработчик события btnLoadLibClick() вызывает функцию  LoadLibrary() для загрузки  библиотеки DllEntryLib.dll. В результате, данная  библиотека загру жается  и отображается в адресное пространство процесса. Кроме  того,  в библиотеке DLL выполняется подпрограмма инициализации, содержащаяся в блоке begin..end, которая запускает  процедуру  входа/выхода для этой библиотеки:

begin

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

DllProc := @DLLEntryPoint;

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

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

DLLEntryPoint(DLL_PROCESS_ATTACH);

end.

На протяжении всей работы процесса раздел  инициализации будет вызван  только один  раз.  Если другой  процесс загрузит  ту же самую библиотеку DLL, то этот  раздел будет вызван  снова,  но уже в контексте нового процесса, поскольку  процессы не ис пользуют экземпляры библиотек DLL совместно.

Обработчик события btnFreeLibClick() выгружает библиотеку DLL с помощью вызова  функции FreeLibrary(). В этом  случае вызывается процедура DLLEn- tryProc(), на которую  указывает переменная DLLProc; в качестве параметра ей пе редается значение DLL_PROCESS_DETACH.

Обработчик события btnCreateThreadClick() создает  объект, являющийся по томком  класса TThread. При  этом вызывается процедура DLLEntryProc() и ей в ка честве  параметра передается значение DLL_THREAD_ATTACH. Обработчик событий btnFreeThreadClick() вызывает ту же процедуру  DLLEntryProc(), но на этот  раз с параметром, равным DLL_THREAD_DETACH. Несмотря на то что  в данном  примере при  возникновении событий выводится всего  лишь  окно  сообщений, эти  события

можно  использовать для любых  операций инициализации либо  завершения любого процесса или потока, которые могут потребоваться в приложении. Ниже  рассматри вается  применение этого  метода  для установки совместно используемых глобальных данных  DLL. Приведенный выше  пример содержится в проекте DLLEntryTest.dpr на прилагаемом компакт диске (см. также www.williamspublishing.com).

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

По теме:

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