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. В вызывающей программе предусмотрен обработчик этого сообщения, в котором реализуются необходимые действия.