Как исправить ошибку при закрытии книги Excel через COM-соединение в 1С?

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

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

В чем причина ошибки при вызове ActiveWorkbook

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


Процедура ЗакрытьФайл()
    Если Excel <> Неопределено Тогда 
        Excel.ActiveWorkbook.Close(Ложь);
        Excel.Quit();    
    КонецЕсли;    
КонецПроцедуры

На первый взгляд кажется, что проверка Если Excel <> Неопределено полностью защищает процедуру от ошибок. Однако на практике возникает исключение. Выясним причину такого поведения:

  1. Отсутствие открытой книги в приложении: Если процесс Excel.Application был инициализирован, но метод открытия книги не был вызван, завершился с ошибкой или книга не была создана, свойство ActiveWorkbook не содержит COM-объекта книги. Обращение к методу Close() у несуществующего объекта приводит к аварийной остановке выполнения.
  2. Неосвобожденная COM-ссылка: Метод Excel.Quit() отправляет операционной системе команду закрыть приложение, однако переменная 1С продолжает удерживать ссылку на COM-объект. Если переменной явно не присвоено значение Неопределено, условие Excel <> Неопределено при повторном обращении вернет значение Истина, но сам процесс Excel уже завершен или находится в некорректном состоянии.
  3. Пользовательские диалоги и блокировки: При закрытии книги Excel может инициировать системные предупреждения или диалоги сохранения, которые блокируют поток выполнения и вызывают ошибку ожидания ответа сервера автоматизации.

Способ 1. Проверка наличия активной книги и обнуление ссылки

Рассмотрим простейший способ устранения ошибки непосредственно в существующей процедуре закрытия. Добавим дополнительную проверку свойства ActiveWorkbook и выполним обязательную очистку переменной COM-объекта:


Процедура ЗакрытьФайл()
    Если Excel <> Неопределено Тогда 
        // Проверяем, есть ли действительно открытая книга в приложении
        Если Excel.ActiveWorkbook <> Неопределено Тогда
            Excel.ActiveWorkbook.Close(Ложь);
        КонецЕсли;
        
        Excel.Quit();
        // Обязательно освобождаем ссылку в 1С
        Excel = Неопределено;
    КонецЕсли;    
КонецПроцедуры

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

Способ 2. Явное сохранение ссылки на книгу (рекомендуемый подход)

Обращение через свойство ActiveWorkbook считается небезопасной практикой при автоматизации. Если во время работы обработки пользователь переключится в другое окно Microsoft Excel, активной книгой станет совсем другой документ. Разберем более надежную архитектуру работы с сохранением ссылки на открытый экземпляр книги:


Перем ЭкземплярExcel;
Перем ТекущаяКнига;

Процедура ОткрытьФайл(ПутьКФайлу)
    // Закрываем предыдущие сеансы перед открытием нового документа
    ЗакрытьФайл();
    
    Попытка
        ЭкземплярExcel = Новый COMОбъект("Excel.Application");
        ЭкземплярExcel.DisplayAlerts = Ложь; // Отключаем предупреждающие сообщения
        ТекущаяКнига = ЭкземплярExcel.Workbooks.Open(ПутьКФайлу);
    Исключение
        ЗакрытьФайл();
        ВызватьИсключение "Не удалось открыть файл Excel: " + ОписаниеОшибки();
    КонецПопытки;
КонецПроцедуры

Процедура ЗакрытьФайл()
    // Последовательно закрываем книгу и приложение
    Если ТекущаяКнига <> Неопределено Тогда
        Попытка
            ТекущаяКнига.Close(Ложь);
        Исключение
            // Игнорируем ошибку, если файл уже был закрыт
        КонецПопытки;
        ТекущаяКнига = Неопределено;
    КонецЕсли;
    
    Если ЭкземплярExcel <> Неопределено Тогда
        Попытка
            ЭкземплярExcel.Quit();
        Исключение
            // Игнорируем ошибку при выходе
        КонецПопытки;
        ЭкземплярExcel = Неопределено;
    КонецЕсли;
КонецПроцедуры

Посмотрим на преимущества данной реализации:

  1. Мы отключаем системные предупреждения с помощью свойства DisplayAlerts = Ложь, предотвращая зависание процесса.
  2. Каждый объект (книга и само приложение) хранится в отдельной переменной и уничтожается по отдельности.
  3. Все потенциально опасные операции освобождения ресурсов обернуты в блок Попытка ... Исключение, что гарантирует работу интерфейса без критических падений.

Ограничения использования COM-объектов в 1С

При проектировании механизмов загрузки данных важно учитывать технологические ограничения COM-соединения:

  1. Привязка к операционной системе: Конструкция Новый COMОбъект работоспособна исключительно в ОС Windows. На сервере или клиенте под управлением Linux данный код вызовет неустранимую ошибку.
  2. Несовместимость с веб-клиентом: В среде веб-клиента создание COM-объектов платформой не поддерживается.
  3. Зависимость от установленного ПО: На рабочем месте пользователя обязательно должен быть установлен и корректно настроен офисный пакет Microsoft Excel.
  4. Проблема разрядности: 64-разрядный клиент 1С:Предприятия не может работать напрямую с 32-разрядным компонентом Excel без настройки COM+ в службах компонентов Windows.

Альтернатива: Чтение файлов без COM-автоматизации

Если задача заключается исключительно в чтении данных из файла Excel (без сложного редактирования формул или форматирования), рекомендуется использовать встроенный объект 1С ТабличныйДокумент. Разберем пример реализации:


ТабДок = Новый ТабличныйДокумент;
Попытка
    ТабДок.Прочитать(ПутьКФайлу);
Исключение
    Сообщить("Ошибка чтения файла: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

// Обходим полученные ячейки
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
    ЗначениеКолонки = ТабДок.Область(НомерСтроки, 1).Текст;
КонецЦикла;

Метод ТабличныйДокумент.Прочитать() работает как с файлами формата XLS, так и с XLSX. Он полностью кроссплатформенный, выполняется значительно быстрее COM-соединения и не оставляет зависших системных процессов в памяти компьютера.

← На главную