При разработке интеграций в 1С часто возникает задача взаимодействия с внешними приложениями, например, с Microsoft Excel, Word или Outlook, через технологию COM. Стандартный подход для обработки возможных ошибок — это использование конструкции Попытка ... Исключение ... КонецПопытки. Однако многие разработчики сталкиваются с ситуацией, когда этот блок не срабатывает, и программа аварийно завершается с ошибкой "Тип не определен", если нужный COM-объект (например, Excel) не установлен на компьютере пользователя. Разберем, почему так происходит и как правильно организовать проверку.
Проанализируем типичный код, который приводит к проблеме. На первый взгляд, он кажется абсолютно корректным:
// Неправильный пример
Перем Excel;
Попытка
Excel = Новый COMОбъект("Excel.Application");
// ... дальнейшая работа с Excel
Исключение
Сообщить("Microsoft Excel не установлен!");
КонецПопытки;
Логика проста: пытаемся создать объект, если не получается — переходим в блок Исключение. Но вместо этого выполнение прерывается. В чем же дело?
Причина кроется в механизме работы платформы 1С и разнице между ошибками компиляции и ошибками выполнения. Процесс можно разделить на два этапа:
Новый COMОбъект("Excel.Application"), она пытается не просто запомнить эту команду, а сразу же обращается к системе, чтобы найти описание (библиотеку типов) для объекта "Excel.Application". Этот механизм называется ранним связыванием (early binding). Он позволяет платформе заранее "узнать" о всех методах и свойствах объекта, что ускоряет последующее выполнение и дает возможность использовать подсказки при написании кода. Если Excel не установлен, его библиотека типов в системе отсутствует. Платформа не может найти описание и генерирует фатальную ошибку "Тип не определен" еще на этапе компиляции, до того, как код начнет выполняться.Попытка ... Исключение предназначена для перехвата ошибок, которые происходят именно на этом этапе (run-time errors), например, деление на ноль, обращение к несуществующему элементу массива или ошибка при создании COM-объекта, если все типы известны.Таким образом, наша проблема заключается в том, что ошибка возникает до того, как блок Попытка начинает свою работу. Он просто не успевает "включиться", потому что весь модуль не может быть скомпилирован.
Чтобы обойти ошибку компиляции, нам нужно заставить 1С не искать типы заранее, а определять их непосредственно в момент выполнения кода. Этот подход называется поздним связыванием (late binding). Для этого достаточно не объявлять переменную с конкретным типом, а сразу присваивать ей результат создания COM-объекта внутри блока Попытка.
Посмотрим на исправленный, правильный код:
Процедура ПроверитьИЗапуститьExcel()
Перем Excel; // Объявляем переменную без типа
Попытка
// Вся магия здесь: создание объекта происходит в момент выполнения
Excel = Новый COMОбъект("Excel.Application");
Исключение
// Если на этапе выполнения создать объект не удалось,
// мы корректно попадем в этот блок
Сообщить("Программа MS Excel не установлена на данном компьютере! Операция не может быть выполнена.");
Возврат; // Прерываем выполнение процедуры
КонецПопытки;
// Если мы дошли до сюда, значит Excel успешно создан
Сообщить("Excel успешно запущен. Начинаем работу...");
Excel.Visible = Истина; // Сделаем окно видимым
Excel.Workbooks.Add(); // Добавим новую книгу
// ... здесь идет дальнейшая работа с объектом Excel ...
КонецПроцедуры
В этом варианте компилятор 1С видит, что переменной Excel присваивается значение, но не пытается заранее определить ее тип. Вся операция по созданию COM-объекта происходит внутри блока Попытка уже на этапе выполнения. Если в этот момент Новый COMОбъект() не сможет найти "Excel.Application" в системе, возникнет ошибка выполнения, которую конструкция Попытка ... Исключение успешно перехватит.
В реальных задачах хорошей практикой является не просто создание нового экземпляра Excel, а проверка, не запущен ли он уже у пользователя. Это более дружелюбно по отношению к пользователю, так как не плодит лишние окна и процессы. Для этой цели используется функция ПолучитьCOMОбъект().
Разберем по шагам, как создать надежную и универсальную функцию для работы с Excel.
Функция ПолучитьОбъектExcel()
// Переменная для хранения COM-объекта
Перем Excel;
// Шаг 1: Попытаться подключиться к уже запущенному экземпляру Excel.
// Первый параметр пустой, второй - имя COM-объекта.
Попытка
Excel = ПолучитьCOMОбъект("", "Excel.Application");
Исключение
// Если не получилось, это не страшно. Это значит, что Excel просто не запущен.
// Переменная Excel останется "Неопределено", и мы перейдем к следующему шагу.
// Никаких сообщений здесь выводить не нужно.
КонецПопытки;
// Шаг 2: Если подключиться к существующему не удалось, создаем новый экземпляр.
Если Excel = Неопределено Тогда
Попытка
Excel = Новый COMОбъект("Excel.Application");
Исключение
// А вот если и создание нового объекта провалилось, значит,
// Excel действительно не установлен в системе.
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Microsoft Excel не установлен на этом компьютере. Выгрузка данных невозможна.";
Сообщение.Сообщить();
Возврат Неопределено; // Возвращаем признак неудачи
КонецПопытки;
КонецЕсли;
// Если все прошло успешно, возвращаем готовый к работе объект
Возврат Excel;
КонецФункции
// Пример использования функции
Процедура СформироватьОтчетВExcel()
ExcelApp = ПолучитьОбъектExcel();
Если ExcelApp = Неопределено Тогда
// Функция уже вывела сообщение, просто выходим
Возврат;
КонецЕсли;
// Делаем Excel видимым и работаем с ним
ExcelApp.Visible = Истина;
Книга = ExcelApp.Workbooks.Add();
Лист = Книга.Worksheets(1);
Лист.Cells(1, 1).Value = "Привет из 1С!";
// ... дальнейшая работа ...
КонецПроцедуры
Этот подход является наиболее профессиональным: он сначала ищет существующий процесс и только в случае неудачи создает новый, при этом корректно обрабатывая ситуацию с отсутствием программы на компьютере.
Работа с COM-объектами требует внимательного отношения к ресурсам. COM-объект — это внешняя по отношению к 1С программа. Если вы просто закроете свою обработку, процесс Excel может остаться "висеть" в памяти компьютера. Чтобы этого избежать, после завершения работы необходимо явно освободить занимаемые ресурсы.
Важно: в конце работы с COM-объектом всегда присваивайте переменной значение Неопределено. Это дает сигнал сборщику мусора 1С, что объект больше не используется и его можно выгрузить из памяти.
// ... работа с Excel завершена ...
// Если вы создавали Excel невидимым и хотите закрыть его без сохранения
// ExcelApp.DisplayAlerts = 0; // Отключаем стандартные диалоги Excel (например, "Сохранить изменения?")
// ExcelApp.Quit(); // Закрываем приложение Excel
// Главный шаг: обнуляем переменную, чтобы освободить COM-объект из памяти.
// Это разорвет связь между 1С и процессом Excel.
ExcelApp = Неопределено;
Следуя этим правилам — используя позднее связывание для проверки и не забывая освобождать ресурсы — вы сможете создавать надежный и стабильный код для интеграции 1С с любыми внешними COM-приложениями.