Почему Word не закрывается после работы из 1С и как это исправить?

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

При работе с Microsoft Word через COM-объекты из 1С часто возникает неприятная ситуация: после выполнения всех операций (создание, заполнение, сохранение документа) и вызова команды закрытия, сам Word вроде бы исчезает с экрана, но его процесс WINWORD.EXE продолжает "висеть" в диспетчере задач. Это приводит к накоплению "мусорных" процессов, которые потребляют ресурсы системы и могут мешать дальнейшей работе. Разберемся, почему так происходит и как правильно завершать работу с Word, чтобы он полностью выгружался из памяти.

Анализ проблемы: почему Word "зависает" в процессах

Давайте проанализируем типичный код работы с COM-объектами, который приводит к этой проблеме. Автор исходного сообщения на форуме использовал примерно такую последовательность действий:

  1. Создал новый COM-объект: Word = Новый COMОбъект("Word.Application");
  2. Открыл документ: Документ = Word.Documents.Open(ИмяВременногоФайла);
  3. Выполнил замену текста в документе Word.
  4. Сохранил результат заполнения шаблона Word в PDF: Документ.SaveAS(ИмяВременногоФайлаПДФ, 17);
  5. Попытался закрыть Word: Word.Application.Quit(); или Word.Quit();

На первый взгляд, все логично. Мы дали команду приложению на закрытие. Но здесь кроется ключевая ошибка. Причина, по которой процесс WINWORD.EXE не завершается, заключается в том, что в памяти 1С остаются активные ссылки на объекты, созданные этим процессом. В нашем случае — это объект открытого документа, хранящийся в переменной Документ. Пока 1С "держит" эту ссылку, сборщик мусора не может полностью освободить COM-объект, и приложение Word считает, что его ресурсы все еще используются, поэтому не может корректно завершить свою работу.

Важный момент: Простого вызова метода Quit() недостаточно. Необходимо придерживаться строгого правила: освобождать COM-объекты нужно в порядке, обратном их созданию. То есть сначала мы должны закрыть "дочерние" объекты (документы, диапазоны, объекты поиска) и только потом — родительский объект приложения.

Правильное решение: последовательное закрытие и освобождение объектов

Чтобы гарантированно закрыть Word, важно соблюдать стандарты и методики разработки и выполнить три ключевых шага. Рассмотрим их подробно.

Шаг 1: Закрываем открытый документ

Перед тем как дать команду на закрытие всего приложения, нужно явно закрыть все открытые в нем документы. Для этого используется метод Close() объекта документа.


// Закрываем документ. Параметр 0 (или константа wdDoNotSaveChanges)
// означает, что документ нужно закрыть без сохранения изменений.
// Это безопасно, так как мы уже сохранили результат в PDF.
Документ.Close(0);

Если бы нам нужно было сохранить изменения в исходном .doc файле, мы бы использовали другой параметр, например, -1 (константа wdSaveChanges).

Шаг 2: Закрываем приложение Word

Теперь, когда все дочерние объекты (документы) закрыты, можно безопасно завершать работу самого приложения. Для этого используется метод Quit().

Word.Quit();

Шаг 3: Освобождаем переменные (разрываем связи)

Последний, но не менее важный шаг — это присвоение значения Неопределено всем переменным, которые хранили ссылки на COM-объекты. Это является явным указанием для сборщика мусора 1С, что эти объекты нам больше не нужны и память, занимаемую ими, можно освободить.


Документ = Неопределено;
Word = Неопределено;
// Также нужно присвоить Неопределено и другим переменным,
// если они ссылались на объекты Word (например, на объект Find).
Замена = Неопределено;

Полный пример кода с обработкой ошибок

Объединим все шаги в единый работающий пример. Крайне рекомендуется оборачивать работу с COM-объектами в конструкцию Попытка ... Исключение ... КонецПопытки. Это гарантирует, что даже если в процессе заполнения документа произойдет ошибка, код очистки (закрытие Word) все равно будет выполнен.

Вот как будет выглядеть доработанный и надежный фрагмент кода:


&НаКлиенте
Процедура СобратьМакетWORD(СсылкаНаОбъект)
    
    // ... Код получения данных и временных имен файлов ...
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("doc"); 
    ИмяВременногоФайлаПДФ = ПолучитьИмяВременногоФайла("PDF"); 
    // ...
    
    Word = Неопределено;
    Документ = Неопределено;
    
    Попытка
        Word = Новый COMОбъект("Word.Application");
        Word.Visible = Ложь; // Работаем в фоновом режиме, не показывая окно пользователю
        
        Документ = Word.Documents.Open(ИмяВременногоФайла);
        
        // --- Блок работы с документом ---
        Для Каждого ЭлементДанных Из Данные Цикл
            Замена = Документ.Content.Find;
            Замена.Execute("«" + ЭлементДанных.Ключ + "»", Ложь, Истина, Ложь, Ложь, , Истина, , Ложь, СокрЛП(ЭлементДанных.Значение), 2);
        КонецЦикла;
        
        // Сохраняем результат в PDF
        // 17 - это числовое значение константы wdFormatPDF
        Документ.SaveAs(ИмяВременногоФайлаПДФ, 17);
        
        ЗапуститьПриложение(ИмяВременногоФайлаПДФ);
        
    Исключение
        Сообщение = Новый СообщениеПользователю();
        Сообщение.Текст = "Произошла ошибка при формировании документа: " + ОписаниеОшибки();
        Сообщение.Сообщить();
    КонецПопытки;
    
    // --- Блок обязательной очистки ресурсов ---
    // Этот код выполнится в любом случае: и после успешной работы, и после ошибки
    Если Документ <> Неопределено Тогда
        Документ.Close(0); // 0 - не сохранять изменения
        Документ = Неопределено;
    КонецЕсли;
        
    Если Word <> Неопределено Тогда
        Word.Quit();
        Word = Неопределено;
    КонецЕсли;
    
КонецПроцедуры

Альтернативные и "силовые" методы

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

Принудительное завершение процесса (не рекомендуется)

Можно запустить из 1С системную команду taskkill для принудительного "убийства" процесса WINWORD.EXE.

Почему это плохой подход? Как было справедливо замечено в обсуждении, у вас нет надежного способа определить, какой именно из процессов WINWORD.EXE был запущен вашим кодом. Если у пользователя в этот момент открыты другие важные документы Word, ваша команда закроет их все без сохранения, что приведет к потере данных. Этот метод стоит рассматривать только в самых крайних случаях и на свой страх и риск.

Отказ от COM в пользу нативных инструментов 1С

Вместо использования шаблонов Word можно рассмотреть встроенные в 1С механизмы:

Эти подходы исключают саму проблему взаимодействия с COM, делая решение более стабильным и независимым от внешних приложений.

Таким образом, ключ к решению проблемы — правильная дисциплина работы с COM-объектами: всегда закрывайте дочерние объекты перед родительскими и очищайте переменные, присваивая им Неопределено.

← На главную