Шаг 228.
Явная (динамическая) загрузка модуля DLL

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

    В отличие от неявной (статической) загрузки модуля DLL, когда имена функций импортируемых функций и процедур, а также библиотека должны быть определены на этапе формирования исходного текста приложения и его компиляции, использование явной (динамической) загрузки позволяет задавать имя динамической библиотеки и имя функции непосредственно перед ее выполнением. Для явной загрузки модулей DLL необходимо загрузить модуль DLL в адресное пространство процесса, получить точку входа для нужной функции, выполнить внешнюю функцию и освободить память процесса от модуля. Для этого используются следующие процедуры и функции API Win32: LoadLibrary и LoadLibraryEx, GetProcAddress и FreeLibrary.

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

type
TCreateWord  = function:boolean;
TVisibleWord = function(kod:boolean):boolean;
TAddDoc = function(name:string):variant;
TFindAllAndPasteTextDoc = function(document:variant;
   findtext,pastetext:string):boolean;
TOpenDoc = function(filename:string):variant;
TCopyTextDocToClipboard = function(document:variant):boolean;
TImportTextFromDoc = function(document:variant):string;
TCloseDocEx = function(document:variant;saved:boolean):boolean;
TCloseWord = function:boolean;

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

var
  hdll:thandle;
  CreateWord_DLL2:TCreateWord;
  VisibleWord_DLL2:TVisibleWord;
  AddDoc_DLL2:TAddDoc;
  FindAllAndPasteTextDoc_DLL2:TFindAllAndPasteTextDoc;
  OpenDoc_DLL2:TOpenDoc;
  CopyTextDocToClipboard_DLL2:TCopyTextDocToClipboard;
  ImportTextFromDoc_DLL2:TImportTextFromDoc;
  CloseDocEx_DLL2:TCloseDocEx;
  CloseWord_DLL2:TCloseWord;

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

procedure TForm1.Button2Click(Sender: TObject);
//Загрузка модуля
begin
  hdll:=LoadLibrary('dserver.dll');
end;

    Переходим непосредственно к выполнению функций модуля, которые создадут и заполнят конверт на основе заготовленного шаблона.

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

procedure TForm1.Button1Click(Sender: TObject);
var
  document: variant;
begin
  //Определяем точки входа функций
  CreateWord_DLL2:=GetProcAddress(hdll, 'CreateWord');
  VisibleWord_DLL2:=GetProcAddress(hdll, 'VisibleWord');
  AddDoc_DLL2:=GetProcAddress(hdll, 'AddDoc');
  FindAllAndPasteTextDoc_DLL2:=GetProcAddress(hdll, 'FindAllAndPasteTextDoc');
  OpenDoc_DLL2:=GetProcAddress(hdll, 'OpenDoc');
  CopyTextDocToClipboard_DLL2:=GetProcAddress(hdll, 'CopyTextDocToClipboard');
  ImportTextFromDoc_DLL2:=GetProcAddress(hdll, 'ImportTextFromDoc');
  CloseDocEx_DLL2:=GetProcAddress(hdll, 'CloseDocEx');
  CloseWord_DLL2:=GetProcAddress(hdll, 'CloseWord');

  if Not CreateWord_DLL2 Then exit;
  VisibleWord_DLL2(True);
  // Создаем новый документ по шаблону
  document:=AddDoc_DLL2(ExtractFileDir(Application.ExeName)+
    '\Конверт.dot');
  MessageBox(handle,'Шаблон почтового конверта создан!',
     'Внимание!',0);
  // Подставляем адрес
  FindAllAndPasteTextDoc_DLL2(document,'###индекс&','350049');
  FindAllAndPasteTextDoc_DLL2(document,'###адрес&',
    'Краснодар, ул. Севастопольская, д. 3, кв. 123');
  FindAllAndPasteTextDoc_DLL2(document,'###Получатель&',
     'Иванов Иван Иванович');
  // Обратный адрес
  FindAllAndPasteTextDoc_DLL2(document, '###обратный индекс&',
   '198005');
  FindAllAndPasteTextDoc_DLL2(document,'###обратный адрес&',
   'Санкт-Петербург, Измайловский пр., д. 29, кв. 111');
  FindAllAndPasteTextDoc_DLL2(document,'###отправитель&',
    'Петрова Светлана Ивановна');
end;

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


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

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

procedure TForm1.Button3Click(Sender: TObject);
//Выгрузка модуля
begin
  FreeLibrary (hdll);
