Как изменить текст в нижнем колонтитуле Word из 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При формировании печатных форм договоров и других документов в Microsoft Word средствами OLE Automation из платформы 1С 7.7 разработчики нередко сталкиваются с ситуацией, когда замена текста в теле документа отрабатывает корректно, а попытка изменить колонтитулы приводит к ошибкам времени выполнения. Разберем типичные ошибки, проанализируем причины их возникновения и рассмотрим правильные варианты реализации задачи.

Анализ проблемы и распространенных ошибок

Посмотрим на классический сценарий. Для замены текста в основном теле документа часто используется объект выделения Word.Selection:


Word.Selection.Find.Replacement.ClearFormatting();
Word.Selection.Find.Execute(Текст1, 0, 0, 0, 0, 0, 1, 1, 0, Текст2, 2);

Однако при попытке обратиться к колонтитулу через Word.Selection(1).Footers... платформа 1С 7.7 возвращает ошибку «Коллекции не поддерживаются». Выясним причину такого поведения. Механизм COM/OLE Automation в 1С 7.7 не умеет индексировать произвольные OLE-объекты как массивы, если они не являются полноправными COM-коллекциями. Сам объект Selection коллекцией не является. Кроме того, поиск через Word.Selection физически ограничен областью основного текста документа (MainDocument) и не затрагивает колонтитулы.

Следующая частая попытка исправления — вызов коллекции разделов через корневой объект приложения: Word.Sections.Item(1).... В этом случае возникает ошибка «Поле агрегатного объекта не обнаружено (Sections)». Причина проста: коллекция Sections принадлежит конкретному документу (объекту Document), а не всему приложению Word.Application.

Также ошибку «Microsoft Word: "Range" не является методом» или «Неопознанный оператор» вызывает попытка обращаться к свойству Range со скобками или использовать его в отдельной строке без присваивания или вызова методов.

Рабочее решение: обращение через коллекцию разделов документа

Чтобы получить доступ к колонтитулу, необходимо обращаться строго к объекту открытого документа (переменной, возвращенной методом Documents.Add() или Documents.Open()), последовательно вызывая нужный раздел из коллекции Sections и нужный колонтитул из коллекции Footers.

Разберем по шагам готовый код процедуры замены текста в нижнем колонтитуле:


Процедура ЗаменитьТекстКолонтитула(Doc, Текст1, Текст2)
    мКолонтитул = Doc.Sections(1).Footers(1).Range;
    мКолонтитул.Find.ClearFormatting();
    мКолонтитул.Find.Replacement.ClearFormatting();
    мКолонтитул.Find.Execute(Текст1, 0, 0, 0, 0, 0, 1, 1, 0, Текст2, 2);
КонецПроцедуры

Рассмотрим подробнее вызов основного метода печати документа:


Процедура Печать()
    ШаблонДоговора = КаталогИБ() + "Шаблоны\Договор.doc";
    
    Если ФС.СуществуетФайл(ШаблонДоговора) = 0 Тогда
        Предупреждение("Файл шаблона не найден!");
        Возврат;
    КонецЕсли;
    
    Word = СоздатьОбъект("Word.Application");
    Word.Visible = 1;
    Doc = Word.Documents.Add(ШаблонДоговора);
    
    // Замена в основном тексте документа
    Word.Selection.Find.Execute("%НомерДоговора%",,,,,,,,,СокрЛП(НомерДог), 2);
    
    // Замена в нижнем колонтитуле первого раздела
    ЗаменитьТекстКолонтитула(Doc, "%НомерДоговора%", СокрЛП(НомерДог));
    ЗаменитьТекстКолонтитула(Doc, "%ДатаДоговора%", СокрЛП(Строка(ДатаДог)));
    
    Doc.Activate();
    Word = 0;
КонецПроцедуры

Важные нюансы работы с колонтитулами Word

Проанализируем ситуации, когда стандартного обращения к первому элементу Footers(1) может быть недостаточно:

  1. Разные типы колонтитулов. Коллекция Footers содержит три элемента:
    1. Индекс 1 (wdHeaderFooterPrimary) — основной колонтитул документа.
    2. Индекс 2 (wdHeaderFooterFirstPage) — колонтитул первой страницы.
    3. Индекс 3 (wdHeaderFooterEvenPages) — колонтитул для четных страниц.
    Если в шаблоне включена опция «Особый колонтитул для первой страницы», то обращение к Footers(1) заменит текст только со второй страницы. Для первой страницы замену нужно продублировать в Footers(2).
  2. Многосекционные документы. Если договор содержит разрывы разделов (например, приложения или альбомные листы) и связь между ними отключена, обращение только к Doc.Sections(1) изменит текст исключительно в первом разделе. В 1С 7.7 отсутствует цикл Для Каждого, поэтому обход всех секций организуется с помощью обычного цикла по счетчику:

Для НомСекции = 1 По Doc.Sections.Count Цикл
    Doc.Sections(НомСекции).Footers(1).Range.Find.Execute(Текст1,,,,,,,,,Текст2, 2);
КонецЦикла;

Альтернативные способы заполнения колонтитулов

Посмотрим на другие варианты реализации, если поиск по тексту дает сбои или шаблон содержит сложную структуру:

  1. Переключение режима отображения окна (SeekView). Мы можем программно перевести курсор активного окна Word прямо в область нижнего колонтитула и выполнить стандартный поиск через Word.Selection:
    
    Word.ActiveWindow.ActivePane.View.SeekView = 10; // 10 = wdSeekCurrentPageFooter
    Word.Selection.Find.Execute(Текст1,,,,,,,,,Текст2, 2);
    Word.ActiveWindow.ActivePane.View.SeekView = 0;  // 0 = wdSeekMainDocument (возврат в тело)
    
  2. Использование закладок (Bookmarks). Если в процессе автопроверки орфографии Word разбивает метку поиска внутри шаблона, надежнее разместить в колонтитуле закладку:
    
    Если Doc.Bookmarks.Exists("НомерДоговора") = 1 Тогда
        Doc.Bookmarks("НомерДоговора").Range.Text = СокрЛП(НомерДог);
    КонецЕсли;
    

Освобождение системных ресурсов

Обратим внимание на завершение работы с OLE: простое присвоение Word = 0 лишь разрывает связь переменной 1С с процессом. Если документ генерируется в скрытом режиме (Word.Visible = 0) для фоновой печати или сохранения в файл, обязательно закрывайте документ и само приложение явным вызовом команд Doc.Close(0) и Word.Quit() во избежание накопления зависших процессов WINWORD.EXE в диспетчере задач.

← На главную