Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Автоматизация документов WORD

Оформил: DeeCo

Автор: Клименко Константин

1. Для чего и для кого

В настоящий момент везде, или почти везде, для работы с текстовыми документами используется Word от Microsoft. Причем, когда читаешь в объявлениях о приеме на работу программиста в фирму не занимающейся разработкой ПО, то с уверенностью можно сказать, что необходим человек, умеющий работать с офисным пакетом (Word, Excel, Access) от вышеупомянутой фирмы. Поэтому данным материалом хотелось бы показать, как можно в некоторых случаях упростить работу с текстовым редактором Word. Для этого не обязательны знания Delphi на профессиональном уровне, достаточно уметь создавать динамически подключаемые библиотеки (DLL) и знать основы VBA для Word. К тому же макроязыки используются не только в пакете от Microsoft, слышал, что аналог VBA есть и в StarOffice.

2. Как подключить DLL в VBA

Любая программа может вызвать функцию из DLL, которая написана на Delphi, независимо от того, написана она на Си, Visual Basic или VBA. Первый вопрос, который может волновать - как это сделать в VBA для Word?
Для вызова DLL в VBA для Word существует специальная функция:
[Public | Private]Declarefunction name Lib "libname"[Alias
  "aliasname"][([arglist])][as type]
Описание функции:
Public и Private
- разрешение на использование вызываемой функции в других процедурах и модулях и использование только в данном модуле.
  • name - имя вызываемой функции.
  • libname - имя библиотеки.
Alias
псевдоним, необходим, когда используются недопустимые символы или существует переменная, название которой совпадает с названием функции
  • arglist - список передаваемых в функцию переменных
As type
тип функции
Если необходимо вызвать процедуру, то вместо Function указывается Sub, и соответственно опускается As type.
Например:
Declarefunction MyTest Lib "PrjWTest"(ByVal Ns as Byte) as string

Sub WordTest()
Dim S1, S2 as string
S1 = MyTest(1)
end Sub
Вызываем функцию MyTest из библиотеки PrjWTest.dll. Функции предаем значение переменной NS, имеющей тип Byte. Функция возвращает строку.
Желательно в VBA создать функцию для вызова DLL. В нашем примере это функция WordTest , которая вызывается MACROBUTTON-ом ({ MACROBUTTON WordTest Кликни здесь }(Вставка => Поле => Автоматизация документа)).

3. Как в Delphi создать DLL

Ответ на этот вопрос можно найти во многих справочниках и учебниках по Delphi. Я лишь приведу исходный текст библиотеки.
На форме находятся следующие компоненты: Edit1 и Button1, причем Button1.ModalResult = mrOk. Листинг библиотеки (PrjWTest.dpr):
library PrjWTest;

uses
  Windows,
  Messages,
  SysUtils,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  UnitWTest in 'UnitWTest.pas' {FormWTest};

var
  //Это наша форма
  MyForm: TFormWTest;

  {*********************Test************************************}

function Test: PChar; export; stdcall;
var
  TmpStr: string;
begin
  TmpStr := '';
  //Вызываем форму
  if MyForm.ShowModal = mrOk then
  begin
    //Считываем текст с Edit
    TmpStr := MyForm.Edit1.Text;
  end;
  //Желательно указать конец строки
  TmpStr := TmpStr + #0;
  //Возвращаем текст
  Test := PChar(TmpStr);
end;

{*********************MyTest************************************
Данную функцию вызываем из Word}

function MyTest(N: Byte): PChar; export; stdcall;
begin
  //Посылаем в Edit число, полученное из Word
  MyForm.Edit1.Text := IntToStr(N);
  //Вызываем вспомогательную функцию
  MyTest := Test;
end;

{*********************MyTest************************************
Создаем форму}

procedure CreateForm; export; stdcall;
begin
  MyForm := TFormWTest.Create(Application);
end;

{*********************MyTest************************************
Освобождаем форму}

procedure FreeForm; export; stdcall;
begin
  MyForm.Free;
end;

exports
  CreateForm Index 1,
  MyTest Index 2,
  FreeForm Index 3;

//{$R *.RES}
begin
  {  Application.Initialize;
    Application.CreateForm(TFormGsk, FormGsk);
    Application.CreateForm(TDataModule2, DataModule2);
    Application.CreateForm(TFormListBoxs, FormListBoxs);
    Application.CreateForm(TFormCreateSk, FormCreateSk);
    Application.CreateForm(TFormAddKontr, FormAddKontr);
    Application.Run;}
end.
При вызове функции MyTest вызывается наша форма, в Edit помещается переданное число, функция возвращает текст из Edit. Полученную DLL желательно поместить в папку Windows.

4. Проблемы, возникающие при передаче данных.

В данной части хотелось бы обратить внимание на некоторые особенности передачи данных из Delphi в VBA.
Во-первых, если передаете текст, то тип передаваемой функции должен быть Pchar, т.к. VBA не понимает типа String.
Во-вторых, VBA все равно при выводе текста в документ выдаст ерунду. Поэтому ниже привожу листинг функции, преобразующей полученный текст в "нормальный".
//Приводим полученный текст в "нормальный" текстовый вид

function StrToStr(St as string) as string
  Dim EndStr as Long
  //Определяем количество символов до конца строки
  EndStr = InStr(1, St, Chr$(0))
  if EndStr <>
0 then
  //Вырезаем и возвращаем нужную информацию
    StrToStr = Left(St, EndStr - 1)
else
  StrToStr = ""
end if


endfunction
В-третьих, лучше создавать и освобождать формы отдельными функциями, особенно это видно при работе с базами.
//Подключаемые функции в DLL
Declare Sub CreateForm Lib "PrjWTest"()

Declarefunction MyTest Lib "PrjWTest"(ByVal Ns as Byte) as string
  Declare Sub FreeForm Lib "PrjWTest"()
5. Как вставлять текст в Word.

Это тоже можно найти в справочниках и учебниках по VBA. Но все же приведу несколько советов по этому вопросу.
Если строку необходимо вставить в определенное место в тексте, то делаем закладку: Вставка=>Закладка в меню Word. Но лучше использовать две закладки: начало текста и конец. Это может понадобиться в случае замены старого текста на новый (обновление данных). Далее листинг этих функций:
//Переходим к метке Label
Sub GotoBookMark(label as string)
Selection.goto What := wdGoToBookmark, Name := label
  with ActiveDocument.Bookmarks
    .DefaultSorting = wdSortByName
    .ShowHidden = False
end with
end Sub

//Вставляет текст NK между закладками BeginBookM и EndBookM
Sub NewTxt(BeginBookM as string, EndBookM as string, NK as string)
//Переходим к первой закладке
GotoBookMark(BeginBookM)
//Выделяем старый текст между закладками
Selection.Extend
//Переходим к второй закладке
GotoBookMark(EndBookM)
//Отступаем чтобы не захватить закладку
Selection.MoveLeft unit := wdCharacter, Count := 1
  //Заменяем старый текст на новый
  Selection.TypeText Text := NK
end Sub
И напоследок, листинг основной функции VBA - WordTest, которая вызывает DLL и вставляет текст между закладками:
Sub WordTest()
Dim S1, S2 as string
//Загружаем DLL и форму
CreateForm
//Считываем данные с Edit
S1 = MyTest(1)
S2 = S1
//Преобразуем в нормальный текст
S2 = StrToStr(S2)
//Вставляем текст между закладками
NewTxt "BeginTest", "EndTest", S2

//Удаляем формы и выгружаем DLL
FreeForm

Exit Sub
end Sub
Исходники программы и документа прилагаются — AutoWrd.zip (127 K).
Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay