Что делать, если во внешней печатной форме 1С всегда открывается один и тот же макет Word?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При разработке внешних печатных форм (ВПФ) для 1С:Зарплата и управление персоналом 3.1 программисты часто сталкиваются с ситуацией, когда механизм выбора макета работает нестабильно. Типичный сценарий: в обработке предусмотрено несколько двоичных макетов (например, разные трудовые договоры для разных должностей), но при последовательной печати документов программа «запоминает» первый открытый макет и подставляет его во все последующие вызовы, игнорируя условия логики. Рассмотрим подробнее, почему это происходит и как правильно организовать работу с COM-объектом Word.Application.

Анализируем причину проблемы: ошибка индексации

Разберем фрагмент кода, который чаще всего становится источником ошибки. В сообщении автора темы мы видим следующую строку: ДокументЗаполнение = Документ.Application.Documents(1); Это классическая ловушка при работе с Microsoft Word через COM-соединение. Проанализируем ситуацию: когда вы обращаетесь к Documents(1), вы просите Word дать вам самый первый документ в коллекции открытых файлов. Если у пользователя на компьютере уже запущен Word с каким-то личным документом, то именно он будет иметь индекс 1. Ваша печатная форма начнет записывать данные (номера договоров, ФИО сотрудников) в этот сторонний файл, а свежесозданный макет останется пустым или вообще не будет задействован. Решение: Никогда не используйте индексы для обращения к документу, который вы только что открыли. Метод Open() сам возвращает ссылку на объект документа. Правильный подход выглядит так:


// Вместо ДокументЗаполнение = Документ.Application.Documents(1);
// Используем объект, возвращенный методом Open
WordApp = Новый COMОбъект("Word.Application");
НовыйДокумент = WordApp.Documents.Open(ИмяВременногоФайла);
// Теперь работаем напрямую с переменной НовыйДокумент
НовыйДокумент.Variables.Item("ДоговорНомер").Value = "123";

Проблема «зомби-процессов» Word

Выясним причину, по которой макет может «залипать» даже при закрытии окна пользователем. В коде автора процедура СобратьМакет создает новый экземпляр Word.Application, но завершает процесс (метод Quit()) только в блоке Исключение. Если печать прошла успешно, процесс winword.exe может остаться висеть в памяти как фоновый процесс (так называемый «зомби-процесс»).

При следующем вызове печатной формы 1С может попытаться подключиться к уже существующему экземпляру Word, который всё еще держит в памяти старый макет или блокирует временные файлы в папке %TEMP%. Это приводит к тому, что новые данные либо не записываются, либо открывается копия старого файла из кэша.

Для предотвращения этой ситуации разберем правильный алгоритм завершения работы:

  1. Если вы планируете оставить документ открытым для пользователя, убедитесь, что вы не создаете лишних скрытых копий приложения.
  2. Если документ формируется в фоне (например, для сохранения в PDF), обязательно вызывайте Word.Quit() в конце кода.
  3. Перед формированием нового файла полезно проверять наличие зависших процессов Word, хотя лучше просто писать «чистый» код управления объектами.

Работа с временными файлами и кэшированием

В представленном коде используется стандартный метод ПолучитьИмяВременногоФайла("doc"). Рассмотрим, к чему это может привести. Если по какой-то причине файл не был удален после предыдущего сеанса печати (например, из-за блокировки зависшим процессом Word), 1С может столкнуться с конфликтом имен или открыть «автосохраненную» копию старого макета.

Проанализируем шаги для безопасной записи макета:

  1. Сгенерируйте уникальное имя файла, добавив к нему временную метку или уникальный идентификатор.
  2. Перед записью проверьте, не существует ли уже файл с таким именем, и если существует — попробуйте его удалить.
  3. Используйте команду УдалитьФайлы(ИмяВременногоФайла) после того, как Word успешно открыл документ, или в самом конце процедуры (после закрытия Word).

Контекст сервера и выбор макета

В функции ФормированиеДоговораПоШаблону автор обращается к реквизиту Объект.Документ.Должность. Посмотрим на этот момент с точки зрения архитектуры ВПФ. Если внешняя обработка открыта как форма, и пользователь выбирает разные документы в поле на форме, данные в Объект могут не обновляться автоматически.

При разработке ВПФ по стандартам БСП (Библиотека стандартных подсистем) рекомендуется получать данные объекта не из реквизитов формы, а по ссылке, переданной в массив объектов для печати. Рассмотрим пример правильного получения макета на сервере:


&НаСервере
Функция ПолучитьНужныйМакет(СсылкаНаОбъект)
    
    // Получаем данные непосредственно из базы по ссылке
    ДанныеДокумента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СсылкаНаОбъект, "Должность, ГрафикРаботы");
    
    Если ДанныеДокумента.Должность.Наименование = "Водитель" Тогда
        ИмяМакета = "Водитель";
    Иначе
        ИмяМакета = "Общий";
    КонецЕсли;
    
    // Обращаемся к макету обработки
    ЭтотОбъект = РеквизитФормыВЗначение("Объект");
    АктивныйДокумент = ЭтотОбъект.ПолучитьМакет(ИмяМакета);
    
    Возврат ПоместитьВоВременноеХранилище(АктивныйДокумент, ЭтаФорма.УникальныйИдентификатор);
    
КонецФункции

Обновление переменных документа (Fields.Update)

После того как мы заполнили DocVariables в Word, необходимо заставить приложение отобразить эти данные. Автор использует Документ.Fields.UpDate(). Важно помнить, что этот метод обновляет поля в основном теле документа, но может «забыть» про колонтитулы или надписи (TextBox).

Если ваши данные из 1С должны попасть в "шапку" или "подвал" документа Word, проанализируем расширенный метод обновления:


// Обновление полей во всех разделах документа (включая колонтитулы)
Для Каждого Раздел Из Документ.Sections Цикл
    Раздел.Headers.Item(1).Range.Fields.Update(); // Верхний колонтитул
    Раздел.Footers.Item(1).Range.Fields.Update(); // Нижний колонтитул
КонецЦикла;
Документ.Fields.Update(); // Основной текст

Итоги и рекомендации

Подводя итог, можно сказать, что проблема автора была вызвана сочетанием некорректного обращения к коллекции документов Documents(1) и отсутствием контроля за жизненным циклом COM-объекта. Чтобы ваша печатная форма всегда выводила актуальный макет, придерживайтесь следующих правил:

Соблюдение этих принципов гарантирует стабильную работу интеграции 1С с офисными приложениями и избавит пользователей от путаницы в печатных формах.

← На главную