Советы по Delphi

         

Delphi и OLE Automation с Word


Автоматизация позволяет одному приложению управлять другим приложением. Управляемое приложение называется сервером автоматизации (в нашем случае Word). Приложение, управляющее сервером называется диспетчером автоматизации.

Есть два пути для получения доступа к серверам автоматизации:

Позднее связывание (Интерфейс IDispatch)

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

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

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

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

Раннее связывание (Использование библиотеки типов/интерфейсов)

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

Библиотека типов должна импортироваться в Delphi. Библиотека типов является языковым нейтральным описанием всех объектов и функций, поддерживаемых сервером. (Это подобно файлу заголовка языка C).

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

Скорость выполнения значительно быстрее, чем при использовании позднего связывания.



Из-за преимуществ второго метода остальная часть документа демонстрирует принципы создания приложений с ранним связыванием. Все приложения, использующие Excel автоматизацию, должны пользоваться последним методом, если нет причин для первого.

Подготовка библиотеки типов.

Модуль Pascal должен быть создан на основе файла библиотеки типов.

    • Выберите пункт меню Project|Import Type Library
    • Нажмите кнопку Add и выберите следующий файл
    • c:\program files\microsoft office\office\msword8.olb
    • Нажмите OK.

    К сожалению, данный модуль с проектом явно не компилируется, хотя и включается в него, вероятно из-за того, что приложение считает данный модуль нечто вроде текстового приложения.

    Наиболее простой путь заключается в следующем: удалите модуль excel_tlb из проекта и только после этого добавьте его в список используемых модулей.

    Документация

    Справочный файл c:\program files\microsoft office\office\vbawrd8.hlp содержит информацию о доступных объектах Word.

    "Записыватель" макросов позволяет быстро создавать VBA-код. После этого он довольно может легко быть портирован в Delphi.

    Пример автоматизации

    Следующий пример использует класс-оболочку Delphi, инкапсулирующий прямые вызовы объектов Word. Вот преимущество этого метода:

      • Обеспечение скрытия параметров. Возможность использования для многих методов параметров по умолчанию. Многие методы Word также работают с вариантными параметрами. Это означает невозможность использования констант - скрытие параметров решает данную проблему.
      • Обеспечение проверки типа. Многие методы определены с параметрами OLEVariant, обеспечивая внешнюю совместимость.
      • Следующий класс-оболочка демонстрирует ключевые методы автоматизации Word. Полностью класс приведен в Приложении 1.

          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;

      Итог

      • Всегда используйте раннее связывание.
      • Если позднее связывание необходимо для вызовов некоторых функций, используйте где возможно раннее связывание и преобразование типа объектной переменной к типу OLEVariant для вызовов, требующим позднее связывание.
      • Не включайте модуль библиотеки типов в ваш проект. Добавьте его только в список используемых модулей.
      • Создавайте код автоматизации в отдельном модуле. Инкапсулируйте вызовы в классе-оболочке.
      • Используйте "записыватель" макросов Word для создания прототипа кода автоматизации.
      • Используйте файл электронной справки vbawrd8.hlp для получения информации об объектах Word.
      • Используйте модуль Word_tlb.pas для проверки необходимых Delphi типов и количества параметров. Для проверки правильности кода перекомпилируйте проект, нажав клавиши <CTRL><F9>.
      • Загружайте и используйте шаблоны Word, содержащие предварительное форматирование текста. Этот способ существенно быстрее и не требует большого времени для создания сложноформатированных документов. Шаблоны ДОЛЖНЫ сохраняться приложением в своей рабочей директории. Это поможет избежать проблем, связанных с конфликтом имен.
      • Используйте закладки (Bookmarks) для определения области ввода текста приложением Delphi.
      • Удостоверьтесь в том, что ваш код содержит команду закрытия приложения Word (app.quit). Не вызывая app.quit, можно быстро исчерпать системные ресурсы, особенно при работе с большим количеством документов Word. Обратите на это особое внимание.
      • Наличие множества незакрытых документов Word легко проверить в Windows NT, используя Менеджер Задач (нажмите CTL+ALT+Del для его открытия).

      Приложение 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]



      Содержание раздела