end;

    Приведем полный текст приложения.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
      { Private declarations }
  public
      { Public declarations }
  end;

var
  Form1: TForm1;

implementation

  {$R *.dfm}

uses MSWORD;

type
TCreateWord  = function:boolean;
TVisibleWord = function(kod:boolean):boolean;
TAddDoc = function(name:string):variant;
TFindAllAndPasteTextDoc = function(document:variant;
   findtext,pastetext:string):boolean;
TOpenDoc = function(filename:string):variant;
TCopyTextDocToClipboard = function(document:variant):boolean;
TImportTextFromDoc = function(document:variant):string;
TCloseDocEx = function(document:variant;saved:boolean):boolean;
TCloseWord = function:boolean;
var
  hdll:thandle;
  CreateWord_DLL2:TCreateWord;
  VisibleWord_DLL2:TVisibleWord;
  AddDoc_DLL2:TAddDoc;
  FindAllAndPasteTextDoc_DLL2:TFindAllAndPasteTextDoc;
  OpenDoc_DLL2:TOpenDoc;
  CopyTextDocToClipboard_DLL2:TCopyTextDocToClipboard;
  ImportTextFromDoc_DLL2:TImportTextFromDoc;
  CloseDocEx_DLL2:TCloseDocEx;
  CloseWord_DLL2:TCloseWord;


procedure TForm1.Button1Click(Sender: TObject);
var
  document: variant;
begin
  //Определяем точки входа функций
  CreateWord_DLL2:=GetProcAddress(hdll, 'CreateWord');
  VisibleWord_DLL2:=GetProcAddress(hdll, 'VisibleWord');
  AddDoc_DLL2:=GetProcAddress(hdll, 'AddDoc');
  FindAllAndPasteTextDoc_DLL2:=GetProcAddress(hdll, 'FindAllAndPasteTextDoc');
  OpenDoc_DLL2:=GetProcAddress(hdll, 'OpenDoc');
  CopyTextDocToClipboard_DLL2:=GetProcAddress(hdll, 'CopyTextDocToClipboard');
  ImportTextFromDoc_DLL2:=GetProcAddress(hdll, 'ImportTextFromDoc');
  CloseDocEx_DLL2:=GetProcAddress(hdll, 'CloseDocEx');
  CloseWord_DLL2:=GetProcAddress(hdll, 'CloseWord');

  if Not CreateWord_DLL2 Then exit;
  VisibleWord_DLL2(True);
  // Создаем новый документ по шаблону
  document:=AddDoc_DLL2(ExtractFileDir(Application.ExeName)+
    '\Конверт.dot');
  MessageBox(handle,'Шаблон почтового конверта создан!',
     'Внимание!',0);
  // Подставляем адрес
  FindAllAndPasteTextDoc_DLL2(document,'###индекс&','350049');
  FindAllAndPasteTextDoc_DLL2(document,'###адрес&',
    'Краснодар, ул. Севастопольская, д. 3, кв. 123');
  FindAllAndPasteTextDoc_DLL2(document,'###Получатель&',
     'Иванов Иван Иванович');
  // Обратный адрес
  FindAllAndPasteTextDoc_DLL2(document, '###обратный индекс&',
   '198005');
  FindAllAndPasteTextDoc_DLL2(document,'###обратный адрес&',
   'Санкт-Петербург, Измайловский пр., д. 29, кв. 111');
  FindAllAndPasteTextDoc_DLL2(document,'###отправитель&',
    'Петрова Светлана Ивановна');
end;

procedure TForm1.Button2Click(Sender: TObject);
//Загрузка модуля
begin
  hdll:=LoadLibrary('dserver.dll');
end;

procedure TForm1.Button3Click(Sender: TObject);
//Выгрузка модуля
begin
  FreeLibrary (hdll);
end;

end.
Текст этого приложения вместе с сопутствующими файлами можно взять здесь (54,9 Кб).

    На предыдущих шагах мы рассмотрели создание и использование DLL для работы с документами MS Word в приложениях Delphi. Справедливости ради стоит отметить, что и сами приложения MS Office могут работать с внешними динамическими модулями. Эта возможность очень заманчива и может дать большой положительный эффект при создании и использовании приложений на любом языке, позволяющем создавать динамические библиотеки. Следующие шаги будут посвящены рассмотрению этого вопроса.

    Со следующего шага мы начнем рассмотривать использование DLL в макросах MS Office.




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