Создание DLL-библиотеки для работы с Word/Excel из приложений на Delphi

Если вы хотите и готовы предложить своим коллегам свои собственные API-функции для работы с документами Word и Excel, то эта статья вам очень пригодится.
Весь набор функций, который рассмотрен в статьях №1 и №2, можно реализовать в виде DLL-библиотеки. Реализация в виде DLL дает большие преимущества программисту в гибкости, надежности использования своих программных продуктов и сокращает время на разработку программного обеспечения. В своих библиотеках вы можете заложить базовые функции, которые не будут изменяться довольно часто, при этом основное приложение, которое использует библиотеки, может меняться достаточно часто и совершенствоваться от версии к версии. Функции, оформленные в виде DLL, называются иначе - API-функциями. Система Windows использует как системные, так и пользовательские функции API.
Если вы решите создавать библиотеку для работы с Word.Application (Excel.Application), то столкнетесь с некоторыми особенностями, которые укладываются в общее представление о создании динамических библиотек. Эти особенности связаны с преобразованием формата данных, передаваемых через механизм DDE.
Приступим к созданию нашей библиотеки (назовем ее MyLWord). Выполним команду меню "File" -> "New..." . В открывшемся окне выберите закладку "New" и далее пиктограмму "DLL", нажмите кнопку "OK". Получим новый проект. Его название изменим на MyLWord и сохраним под тем же именем. Используем нашу библиотеку MyWord, которая была создана ранее (см. "Суперфункции 1.5"). Изменим эту библиотеку, дописав в конец объявления каждой процедуры в секции interface ключевое слово StdCall, которое определяет соглашение о передаче параметров через стек. В файле проекта MyLWord.dpr в секцию подключения внешних модулей uses допишем ссылку на библиотеку MyWord. После секции uses создадим секцию экспортируемых процедур и функций, напишем ключевое слово exports, после которого через запятую перечислим список всех экспортируемых процедур и функций. Если откомпилировать этот проект, то получим файл динамической библиотеки MyLWord.dll. Ниже представлены фрагменты перечисленных выше файлов.
Файл - MyLWord.dpr
library MyLWord;
uses
 SysUtils,
 Classes,
 MyWord;
{$R *.RES}
exports
 CreateWord,
 VisibleWord,
 {................,}
 GetNameIndexShape;
begin
{ Секция инициализации модуля, можно вставлять функции,
 которые должны выполняться при загрузке модуля, например
 начальная загрузка данных, которые будут использоваться
 всеми функциями и процедурами модуля. }
end.
Файл - MyWord.pas
unit MyWord;
interface
 const
 wdBorderTop = -1;
 {......................}
 wdLineStyleEngrave3D = 22;
function CreateWord: Boolean; StdCall
function VisibleWord(Visible: Boolean): Boolean; StdCall
{.........................................}
function SetNewNameShape(NameShape: Variant;
 NewNameShape: string): string; StdCall
function GetNameIndexShape(NameIndex: Variant): string; StdCall
var W:variant;
implementation
uses ComObj;
function CreateWord: Boolean;
begin
 Result := True;
 try
 W := CreateOleObject('Word.Application');
 {.........................................}
function DeleteShape(NameShape: Variant): Variant;
begin
 Result := True;
 try
 W.ActiveDocument.Shapes.Item(NameShape).Delete;
 except
 Result := False;
 end;
end;
end.
После создания динамической библиотеки процедур и функций рассмотрим ее использование. Для этого возьмем пример, описанный в предыдущих статьях "Суперфункции". Любую динамическую библиотеку можно использовать двумя основными способами: загрузка библиотеки при старте EXE-модуля и динамическая загрузка, которая выполняется в местах программы, там, где это необходимо. Преимущество первого метода заключается в простоте написания кода, второго - в гибкости, например, в зависимости от каких-либо условий программы можно загружать различные модули, содержащие одинаковые функции. Если используется первый вариант, то при отсутствии модуля DLL программа просто не загрузится, при втором варианте программа загрузится, но в местах вызова модуля будет сгенерирована ошибка, которую можно обработать.
Рассмотрим подробнее вариант загрузки модуля DLL при старте программы, которая его использует. Если вы хотите использовать какую-либо функцию динамической библиотеки, то достаточно в модуле, где будет использоваться функция, добавить строку объявления такого типа:
 function (procedure) <Имя функции (процедуры)>(<список переменных и типов>): <возвращаемое значение>; external '<Имя файла библиотеки с расширением>' name ' Имя функции или процедуры ';
