При интеграции 1С с внешними приложениями, в частности с Microsoft Excel, разработчики часто сталкиваются со специфическими ошибками операционной системы Windows. Одной из самых коварных является ошибка с кодом -2147221020 (0x800401E4): Синтаксическая ошибка, возникающая в момент инициализации COM-объекта через функцию ПолучитьCOMОбъект.
В этой статье мы подробно проанализируем, почему возникает эта ошибка, разберем системные механизмы Windows, которые за ней стоят, рассмотрим способы исправления исходного кода, а также изучим современные альтернативные подходы к чтению файлов Excel без использования технологии COM.
Рассмотрим классический пример кода, который приводит к возникновению исключительной ситуации:
Процедура КнопкаВыполнитьНажатие(Элемент)
Путь = Константы.ПутьДоФайлов.Получить() + "\";
Док = ПолучитьCOMОбъект(Путь + "конкуренты.xls");
// Дальнейшая обработка файла...
КонецПроцедуры
При выполнении этой процедуры платформа аварийно завершает работу на строке инициализации переменной Док, выводя системное сообщение: "Ошибка получения объекта COM: -2147221020(0x800401E4): Синтаксическая ошибка". Выясним, почему это происходит.
Код ошибки 0x800401E4 в операционной системе Windows соответствует системной константе MK_E_SYNTAX (недопустимый синтаксис моникера). Когда мы вызываем встроенную функцию 1С ПолучитьCOMОбъект(ПутьКФайлу), платформа транслирует этот вызов к Windows API функциям (таким как CoGetObject или CreateFileMoniker) для создания так называемого файлового моникера.
Для того чтобы операционная система смогла корректно распознать и создать файловый моникер, к строке пути предъявляются жесткие требования:
C:\Folder\File.xls или сетевой UNC-путь \\Server\Share\File.xls).В кодовой базе автора темы переменная Путь собирается динамически из константы:
Путь = Константы.ПутьДоФайлов.Получить() + "\";
Если константа ПутьДоФайлов не заполнена в информационной базе, то переменная Путь примет значение "\". При склеивании имени файла итоговая строка будет выглядеть как "\конкуренты.xls". Для подсистемы COM Windows этот путь является относительным. Попытка инициализировать моникер по такому пути гарантированно приводит к ошибке 0x800401E4 (MK_E_SYNTAX).
Решение в кодовой базе: Перед вызовом COM-объекта необходимо обязательно проверять заполненность пути и его валидность. Модифицируем код, добавив явные проверки:
Процедура КнопкаВыполнитьНажатие(Элемент)
БазовыйПуть = СокрЛП(Константы.ПутьДоФайлов.Получить());
Если ПустаяСтрока(БазовыйПуть) Тогда
ВызватьИсключение "Не задан путь к файлам в константах!";
КонецЕсли;
// Обеспечиваем корректное слияние каталога и имени файла
Если Прав(БазовыйПуть, 1) <> "\" Тогда
БазовыйПуть = БазовыйПуть + "\";
КонецЕсли;
ПолныйПуть = БазовыйПуть + "конкуренты.xls";
// Дополнительно проверяем физическое существование файла на диске
ФайлНаДиске = Новый Файл(ПолныйПуть);
Если Не ФайлНаДиске.Существует() Тогда
ВызватьИсключение "Указанный файл не найден по пути: " + ПолныйПуть;
КонецЕсли;
Попытка
Док = ПолучитьCOMОбъект(ПолныйПуть);
Исключение
Сообщить("Не удалось получить COM-объект. Описание ошибки: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Безопасная обработка данных...
КонецПроцедуры
Даже если путь к файлу абсолютно корректен, вызов может завершиться ошибкой, если код выполняется в серверном контексте. Проанализируем ключевые системные проблемы, которые могут возникнуть при работе COM-объектов на сервере:
USR1CV8) не имеет доступа к интерактивному рабочему столу Windows и правам запуска DCOM-объектов. Чтобы разрешить серверу 1С открывать Excel, необходимо запустить утилиту настройки DCOM (dcomcnfg.exe), найти в списке "Microsoft Excel Application" и во вкладках "Безопасность" и "Удостоверение" предоставить полные права для пользователя, под которым запущена служба 1С.Учитывая данные сложности администрирования, выполнять COM-код на стороне сервера крайне не рекомендуется.
Технология COM (Component Object Model) была основным инструментом интеграции в начале 2000-х годов, однако сегодня ее использование для чтения файлов Excel в среде 1С несет огромные риски:
Док.Application.Quit() не будет вызван. В результате процесс excel.exe останется висеть в диспетчере задач. При регулярной работе обработки сервер очень быстро исчерпает всю доступную оперативную память из-за сотен зависших процессов.Начиная с версии платформы 8.3.6, разработчикам доступен мощный встроенный кроссплатформенный механизм чтения файлов Excel без использования стороннего софта. Речь идет об объекте ТабличныйДокумент и его методе Прочитать().
Этот способ работает на любой операционной системе (Windows, Linux, macOS), выполняется на сервере и клиенте одинаково быстро, не требует установленного Microsoft Office и полностью исключает утечки оперативной памяти.
Рассмотрим, как переписать исходный алгоритм автора темы с использованием объекта ТабличныйДокумент. Наш новый код будет выглядеть следующим образом:
Процедура ЧтениеExcelЧерезТабДок(ИмяФайла)
// Создаем объект табличного документа платформы
ТабДок = Новый ТабличныйДокумент;
Попытка
// Читаем файл напрямую. Платформа сама определит структуру xls/xlsx
ТабДок.Прочитать(ИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
Сообщить("Не удалось прочитать файл! Ошибка: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Получаем размеры прочитанной таблицы
ВысотаТаблицы = ТабДок.ВысотаТаблицы;
ШиринаТаблицы = ТабДок.ШиринаТаблицы;
// Анализируем данные. В исходном коде обход делался по двум листам.
// Если нужно читать конкретные области, мы можем обращаться к ячейкам по индексам.
// Обратите внимание: индексы в Табличном Документе начинаются с 1.
Для СтрокаНом = 1 По ВысотаТаблицы Цикл
Контрагент = ТабДок.Область(СтрокаНом, 1).Текст;
Номенклатура = ТабДок.Область(СтрокаНом, 2).Текст;
Цена = ТабДок.Область(СтрокаНом, 3).Текст;
// Прерываем цикл, если строка пустая (эквивалент цикла Пока из примера)
Если ПустаяСтрока(СокрЛП(Номенклатура)) Тогда
Продолжить;
КонецЕсли;
Сообщить(Строка(Номенклатура) + " - " + Строка(Цена));
КонецЦикла;
КонецПроцедуры
Этот простой и лаконичный метод избавляет разработчиков от необходимости настраивать права DCOM, следить за разрядностью систем и бороться с зависшими процессами Windows. Для обеспечения максимальной производительности при разборе очень больших файлов рекомендуется использовать чтение XML-структуры архива .xlsx напрямую с помощью встроенных механизмов ЧтениеXML и ЧтениеZipФайла.