Как корректно закрыть Excel и освободить файл при работе через COM-объект в 1С?

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

При программном формировании отчетов, заполнении шаблонов или пакетной выгрузке данных в файлы Microsoft Excel разработчики часто сталкиваются с ошибками совместного доступа. Типичная ситуация: файл сформирован и сохранен, но при попытке тут же прикрепить его к письму для отправки по электронной почте или переместить в другой каталог платформа 1С выдает ошибку блокировки. В диспетчере задач при этом продолжает висеть процесс EXCEL.EXE, удерживающий дескриптор файла.

Проанализируем причины такого поведения COM-сервера, разберем типичные ошибки в коде 1С и рассмотрим по шагам, как гарантированно выгружать Excel из оперативной памяти.

Почему процесс Excel зависает в памяти

Работа с внешними офисными программами из 1С строится на технологии COM (Component Object Model). COM-сервер отслеживает количество активных ссылок на свои объекты. Если хотя бы одна ссылка не была освобождена, процесс операционной системы не завершится, даже если в коде был вызван метод завершения приложения.

Выделим основные причины зависания процесса:

  1. Неосвобожденные ссылки на дочерние объекты. При обращении к листам книги (Worksheets), диапазонам (Range), ячейкам (Cells) или строкам (EntireRow) платформа 1С неявно создает внутренние COM-объекты. Если переменной, содержащей лист или ячейку, не присвоить значение Неопределено, счетчик ссылок COM-сервера остается больше нуля.
  2. Незакрытые книги. Открытие шаблона или новой книги требует обязательного вызова метода Close() для каждого открытого экземпляра Workbook до завершения работы самого приложения.
  3. Нарушение порядка завершения. Вызов метода Quit() после того, как ссылка на само Приложение уже была затерта значением Неопределено, не сработает. Также метод Quit() не закроет процесс, если перед этим не были закрыты книги и не обнулены промежуточные переменные.
  4. Скрытые диалоговые окна. Если Excel пытается запросить подтверждение перезаписи файла или сохранения несохраненных изменений, невидимый процесс переходит в модальный режим ожидания ответа пользователя.

Пошаговый алгоритм правильной работы с COM-объектом Excel

Разберем последовательность действий, гарантирующую корректное закрытие файлов и выгрузку процесса из памяти:

  1. Отключение предупреждений и обновлений. Сразу после создания объекта Excel.Application обязательно отключаем вывод системных диалогов: Приложение.DisplayAlerts = Ложь;.
  2. Работа внутри блока обработки исключений. Весь процесс формирования файла необходимо помещать в конструкцию Попытка ... Исключение, чтобы в случае программного сбоя код закрытия и очистки переменных гарантированно выполнился.
  3. Явное закрытие книг. Для каждого открытого объекта рабочей книги вызываем метод Close(Ложь) с параметром Ложь (чтобы отключить запрос на сохранение, если файл уже был записан отдельно).
  4. Завершение работы приложения. Вызываем метод Приложение.Quit() строго до обнуления ссылки на приложение.
  5. Обнуление всех COM-переменных. Присваиваем Неопределено всем переменным, которые ссылались на ячейки, листы, коллекции, книги и само приложение.
  6. Принудительный запуск сборщика мусора. Вызываем процедуру ОчиститьПамять(), чтобы платформа 1С немедленно освободила память COM-интерфейсов.

Посмотрим на пример правильной структуры процедуры:


&НаСервере
Процедура СформироватьИОтправитьФайлExcel()
    
    Приложение = Неопределено;
    РабочаяКнига = Неопределено;
    Лист = Неопределено;
    Ячейка = Неопределено;
    
    Попытка
        Приложение = Новый COMОбъект("Excel.Application");
        Приложение.DisplayAlerts = Ложь;
        Приложение.ScreenUpdating = Ложь;
        
        РабочаяКнига = Приложение.Workbooks.Add();
        Лист = РабочаяКнига.Worksheets(1);
        
        Ячейка = Лист.Cells(1, 1);
        Ячейка.Value = "Тестовые данные";
        
        ИмяФайла = ПолучитьИмяВременногоФайла("xlsx");
        РабочаяКнига.SaveAs(ИмяФайла);
        
    Исключение
        Сообщить("Ошибка при формировании Excel: " + ОписаниеОшибки());
    КонецПопытки;
    
    // Освобождаем ресурсы в обратном порядке
    Ячейка = Неопределено;
    Лист = Неопределено;
    
    Если РабочаяКнига <> Неопределено Тогда
        РабочаяКнига.Close(Ложь);
        РабочаяКнига = Неопределено;
    КонецЕсли;
    
    Если Приложение <> Неопределено Тогда
        Приложение.Quit();
        Приложение = Неопределено;
    КонецЕсли;
    
    // Принудительно очищаем COM-ссылки в памяти 1С
    ОчиститьПамять();
    
    // Теперь файл гарантированно разблокирован и готов к отправке
    ОтправитьФайлПоПочте(ИмяФайла);
    
КонецПроцедуры

Альтернативный способ: использование штатного табличного документа

Рассмотрим более надежный и современный вариант выгрузки данных, не требующий установки Microsoft Office и использования технологии COM. В платформе 1С реализован встроенный механизм сохранения табличных документов в формат Excel.

Преимущества данного подхода:

  1. Работа на сервере без ограничений. Метод полностью платформонезависим и стабильно работает на 64-разрядных серверах 1С под управлением как Windows, так и Linux.
  2. Отсутствие блокировок. Файл создается средствами платформы и закрывается сразу в момент записи, что исключает зависание процессов в операционной системе.
  3. Высокая скорость работы. Формирование отчета через встроенный макет происходит в разы быстрее, чем обращение к каждой отдельной ячейке через COM-модель.

Разберем пример сохранения данных через ТабличныйДокумент:


&НаСервере
Функция СформироватьФайлЧерезТабДок(ВыборкаДанных)
    
    ТабДок = Новый ТабличныйДокумент;
    Макет = ПолучитьМакет("МакетВыгрузки");
    
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ТабДок.Вывести(ОбластьШапка);
    
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    Пока ВыборкаДанных.Следующий() Цикл
        ОбластьСтрока.Параметры.Заполнить(ВыборкаДанных);
        ТабДок.Вывести(ОбластьСтрока);
    КонецЦикла;
    
    ПутьКФайлу = ПолучитьИмяВременногоФайла("xlsx");
    ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
    
    Возврат ПутьКФайлу;
    
КонецФункции

Если для бизнес-логики не требуется специфическая функциональность макросов VBA, предпочтительно использовать штатный ТабличныйДокумент вместо создания COM-объектов.

← На главную