При программном взаимодействии с Microsoft Excel из платформы 1С:Предприятие разработчики часто сталкиваются с необходимостью использовать встроенные параметры поиска или форматирования, такие как xlValues, xlPart, xlWhole. Однако прямое обращение вида COMОбъект.XlFindLookIn.xlValues вызывает ошибку: платформа сообщает, что переменная не обнаружена. В этой статье мы подробно разберем, почему возникает такое поведение, как правильно передавать константы и как настроить вызов метода поиска Find без возникновения системных исключений.
Проанализируем техническую сторону взаимодействия платформы 1С и офисного пакета. Когда мы создаем объект с помощью конструкции Новый COMObject("Excel.Application"), платформа работает с внешним приложением через механизм позднего связывания по интерфейсу IDispatch.
В объектной модели Excel именованные константы и перечисления (например, XlFindLookIn, XlLookAt) зашиты в библиотеку типов (TypeLib) приложения и служат для удобства написания кода в среде Visual Basic for Applications (VBA). Сам COM-объект верхнего уровня Application не содержит эти константы как доступные свойства. Поэтому 1С не может разрешить обращение по имени и возвращает ошибку отсутствия свойства или переменной. Единственный способ передать нужный параметр в методы Excel через COM в 1С — использовать их числовые эквиваленты.
Рассмотрим способы, с помощью которых можно быстро и точно определить целочисленное значение любой константы Microsoft Excel.
Alt + F11 для перехода в редактор Visual Basic, а затем нажмем клавишу F2. Откроется окно обозревателя объектов (Object Browser). В поле поиска введем имя интересующей константы, например xlValues или xlPart. В нижней информационной панели будет показано точное числовое значение константы.Ctrl + G для открытия окна Immediate и выполним команду вывода значения: Debug.Print XlLookAt.xlPart, после чего нажмем Enter. В строке ниже отобразится число.powershell -Command "[int][Microsoft.Office.Interop.Excel.XlLookAt]::xlWhole".Выделим наиболее востребованные константы, применяемые при вызове метода Find:
Область поиска данных (XlFindLookIn):
xlFormulas (поиск в формулах) = -4123;xlValues (поиск в вычисленных значениях) = -4163;xlComments (поиск в примечаниях к ячейкам) = -4144.Степень соответствия (XlLookAt):
xlWhole (ячейка целиком) = 1;xlPart (любая часть ячейки) = 2.Порядок просмотра (XlSearchOrder):
xlByRows (по строкам) = 1;xlByColumns (по колонкам) = 2.Направление поиска (XlSearchDirection):
xlNext (следующее совпадение) = 1;xlPrevious (предыдущее совпадение) = 2.Нередко разработчик, определив верные числовые значения, пытается вызвать метод поиска и получает ошибки OLE-моста вида 0x80020005 или 0x8002000b. Разберем механику возникновения этих исключений.
1. Ошибка 0x80020005 (DISP_E_TYPEMISMATCH — Несоответствие типов).
В синтаксисе метода Excel Find вторым параметром идет аргумент After, который задает ячейку, после которой начинается поиск. Если в коде 1С попытаться пропустить этот параметр двойной запятой: Диапазон.Find(ИскомоеЗначение, , xlValues, xlPart), OLE-мост передает пустое значение типа VT_EMPTY. Метод Find жестко требует, чтобы во второй параметр передавался именно COM-объект единичной ячейки. Из-за несовпадения типов возникает исключение 0x80020005.
2. Ошибка 0x8002000b (DISP_E_BADINDEX — Неверный индекс).
Данная ошибка возникает, когда в аргумент After передана переменная со значением Неопределено, либо передан объект ячейки, не входящей в исходный диапазон поиска. По правилам объектной модели Excel аргумент After обязан представлять собой строго одну ячейку, лежащую внутри исследуемого диапазона.
3. Неявное форматирование чисел в 1С.
Если адреса строк или столбцов формируются динамически с помощью числовых переменных, помните: стандартное строковое преобразование числа в платформе 1С (функция Строка()) вставляет неразрывный пробел в качестве разделителя групп разрядов при числах от 1000 и выше. При передаче адреса вида "A1 000" Excel вернет ошибку COM. Для адресации всегда используйте форматирование без разделителей: Формат(НомерСтроки, "ЧГ=0").
Объединим полученные знания и напишем надежный алгоритм поиска значения на листе Excel. Чтобы обойти проблему пропуска аргумента After, передадим в него первую ячейку исследуемого диапазона:
// Создаем экземпляр приложения Excel
ExcelПриложение = Новый COMObject("Excel.Application");
ExcelПриложение.Visible = Ложь;
Попытка
Книга = ExcelПриложение.Workbooks.Open(ПутьКФайлу);
Лист = Книга.Sheets(1);
// Определяем диапазон для поиска
Диапазон = Лист.UsedRange;
// В качестве стартовой ячейки обязательно берем первую ячейку диапазона
СтартоваяЯчейка = Диапазон.Cells(1, 1);
// Числовые эквиваленты констант Excel
xlValues = -4163;
xlPart = 2;
ИскомаяСтрока = "Тестовая строка";
// Выполняем поиск с явным указанием параметров
Результат = Диапазон.Find(ИскомаяСтрока, СтартоваяЯчейка, xlValues, xlPart);
Если Результат <> Неопределено Тогда
Сообщить("Найдено в ячейке: " + Результат.Address);
Иначе
Сообщить("Значение не найдено.");
КонецЕсли;
Исключение
Сообщить("Произошла ошибка при поиске: " + ОписаниеОшибки());
КонецПопытки;
// Обязательно корректно закрываем книгу и освобождаем процесс
Книга.Close(Ложь);
ExcelПриложение.Quit();
ExcelПриложение = Неопределено;
Важное замечание: Microsoft Excel сохраняет параметры последнего поиска (LookIn, LookAt, SearchOrder) между вызовами программного кода и действиями пользователя в интерфейсе. Если вызвать метод Find только с одним параметром строки поиска, Excel применит настройки, которые использовались в предыдущей сессии. Это часто приводит к трудноуловимым ошибкам, когда на одном сервере код находит ячейку, а на другом — нет. Рекомендуется всегда явно указывать параметры поиска числами.
Обращение к Excel через COM имеет ряд существенных ограничений: необходимость установки платного офисного пакета на сервер, несовместимость с операционными системами Linux, высокий расход оперативной памяти и риск зависания фоновых процессов в диспетчере задач.
Если задача заключается исключительно в чтении и поиске данных, рассмотрим нативный механизм платформы 1С — ТабличныйДокумент:
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу);
ПараметрыНахождения = Новый ПараметрыНахожденияТекста;
ПараметрыНахождения.СтрокаПоиска = "Тестовая строка";
ПараметрыНахождения.ТочноеСоответствие = Ложь;
Область = ТабДок.НайтиТекст(ПараметрыНахождения);
Если Область <> Неопределено Тогда
Сообщить("Текст найден в строке: " + Формат(Область.Верх, "ЧГ=0"));
КонецЕсли;
Чтение файла через ТабличныйДокумент выполняется средствами платформы без запуска сторонних процессов, работает кроссплатформенно на Windows и Linux и значительно превосходит COM-соединение по скорости обработки файлов.