Конкретные примеры:
function CreateWord: Boolean;
 external 'MyLWord.dll' name 'CreateWord';
function VisibleWord(Visible: Boolean): Boolean;
 external 'MyLWord.dll' name 'VisibleWord';
{.........................}
begin
 {.....................}
 if CreateWord then VisibleWord(true);
 {.....................}
end.
Для объявления функций и процедур динамической библиотеки удобно использовать отдельный модуль Unit. В таком модуле в секции interface перечисляются функции и процедуры с указанием имен, параметров и типов возвращаемых значений как в обычном модуле, в секции implementation они описываются с указанием на модули (имена файлов) DLL и оригинальные имена. Например:
unit MyDWord;
interface
function CreateWord: Boolean; StdCall
function VisibleWord(Visible: Boolean): Boolean; StdCall
{.........................................}
implementation
function CreateWord: Boolean;
 external 'MyLWord.dll' name 'CreateWord';
function VisibleWord(Visible: Boolean): Boolean;
 external 'MyLWord.dll' name 'VisibleWord';
{.........................................}
end.
Чтобы использовать данный модуль в приложении, достаточно указать на него ссылку в секции uses. Рассмотрим пример:
uses MyDWord;
{.........................................}
begin
 // Выполним загрузку Word'а, вызвав необходимые функции.
 if CreateWord then VisibleWord(True);
end;
Рассмотрим динамическое выполнение процедур и функций модуля DLL. Для динамической загрузки и выполнения необходимо определить типы вызываемых процедур (функций), загрузить библиотеку DLL, получить адреса входа в процедуру (функцию), выполнить процедуру (функцию) и выгрузить библиотеку.
Для этого рассмотрим следующий пример:
{ Выполним загрузку и отображение Word'а, используя
 функции CreateWord и VisibleWord. В секции type
 определим их типы, они должны совпадать с оригиналом
 в модуле DLL. }
type
 TCreateWord = function: Boolean;
 TVisibleWord = function (Visible: Boolean): Boolean;
{ В разделе описания переменных определим переменную
 hdll:thandle, через которую будем обращаться к функциям
 работы с библиотекой, и переменные - ссылки на процедуры
 динамической библиотеки. }
var
 hDll: THandle;
 CreateWord: TCreateWord;
 VisibleWord: TVisibleWord;
begin
 // В секции кода выполним загрузку модуля (библиотеки) и получим ее handle.
 hDll := LoadLibrary('MyLWord.dll');
 // Получим точки входа в функции.
 CreateWord := GetProcAddress(hDll, 'CreateWord');
 VisibleWord := GetProcAddress(hDll, 'VisibleWord');
 // Выполним загрузку Word'а, вызвав необходимые функции.
 if CreateWord then VisibleWord(True);
 // Выгрузим библиотеку (очистим память от библиотеки).
 FreeLibrary(hDll);
end;
Как видно, динамическая загрузка библиотеки немного сложнее, но, несмотря на это, она оправдывает себя. Используя данный материал, вы сможете создать и использовать свою персональную динамическую библиотеку для работы с редакторами Word и Excel. Полные исходные тексты с примерами смотрите по адресу www.kornjakov.ru/st3_1.zip. По всем вопросам можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.
Литература: Марко Кенту "Delphi 6 " "Питер" 2002.
== См. также ==
* Суперфункции MS Word and MS Excel (статья)
* Суперфункции EXCEL.
* Настройки листа и печать в MS Excel
* Диаграммы Excel
* Создание DLL-библиотеки для работы с Word/Excel из приложений на Delphi
* Суперфункции:FAQ
Author: Василий КОРНЯКОВ
Source: http://www.kornjakov.ru
Category:COM
Category:MS Office