Почему перестает работать ПолучитьCOMОбъект(ИмяФайла) для Excel и чем его заменить?

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

В практике разработки на 1С часто встречается ситуация, когда код, который долгое время работал без сбоев, внезапно начинает выдавать ошибку. Одна из таких «плавающих» проблем — отказ функции ПолучитьCOMОбъект(ИмяФайла) при работе с файлами Microsoft Excel. Давайте разберемся, почему это происходит и какие существуют более надежные способы для решения этой задачи.

Проблема обычно выглядит так: строка кода ДокExcel = ПолучитьCOMОбъект(ИмяФайла);, которая раньше успешно открывала файл и возвращала COM-объект, начинает вызывать исключение «Ошибка при вызове метода контекста (ПолучитьCOMОбъект)». При этом подключение к уже запущенному экземпляру Excel через ПолучитьCOMОбъект(, "Excel.Application") может продолжать работать.

Причины такого поведения чаще всего кроются не в коде 1С, а во внешнем окружении:

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

Решение 1: Использование связки `Новый COMОбъект` и метода `Open`

Этот подход является более стабильным и управляемым, чем ПолучитьCOMОбъект. Мы не полагаемся на систему в поиске или создании приложения для файла, а явно создаем новый экземпляр Excel и даем ему команду открыть нужный файл. Это дает больше контроля над процессом.

Посмотрим на пример. Изначально код, который перестал работать, мог выглядеть так:


// Старый, нестабильно работающий вариант
Попытка
    Книга = ПолучитьCOMОбъект(inputFileName);
    Ексель = Книга.Application;
    Ексель.DisplayAlerts = Ложь;
    Лист = Книга.Sheets(1);
Исключение
    // ... обработка ошибки
КонецПопытки;

Заменим его на более надежную конструкцию. Разберем по шагам:

  1. Создаем новый экземпляр приложения Excel с помощью Новый COMОбъект("Excel.Application").
  2. Используя полученный объект, открываем нужную книгу методом Workbooks.Open(ИмяФайла).
  3. Выполняем необходимые действия с листами и ячейками.
  4. Важный шаг: корректно завершаем работу, закрывая книгу и сам объект Excel, чтобы не оставлять «подвисших» процессов.

Вот как выглядит итоговый код:


&НаСервере
Процедура ПрочитатьФайлЧерезНовыйCOM()

    ИмяФайла = "C:\Temp\МойФайл.xlsx"; // Укажите свой путь к файлу
    Excel = Неопределено;

    Попытка
        // 1. Создаем новый объект приложения Excel
        Excel = Новый COMОбъект("Excel.Application");

        // Управляем видимостью окна и оповещениями (полезно для фоновой обработки)
        Excel.Visible = Ложь;
        Excel.DisplayAlerts = Ложь;

        // 2. Открываем книгу в созданном приложении
        Книга = Excel.Workbooks.Open(ИмяФайла);
        
        // 3. Получаем доступ к листу (например, к первому)
        Лист = Книга.Worksheets(1);

        // ... здесь ваш код для работы с данными листа ...
        Сообщить("Файл успешно открыт. Значение ячейки А1: " + Лист.Cells(1,1).Value);

    Исключение
        Предупреждение("Внимание! Файл не открыт. " + ОписаниеОшибки());
        // Если Excel был создан, но произошла ошибка при открытии файла,
        // его все равно нужно попытаться закрыть
        Если Excel <> Неопределено Тогда
            Excel.Quit();
        КонецЕсли;
        Возврат;
    КонецПопытки;

    // 4. Корректно завершаем работу с COM-объектами
    Если Excel <> Неопределено Тогда
        // Закрываем книгу без сохранения изменений
        Книга.Close(Ложь);
        // Закрываем приложение Excel
        Excel.Quit();
        // Освобождаем переменные
        Excel = Неопределено;
    КонецЕсли;

КонецПроцедуры

Обратите внимание: при работе на сервере даже этот метод может выдать ошибку «Невозможно получить свойство Open класса Workbooks». Чаще всего это связано с тем, что у системного пользователя, от имени которого запущена служба сервера 1С, нет папки Desktop в его системном профиле. Для решения может потребоваться создать каталоги C:\Windows\SysWOW64\config\systemprofile\Desktop и C:\Windows\System32\config\systemprofile\Desktop.

Решение 2: Чтение файла через объект `ТабличныйДокумент` (без COM)

Это самый надежный способ для чтения данных из файлов .xls и .xlsx, особенно при выполнении кода на сервере. Он полностью исключает взаимодействие с COM, а значит, ему не нужен установленный MS Excel на машине, где выполняется код. Этот метод не зависит от прав DCOM, обновлений Office и других внешних факторов.

Преимущества:

Ограничения:

Рассмотрим пример функции, которая читает данные с указанного листа Excel и возвращает их в виде таблицы значений.


&НаСервере
Функция ПрочитатьЛистExcelНаСервере(пИмяФайла, пИмяЛиста)
    
    ТабличныйДокумент = Новый ТабличныйДокумент;
    
    // Считываем весь файл в объект ТабличныйДокумент
    Попытка
        ТабличныйДокумент.Прочитать(пИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    Исключение
        Сообщить("Не удалось прочитать файл: " + пИмяФайла);
        Возврат Новый ТаблицаЗначений;
    КонецПопытки;

    // Преобразуем имя листа в имя области
    // Это ключевой момент! Имена областей формируются по особым правилам.
    ИмяОбласти = "_" + СтрЗаменить(пИмяЛиста, ".", "_");
    ИмяОбласти = СтрЗаменить(ИмяОбласти, ",", "_");
    ИмяОбласти = СтрЗаменить(ИмяОбласти, " ", "_");
    ИмяОбласти = СтрЗаменить(ИмяОбласти, "(", "_");
    ИмяОбласти = СтрЗаменить(ИмяОбласти, ")", "_");
    // и т.д. для всех служебных символов

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

Очень важный нюанс, который нужно учесть, — это формирование имени области. Когда 1С считывает файл Excel, имена листов преобразуются в имена именованных областей в объекте ТабличныйДокумент по следующим правилам:

Например:

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


&НаКлиенте
Процедура ПримерВызоваЧтения()
    ИмяФайла = "C:\Temp\МойФайл.xlsx";
    ИмяЛиста = "01 Контрагенты";
    
    ТаблицаДанных = ПрочитатьЛистExcelНаСервере(ИмяФайла, ИмяЛиста);
    
    Если ТаблицаДанных.Количество() > 0 Тогда
        Сообщить("Данные с листа '" + ИмяЛиста + "' успешно загружены!");
        // Дальнейшая работа с таблицей значений...
    КонецЕсли;
КонецПроцедуры

Таким образом, если вы столкнулись с нестабильной работой ПолучитьCOMОбъект, рекомендуем перейти на один из предложенных методов. Для универсальных задач и работы с форматированием используйте Новый COMОбъект, а для надежного чтения данных на сервере — встроенный объект ТабличныйДокумент.

← На главную