При интеграции 1С с Microsoft Excel через COM-соединение разработчики нередко сталкиваются с ошибкой: «Ошибка при вызове метода контекста (Cells): Произошла исключительная ситуация (0x800a03ec)». Разберем подробно, почему возникает данная исключительная ситуация, как правильно настроить обход строк и корректно перенести данные в табличную часть документа.
Код ошибки 0x800a03ec является общей ошибкой автоматизации Microsoft Excel (Name Not Found / Invalid Index). Проанализируем основные факторы, вызывающие этот сбой:
Cells(НомерСтроки, НомерКолонки) значение 0 или отрицательное число, Excel не сможет адресовать ячейку и выбросит исключение.Sheets("ИмяЛиста") или опечатка в названии..xls).Посмотрим на типичный фрагмент кода, в котором переменная начальной строки инициализирована нулем или не заполнена:
номстр = НачалоСтроки; // если здесь 0, произойдет ошибка 0x800a03ec
Пока СокрЛП("" + док.Sheets("Лист").Cells(номстр, 1).Value) <> "zzzzzz" Цикл
// обработка данных
номстр = номстр + 1;
КонецЦикла;
Для устранения проблемы явно укажем начальный индекс, равный единице (или номеру первой строки с данными):
номстр = 1; // Нумерация в Excel всегда начинается с 1
Пока СокрЛП("" + док.Sheets("Лист").Cells(номстр, 1).Value) <> "" Цикл
// Чтение данных
номстр = номстр + 1;
КонецЦикла;
Частая проблема при переносе строк из файла в табличную часть — незаполнение полей ссылочного типа. Если реквизит ПунктПрейскуранта имеет тип СправочникСсылка.Прейскурант, прямое присвоение ему строкового значения приведет к тому, что ячейка останется пустой:
// Ошибочный вариант: строковое значение присваивается ссылочному полю
стро.ПунктПрейскуранта = Знаим; // Поле останется пустым!
Рассмотрим два варианта решения в зависимости от бизнес-логики задачи:
Вариант А. Создание нового элемента справочника, если он не найден:
спр = Справочники.Прейскурант.НайтиПоКоду(Зкод);
Если спр = Справочники.Прейскурант.ПустаяСсылка() Тогда
// Создаем новый элемент в базе
НовыйЭлемент = Справочники.Прейскурант.СоздатьЭлемент();
НовыйЭлемент.Код = Зкод;
НовыйЭлемент.Наименование = Знаим;
НовыйЭлемент.Записать();
стро = Работы.Добавить();
стро.ПунктПрейскуранта = НовыйЭлемент.Ссылка;
стро.Код = Зкод;
стро.ЦенаНас = Число(сокрлп("" + док.Sheets("Лист").Cells(номстр, 29).Value));
Иначе
стро = Работы.Добавить();
стро.ПунктПрейскуранта = спр;
стро.Код = Зкод;
КонецЕсли;
Вариант Б. Заполнение отдельного текстового реквизита:
Если справочник засорять новыми позициями не требуется, в табличную часть добавляется строковый реквизит (например, НаименованиеСтрокой), в который напрямую записывается прочитанный текст: стро.НаименованиеСтрокой = Знаим;.
При использовании ПолучитьCOMОбъект() процесс EXCEL.EXE остается в оперативной памяти даже после завершения работы процедуры. Чтобы избежать утечек памяти и зависания файла, обязательно закрываем книгу и очищаем ссылку на объект:
Процедура ГрузимКалькуляции(Кнопка)
Если Не ЗначениеЗаполнено(файл) Тогда
Возврат;
КонецЕсли;
док = ПолучитьCOMОбъект(файл);
Лист = док.Sheets("Лист");
номстр = 1;
Пока СокрЛП("" + Лист.Cells(номстр, 1).Value) <> "" Цикл
Зкод = СокрЛП("" + Лист.Cells(номстр, 1).Value);
Знаим = СокрЛП("" + Лист.Cells(номстр, 2).Value);
спр = Справочники.Прейскурант.НайтиПоКоду(Зкод);
Если спр.Пустая() Тогда
стро = Работы.Добавить();
стро.Код = Зкод;
стро.ЦенаНас = Лист.Cells(номстр, 29).Value;
стро.ЦенаЮл = Лист.Cells(номстр, 29).Value;
КонецЕсли;
номстр = номстр + 1;
КонецЦикла;
// Закрытие книги без сохранения и освобождение памяти
док.Application.Quit();
док = Неопределено;
КонецПроцедуры
Чтобы полностью отказаться от COM-соединения, зависимости от разрядности Office и платформы Windows, рекомендуется использовать встроенный метод ТабличныйДокумент.Прочитать(). Он работает значительно быстрее и поддерживается на сервере 1С под управлением любой операционной системы:
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(файл);
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
Зкод = СокрЛП(ТабДок.Область(НомерСтроки, 1).Текст);
Знаим = СокрЛП(ТабДок.Область(НомерСтроки, 2).Текст);
Если ПустаяСтрока(Зкод) Тогда
Продолжить;
КонецЕсли;
// Обработка полученных строк
КонецЦикла;