Шаг 313.
Создание внутрипроцессных серверов автоматизации. Создание и использование DLL. Немодальные формы в DLL (продолжение)

    На этом шаге мы рассмотрим загрузку немодальных форм из динамически подключаемых библиотек.

    Однако иногда возникает необходимость отображения немодальных форм из динамически загружаемых библиотек - например, при редком использовании в приложении немодальных форм для экономии ресурсов. Если реализовать код таким же образом, как и при показе модальных диалоговых окон, то форма будет создана и, может быть, даже показана на экране. Но после этого произойдет выгрузка DLL, и вслед за этим немедленно последуют исключения, так как в памяти компьютера будет отсутствовать код для работы с элементами управления формы. Традиционное решение этой проблемы выглядит следующим образом: библиотека загружается динамически, и в качестве одного из параметров ей передается адрес функции главного приложения, которая будет вызвана при закрытии немодальной формы - обычно в обработчике события OnDestroy. Эта функция должна информировать главное приложение о необходимости выгрузки DLL из памяти компьютера, но библиотека должна выгружаться после завершения ее работы (и, следовательно, после завершения работы деструктора формы) - иначе возможно возникновение исключения из-за отсутствия кода в памяти компьютера. Это достигается путем асинхронной развязки - посылки сообщения с помощью функции PostMessage какому-либо окну приложения, обычно главной форме. Код реализации данного способа отображения немодальных форм в DLL выглядит следующим образом (приведем полный текст модуля формы, находящейся в DLL):

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TNotifyClose = procedure; stdcall;

type
  TForm2 = class(TForm)
    Label1: TLabel;
    procedure FormDestroy(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
    FNC: TNotifyClose;
  end;

var
  Form2: TForm2;

procedure DynNonmodal(AppHandle:THandle; NC: Pointer); stdcall;

implementation

{$R *.dfm}


procedure TForm2.FormDestroy(Sender: TObject);
begin
  if Assigned(FNC) then FNC;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure DynNonmodal(AppHandle:THandle; NC: Pointer); stdcall;
begin
  Application.Handle:=AppHandle;
  if Assigned(Form2) then
    Form2.Show
  else begin
    Form2:=TForm2.Create(Application);
    Form2.FNC:= TNotifyClose(NC);
    Form2.Show;
  end;
end;

end.

    Приложение, использующее эту библиотеку, имеет следующий код (приведем полный текст приложения):

unit Unit_pr;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  WM_DLLUNLOAD = WM_USER+1;

type
  TDynNonmodal=procedure(AppHandle: THandle; NC: Pointer); stdcall;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    procedure WMDLLUnload(var Message:TMessage);
    MESSAGE WM_DLLUNLOAD; {метод обработки сообщения}
   { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  FHLib: THandle;

procedure ReceiveCloseNotify; stdcall;
begin
 Application.ProcessMessages;
 PostMessage(Form1.Handle, WM_DLLUNLOAD, 0, 0);
end;

procedure TForm1.WMDLLUnload(var Message: TMessage);
begin
  Application.ProcessMessages;
  if FHLib <> 0 then FreeLibrary(FHLib);
  FHLib := 0;
  ShowMessage('Библиотека выгружена');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  DM: TDynNonmodal;
begin
  if FHLib = 0 then
    FHLib := LoadLibrary('FirstLib.dll');
  if FHLib > 0 then
    begin
      DM := GetProcAddress(FHLib, 'DynNonmodal');
      if Assigned(DM) then
        DM(Application.Handle, @ReceiveCloseNotify);
    end;
end;

end.
Текст этого приложения вместе с DLL можно взять здесь (448,2 Кб).

    Результат работы приложения изображен на рисунке 1:


Рис.1. Результат работы приложения

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг