13.5. ВКЛЮЧЕНИЕ В БИБЛИОТЕКУ ФОРМ

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

В следующем примере иллюстрируется техника включения в DLL формы и использования ее в вызывающей программе.

Текст DLL

library DLLWithForm;

uses

SysUtils,

Classes,

DLLFormU in 'DLLFormU.pas' {DLLForm};

{$R *.RES}

exports

ShowModalForm, ShowForm, FreeForm;

begin

end.

Текст формы в DLL

unit DLLFormU;

interface

uses

Windows, Messages, SysUtils,Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls, Buttons;

type

TDLLForm = class (TForm) BitBtnl: TBitBtn;

BitBtn2: TBitBtn;

procedure FormClose(Sender: TObject;

var Action: TCloseAction);

private

{ Private declarations }

CallForm: THandle; //Дескриптор вызывающей формы

public

{ Public declarations }

end;

// Объявление экспортируемых подпрограмм

function ShowModalForm: Integer;

procedure ShowForm(aHandle: THandle);

procedure FreeForm;

var

DLLForm: TDLLForm;

implementation

{$R *.DFM}

function ShowModalForm: Integer;

// Модальный вызов

begin

DllForm := TDllForm.Create(Application);

Result := DLLForm.ShowModal;

DLLForm.Free;

end;

procedure ShowForm(Appl, Form: THandle);

// Немодальный вызов

begin

Application.Handle := Appl; // Замена объекта

Application DllForm := TDllForm.Create(Application);

// Запоминаем дескриптор вызывающего окна для посылки

// ему сообщения о закрытии

CallForm := Form;

DLLForm.Show

end;

procedure FreeForm;

// Уничтожение формы

begin

DLLForm.Free

end;

procedure TDLLForm.FormClose(Sender: TObject;

var Action: TCloseAction);

begin

if CallForm>O then

SendMessage(CallForm, wm_User, 0, 0)

end;

end.

Текст вызывающей программы

unit TestMainU;

interface

uses

Windows, Messages, SysUtils, Classes,

Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TTestMain = class (TForm)

Buttoni: TButton; // Открыть в модальном режиме

Button2: TButton; // Открыть в немодальном режиме

Button3: TButton; // Закрыть окно

Label I: TLabel;

procedure ButtonlClick(Sender: TObject);

procedure Button2Click(Sender: TObject);

procedure ButtonSClick(Sender: TObject);

private

{ Private declarations } public

{ Public declarations }

procedure WMUser(var Msg: TMessage);

message WM_USER;

end;

var

TestMain: TTestMain;

implementation

{$R *.DFM}

function ShowModalForm: Integer;

External 'DLLWithForm';

procedure ShowForm(Appl, Form: THandle);

External ' DLLWithForm' ;

procedure FreeForm;

External 'DLLWithForm';

procedure TTestMain.ButtonlClick(Sender: TObject);

// Модальный вызов

begin

Button2.Enabled := False;

label1.Caption := 'ModalResult = '+IntToStr(ShowModalForm);

label1.Show; // Показываем результат вызова

Button2.Enabled := True

end;

procedure TTestMain.Button2Click(Sender: TObject);

// Немодальный вызов

begin

Buttoni.Enabled :== False;

Button2.Enabled := False;

Buttons.Enabled := True; label 1.Hide;

ShowForm(Application.Handle, Self.Handle) ;

end;

procedure TTestMain.Button3Click(Sender: TObject);

// Закрыть форму

begin

FreeForm;

Button1.Enabled := True;

Button2.Enabled := True;

Button3.Enabled := False/end;

procedure TTestMain.WMUser(var Msg: TMessage) ;

// Сообщение из формы DLL о ее закрытии

begin

Buttons.Click

end;

end.

Модуль формы DLLForm, помещенной в DLL, ссылается на стандартный модуль Forms и таким образом получает свой глобальный объект Application, который ничего “не знает” о глобальном объекте вызывающей программы (см. гл. 21). В режиме модального вызова это не имеет особого значения, т. к. модальное окно блокирует работу вызывающей программы. В режиме немодального вызова следует синхронизовать действия объектов, в противном случае минимизация главного окна, например, не приведет к минимизации окна DLL. Синхронизация достигается тем, что дескриптор объекта Application DLL заменяется на соответствующий дескриптор вызывающей программы.

При показе формы в немодальном режиме она может быть закрыта щелчком по собственной системной кнопке закрыть. В этом случае она должна каким-то образом известить вызывающую программу об этом событии. Для этого используется стандартный механизм посылки вызывающей форме Windows-сообщения. Сообщение должно иметь адрес, в роли которого используется дескриптор окна, получающего это сообщение. Вот почему вторым параметром обращения к функции ShowForm в DLL передается и в поле CallForm: запоминается дескриптор вызывающего окна. Обработчик события enclose формы проверяет это поле и, если оно определено, посылает вызывающему окну сообщение с индексом wm_user. В вызывающей программе предусмотрен обработчик этого сообщения, в котором реализуются необходимые действия.