При разработке обработок загрузки данных из электронных таблиц в базы 1С программисты часто сталкиваются с исключением:
Ошибка при вызове конструктора (COMОбъект): Excel = Новый COMОбъект("Excel.Application"); по причине: -2147221005(0x800401F3): Недопустимая строка с указанием класса
Выясним причину такого поведения платформы и подробно разберем несколько надежных способов устранения проблемы.
Код ошибки 0x800401F3 указывает на то, что идентификатор класса (ProgID — «Excel.Application») не зарегистрирован в реестре операционной системы в том окружении, где выполняется программный код. Проанализируем типичные ситуации, приводящие к этому сбою:
&НаСервере выполняется серверным процессом 1С (rphost). Если Microsoft Excel установлен только на клиентских рабочих станциях пользователей, а на физическом сервере его нет, сервер 1С не обнаружит нужных записей в ветке реестра HKEY_CLASSES_ROOT.USR1CV8 или аналогичная учетная запись сервера часто не имеет интерактивного профиля пользователя и прав DCOM на запуск приложений MS Office. Корпорация Microsoft официально не рекомендует серверную автоматизацию приложений пакета Office из системных служб.Самое простое и эффективное решение в случае, когда Excel установлен на клиентских компьютерах пользователей, — перенести создание COM-объекта в клиентский контекст с последующей передачей полученных данных на сервер.
Разберем по шагам реализацию такого подхода в управляемой форме. Сначала на клиенте интерактивно выбираем файл, открываем его через COM-объект, считываем нужные строки во временную структуру или массив, а затем передаем готовые данные на сервер для заполнения документов или справочников:
&НаКлиенте
Процедура ЗагрузитьФайлНаКлиенте(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Файлы Excel (*.xlsx;*.xls)|*.xlsx;*.xls";
Если Не Диалог.Выбрать() Тогда
Возврат;
КонецЕсли;
ИмяФайла = Диалог.ПолноеИмяФайла;
// Создание COM-объекта в контексте клиента
Попытка
ExcelПриложение = Новый COMОбъект("Excel.Application");
Исключение
Сообщить("Не удалось запустить Excel на клиенте: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
ExcelПриложение.Visible = Ложь;
ExcelПриложение.DisplayAlerts = Ложь;
Книга = ExcelПриложение.Workbooks.Open(ИмяФайла);
Лист = Книга.Sheets(1);
МассивДанных = Новый Массив;
НомерСтроки = 2; // Пропускаем строку заголовков
Пока ЗначениеЗаполнено(Лист.Cells(НомерСтроки, 1).Value) Цикл
СтрокаДанных = Новый Структура;
СтрокаДанных.Вставить("Артикул", СокрЛП(Лист.Cells(НомерСтроки, 1).Text));
СтрокаДанных.Вставить("Количество", Число(Лист.Cells(НомерСтроки, 2).Value));
СтрокаДанных.Вставить("Цена", Число(Лист.Cells(НомерСтроки, 3).Value));
МассивДанных.Добавить(СтрокаДанных);
НомерСтроки = НомерСтроки + 1;
КонецЦикла;
Книга.Close(Ложь);
ExcelПриложение.Quit();
ExcelПриложение = Неопределено;
// Передаем прочитанную коллекцию на сервер
ЗаполнитьДанныеНаСервере(МассивДанных);
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьДанныеНаСервере(МассивДанных)
Для Каждого Строка Из МассивДанных Цикл
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Артикул = Строка.Артикул;
НоваяСтрока.Количество = Строка.Количество;
НоваяСтрока.Цена = Строка.Цена;
КонецЦикла;
КонецПроцедуры
Рассмотрим более современный способ, который вообще не зависит от наличия MS Office и COM-библиотек. Начиная с платформы 8.3, объект ТабличныйДокумент умеет нативно открывать файлы форматов .xlsx и .xls как на клиенте, так и на сервере под Windows или Linux.
Разберем по шагам, как загрузить файл на сервер через временное хранилище и прочитать его:
&НаКлиенте
Процедура ВыбратьИЗагрузить(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Файлы Excel (*.xlsx)|*.xlsx";
Если Диалог.Выбрать() Тогда
АдресВХранилище = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(Диалог.ПолноеИмяФайла), УникальныйИдентификатор);
ПрочитатьФайлНаСервере(АдресВХранилище);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПрочитатьФайлНаСервере(АдресВХранилище)
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресВХранилище);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
ТабДок = Новый ТабличныйДокумент;
// Чтение файла средствами платформы 1С
ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Текст);
УдалитьФайлы(ИмяВременногоФайла);
// Обход строк полученного документа
ВсегоСтрок = ТабДок.ВысотаТаблицы;
Для НомерСтроки = 2 По ВсегоСтрок Цикл
Артикул = ТабДок.ПолучитьОбласть("R" + НомерСтроки + "C1").Текст;
Если ПустаяСтрока(Артикул) Тогда
Продолжить;
КонецЕсли;
Количество = ТабДок.ПолучитьОбласть("R" + НомерСтроки + "C2").Текст;
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Артикул = СокрЛП(Артикул);
НоваяСтрока.Количество = Число(Количество);
КонецЦикла;
КонецПроцедуры
Если требуется высокая скорость обработки больших таблиц непосредственно на сервере без установки полного пакета Microsoft Office, разберем чтение через провайдер Microsoft.ACE.OLEDB. В этом случае на сервере устанавливается только бесплатный компонент доступа к данным Microsoft Access Database Engine.
Важно: разрядность установленного OLE DB драйвера должна строго соответствовать разрядности сервера 1С:Предприятие (для 64-битного сервера необходим 64-битный драйвер).
&НаСервере
Процедура ПрочитатьЧерезADODB(ИмяФайла)
Соединение = Новый COMОбъект("ADODB.Connection");
СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ИмяФайла + ";Extended Properties=""Excel 12.0 XML;HDR=YES;"";";
Попытка
Соединение.Open(СтрокаПодключения);
Исключение
Сообщить("Ошибка подключения к ADODB: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
НаборЗаписей = Новый COMОбъект("ADODB.Recordset");
// Выбираем данные с первого листа книги
ТекстЗапроса = "SELECT * FROM [Лист1$]";
НаборЗаписей.Open(ТекстЗапроса, Соединение);
Пока Не НаборЗаписей.EOF Цикл
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Артикул = СокрЛП(Строка(НаборЗаписей.Fields("Артикул").Value));
НоваяСтрока.Количество = Число(НаборЗаписей.Fields("Количество").Value);
НаборЗаписей.MoveNext();
КонецЦикла;
НаборЗаписей.Close();
Соединение.Close();
КонецПроцедуры
Файлы формата .xlsx представляют собой сжатый zip-архив, содержащий XML-файлы с разметкой и строками. Платформа 1С содержит встроенные механизмы работы с архивами и XML:
ЧтениеZIPФайла архив распаковывается во временный каталог на сервере.xl/sharedStrings.xml с помощью объекта ЧтениеXML загружается пул уникальных строк документа.xl/worksheets/sheet1.xml) извлекаются координаты ячеек и индексы строк.Этот способ полностью платформенный, работает предельно быстро, не требует никаких сторонних библиотек и одинаково надежно выполняется в любых операционных системах.
Если архитектура конфигурации требует именно создания объекта Excel.Application под учетной записью службы сервера 1С, выполним обязательные системные настройки:
C:\Windows\System32\config\systemprofile\DesktopC:\Windows\SysWOW64\config\systemprofile\Desktopdcomcnfg («Службы компонентов») перейдем к настройке приложения «Microsoft Excel Application». На вкладке «Безопасность» назначим права на локальный запуск и активацию для пользователя сервера 1С, а на вкладке «Удостоверение» установим режим запуска «Указанный пользователь» с указанием действующей интерактивной учетной записи.dllhost.exe), чтобы обеспечить корректную трансляцию обращений между 32- и 64-битными адресными пространствами.