Автоматизация позволяет одному приложению управлять другим приложением. Управляемое приложение называется сервером автоматизации (в нашем случае Word). Приложение, управляющее сервером называется диспетчером автоматизации.
Есть два пути для получения доступа к серверам автоматизации:
Позднее связывание (Интерфейс IDispatch)
При использовании данного метода имена функций и типы параметров решаются во время выполнения программы, все параметры определены вариантным типом.
Поскольку во время компиляции невозможно определить соответствия имен функций и типов параметров, данный метод чреват ошибками.
Так как имена функций и типы параметров должны проверяться во время выполнения программы, данный метод выполняется медленно.
Единственное преимущество данного метода при программировании в Delphi заключается в том, что отпадает необходимость передачи всех параметров вызываемой функции.
Раннее связывание (Использование библиотеки типов/интерфейсов)
При использовании данного метода имена функций и типы параметров полностью решаются во время компиляции.
Библиотека типов должна импортироваться в Delphi. Библиотека типов является языковым нейтральным описанием всех объектов и функций, поддерживаемых сервером. (Это подобно файлу заголовка языка C).
При вызове функции должны обязательно присутствовать все параметры, даже те, которые в документации указаны как дополнительные (необязательные). Это позволяет обнаружить и исправить множество ошибок еще до запуска программы.
Скорость выполнения значительно быстрее, чем при использовании позднего связывания.
Из-за преимуществ второго метода остальная часть документа демонстрирует принципы создания приложений с ранним связыванием. Все приложения, использующие Excel автоматизацию, должны пользоваться последним методом, если нет причин для первого.
Подготовка библиотеки типов.
Модуль Pascal должен быть создан на основе файла библиотеки типов.
К сожалению, данный модуль с проектом явно не компилируется, хотя и включается в него, вероятно из-за того, что приложение считает данный модуль нечто вроде текстового приложения.
Наиболее простой путь заключается в следующем: удалите модуль excel_tlb из проекта и только после этого добавьте его в список используемых модулей.
Документация
Справочный файл c:\program files\microsoft office\office\vbawrd8.hlp содержит информацию о доступных объектах Word.
"Записыватель" макросов позволяет быстро создавать VBA-код. После этого он довольно может легко быть портирован в Delphi.
Пример автоматизации
Следующий пример использует класс-оболочку Delphi, инкапсулирующий прямые вызовы объектов Word. Вот преимущество этого метода:
unit doc; interface uses windows, sysutils, Word_TLB; type TWinWord = class Private App : _Application; public constructor Create; destructor Destroy; override; procedure NewDoc(Template : String); procedure GotoBookmark(Bookmark : String); procedure InsertText(Text : String); procedure SaveAs(Filename : string); end; //------------------------------------------------------------------ implementation //------------------------------------------------------------------ constructor TWinWord.Create; begin App := CoApplication.Create; end; //------------------------------------------------------------------ destructor TWinWord.Destroy; var SaveChanges : OLEVariant; OriginalFormat : OLEVariant; RouteDocument : OLEVariant; begin SaveChanges := wdDoNotSaveChanges; OriginalFormat := unAssigned; RouteDocument := unAssigned; app.Quit(SaveChanges, OriginalFormat, RouteDocument); inherited destroy; end; //------------------------------------------------------------------ procedure TWinWord.GotoBookmark(Bookmark : string); var What : OLEVariant; Which : OLEVariant; Count : OLEVariant; Name : OLEVariant; begin What := wdGoToBookmark; Which := unAssigned; Count := unAssigned; Name := Bookmark; App.Selection.GoTo_(What, Which, Count, Name); end; //------------------------------------------------------------------ procedure TWinWord.InsertText(Text : String); begin App.Selection.TypeText(Text); end; //------------------------------------------------------------------ procedure TWinWord.NewDoc(Template : String); var DocTemplate : OleVariant; NewTemplate : OleVariant; begin DocTemplate := Template; NewTemplate := False; App.Documents.Add(DocTemplate, NewTemplate); end; //------------------------------------------------------------------ procedure TWinWord.SaveAs(Filename : string); begin OLEVariant(App).ActiveDocument.SaveAs(FileName); end; //------------------------------------------------------------------ end. |
Чтобы создать класс:
Добавьте модуль библиотеки типов в список используемых модулей.
uses windows, sysutils, Word_TLB; |
Создадим определение класса:
TWinWord = class Private App : _Application; public procedure NewDoc(Template : String); procedure GotoBookmark(Bookmark : String); procedure InsertText(Text : String); procedure SaveAs(Filename : string); constructor Create; destructor Destroy; override; end; |
Переменная App является ссылкой на приложение Word. Это допускает вызов методов Word с применением технологии раннего связывания.
Опубликованные (public) процедуры - процедуры, которые могут быть использованы при работе с классом.
Создадим конструктор.
constructor TWinWord.Create; begin App := CoApplication.Create; end; |
Он вызывается при создании класса TWinWord. CoApplication.create создает новый экземпляр Word и возвращает ссылку на интерфейс Application. Это позволяет вызывать методы объекта app.
Реализация дектруктора
destructor TWinWord.Destroy; var SaveChanges : OLEVariant; OriginalFormat : OLEVariant; RouteDocument : OLEVariant; begin SaveChanges := wdDoNotSaveChanges; OriginalFormat := unAssigned; RouteDocument := unAssigned; app.Quit(SaveChanges, OriginalFormat, RouteDocument); inherited destroy; end; |
Деструктор должен вызываться В ОБЯЗАТЕЛЬНОМ ПОРЯДКЕ. Метод Quit объекта приложения закрывает Word и распределяет всю связанную с ним память. Так как параметры метода Quit определены как вариантный тип OLEVariant, вся свазанная с ними память распределяется именно для этого типа переменных.
Реализуем метод NewDoc. Этот метод создаст новый текстовый документ на основе заданного шаблона.
procedure TWinWord.NewDoc(Template : String); var DocTemplate : OleVariant; NewTemplate : OleVariant; begin DocTemplate := Template; NewTemplate := False; App.Documents.Add(DocTemplate, NewTemplate); end; |
Данный метод осуществляет более строгую проверку типов, чем это осуществляет сам Word. Параметр Template должен содержать строку с именем шаблона. Метод Word Add в качестве параметров может содержать значения любого типа. Лучшая пример этого - метод MoveRight, реализация которого показана в Приложении 1.
Ниже показана реализация метода SaveAs. Данный метод позволит сохранить в файле текущий документ.
procedure TWinWord.SaveAs(Filename : string); begin OLEVariant(App).ActiveDocument.SaveAs(FileName); end; |
Данный пример использует позднее связывание. В результате имя метода и используемые типы проверяются только во время прогона. Изменение имени метода в этом случае не вызовет ошибку во время компиляции. В нашем случае технология позднего связывания более эффективна, так как метод SaveAs требует 12 параметров, но только параметр FileName является обязательным. Так как данный вызов можно считать единичным, его выполнение не может особо сказаться на скорости выполнения программы.
Следующий код демонстрирует использование данного класса для создания, редактирования, печати и сохранения документа, созданного на основе шаблона:
Word := TWinWord.create; try Word.visible := true; Word.NewDoc('c:\delphi\word\sample\Demo'); Word.GotoBookmark('From'); Word.InsertText('Иван Иваныч'); Word.GotoBookmark('Dept'); Word.InsertText('Разработка'); Word.GotoBookmark('Phone'); Word.InsertText('111111'); Word.GotoBookmark('Now'); Word.InsertText(FormatDateTime('d-mmm-yyyy', now)); //SF элементы Word.GotoBookmark('Items'); Word.InsertText('112021'); Word.MoveRight(1); Word.InsertText('PVCS'); Word.MoveRight(1); Word.InsertText('1'); Word.MoveRight(1); Word.InsertText('Ј 305.99'); Word.MoveRight(1); Word.InsertText('Ј 305.99'); Word.MoveRight(1); Word.UpdateFields; Word.RunMacro('Demo'); Word.Print; Word.SaveAs(filename); finally Word.Free; end; |
Итог
Приложение A – Полный исходный код сласса TWinWord
Полный исходный код класса tWinWord приведен ниже. Он включает реализацию всех методов:
unit doc; interface uses Word_TLB, windows, sysutils; Type TWinWord = class Private App : _Application; function fGetVisible : boolean; procedure fSetVisible(visible : boolean); public procedure NewDoc(Template : String); procedure GotoBookmark(Bookmark : String); procedure InsertText(Text : String); procedure MoveRight(Count : integer); procedure Print; procedure UpdateFields; procedure SaveAs(Filename : string); Procedure RunMacro(MacroName : string); constructor Create; destructor Destroy; override; property visible : boolean read fGetVisible write fSetVisible; end; implementation //------------------------------------------------------------------ constructor TWinWord.Create; begin App := CoApplication.Create; end; //------------------------------------------------------------------ destructor TWinWord.Destroy; var SaveChanges : OLEVariant; OriginalFormat : OLEVariant; RouteDocument : OLEVariant; begin SaveChanges := wdDoNotSaveChanges; OriginalFormat := unAssigned; RouteDocument := unAssigned; app.Quit(SaveChanges, OriginalFormat, RouteDocument); inherited destroy; end; //------------------------------------------------------------------ function TWinWord.fGetVisible : boolean; begin result := App.Visible; end; //------------------------------------------------------------------ procedure TWinWord.fSetVisible(Visible : boolean); begin App.visible := Visible; end; //------------------------------------------------------------------ procedure TWinWord.GotoBookmark(Bookmark : string); var What : OLEVariant; Which : OLEVariant; Count : OLEVariant; Name : OLEVariant; begin What := wdGoToBookmark; Which := unAssigned; Count := unAssigned; Name := Bookmark; App.Selection.GoTo_(What, Which, Count, Name); end; //------------------------------------------------------------------ procedure TWinWord.InsertText(Text : String); begin App.Selection.TypeText(Text); end; //------------------------------------------------------------------ procedure TWinWord.NewDoc(Template : String); var DocTemplate : OleVariant; NewTemplate : OleVariant; begin DocTemplate := Template; NewTemplate := False; App.Documents.Add(DocTemplate, NewTemplate); end; //------------------------------------------------------------------ procedure TWinWord.MoveRight(Count : integer); var MoveUnit : OleVariant; vCount : OleVariant; Extended : OleVariant; begin MoveUnit := wdCell; vCount := Count; Extended := unassigned; app.selection.MoveRight(MoveUnit, vCount, Extended); end; //------------------------------------------------------------------ procedure TWinWord.Print; begin OLEVariant(app).Printout; end; //------------------------------------------------------------------ procedure TWinWord.UpdateFields; begin App.ActiveDocument.Fields.Update; end; //------------------------------------------------------------------ procedure TWinWord.SaveAs(Filename : string); begin OLEVariant(App).ActiveDocument.SaveAs(FileName); end; //------------------------------------------------------------------ procedure TWinWord.RunMacro(MacroName : string); begin App.Run(MacroName); end; //------------------------------------------------------------------ end. |
[000199]