Почему возникает ошибка «Метод объекта не обнаружен (newobject)» при работе через COM-соединение в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При организации обмена данными между информационными базами 1С через COM-соединение разработчики часто сталкиваются с неочевидными ошибками. Среди них наиболее распространены две: ошибка вызова глобальных методов внешнего контекста (например, NewObject или НовыйОбъект) и падение программы при попытке обратиться к элементам коллекций метаданных по индексу в квадратных скобках []. Разберем по шагам причины такого поведения платформы и рассмотрим правильные варианты реализации обмена данными.

1. Причины ошибки «Метод объекта не обнаружен (newobject)»

Проанализируем ситуацию, когда при выполнении следующей строки возникает исключение:


УидВоВнешнейБазе = БазаОткрыта.NewObject("УникальныйИдентификатор", Строка(УидВЭтойБазе));

Существует две основные причины, приводящие к такой ошибке:

  1. Потеря COM-объекта при пересечении клиент-серверного контекста. COM-объекты Windows являются платформенно-зависимыми и не сериализуются. Если инициализация соединения COMConnector выполнена на клиенте, а затем переменная передается в серверную процедуру (или наоборот), значение переменной теряется и превращается в Неопределено либо теряет доступные методы. Все манипуляции с COM-соединением должны происходить строго в рамках одного контекста (рекомендуется выполнять весь обмен исключительно на сервере).
  2. Разница между COMConnector и Automation-сервером (Application). При создании объекта V83.COMConnector метод Connect() возвращает ссылку на глобальный контекст внешней базы данных. Именно у этой ссылки доступны методы NewObject, НовыйОбъект, Справочники, Документы и т.д. Если же используется OLE-сервер V83.Application, метод Connect() возвращает лишь булево значение (Истина/Ложь), а обращение к глобальному контексту необходимо выполнять напрямую через созданный COM-объект приложения.

Посмотрим на корректный пример инициализации подключения через COMConnector на стороне сервера:


&НаСервере
Процедура ВыполнитьПодключениеИОбмен()
    
    ПараметрыПодключения = "File=""" + СокрЛП(ПутьКБазе) + """; Usr=""" + СокрЛП(Логин) + """; Pwd=""" + СокрЛП(Пароль) + """;";
    
    Попытка
        COMСоединитель = Новый COMОбъект("V83.COMConnector");
        ВнешняяБаза = COMСоединитель.Connect(ПараметрыПодключения);
    Исключение
        ЗаписьЖурналаРегистрации("ОбменЧерезCOM", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        ВызватьИсключение "Не удалось подключиться к внешней базе: " + ОписаниеОшибки();
    КонецПопытки;
    
    // Передаем валидный COM-объект в процедуру внутри сервера
    СкопироватьДанные(ВнешняяБаза);
    
КонецПроцедуры

2. Ошибка обращения к коллекциям по индексу через квадратные скобки

Следующая частая проблема возникает при обходе метаданных внешней базы. В коде текущей конфигурации 1С программисты привыкли обращаться к элементам коллекций (реквизитам, табличным частям, колонкам) через квадратные скобки: Метаданные().Реквизиты[Сч].Имя.

Однако при работе с COM-объектом интерфейс IDispatch не поддерживает синтаксис квадратных скобок для коллекций внешней базы. Попытка выполнить такой код приведет к ошибке выполнения.

Выясним правильные способы обхода коллекций объектов внешней базы:

  1. Использование явного метода Получить(Индекс) или Get(Index):
    
    КоличествоРеквизитов = ВнешнийОбъект.Метаданные().Реквизиты.Количество();
    
    Для Сч = 0 По КоличествоРеквизитов - 1 Цикл
        Реквизит = ВнешнийОбъект.Метаданные().Реквизиты.Получить(Сч);
        ИмяРеквизита = Реквизит.Имя;
        // Дальнейшая обработка реквизита
    КонецЦикла;
    
  2. Использование универсального цикла Для Каждого:
    
    Для Каждого Реквизит Из ВнешнийОбъект.Метаданные().Реквизиты Цикл
        ИмяРеквизита = Реквизит.Имя;
        // Дальнейшая обработка реквизита
    КонецЦикла;
    

3. Универсальный перенос реквизитов и значений между базами

Рассмотрим, как правильно сопоставлять и переносить реквизиты, если состав метаданных в базах различается (в приемнике реквизитов меньше или они имеют другой порядок).

Если требуется перенести простые типы данных (числа, строки, даты, булево) по совпадающим именам, нет необходимости вручную перебирать метаданные. Функция платформы ЗаполнитьЗначенияСвойств прекрасно работает с COM-объектами:


// Автоматически скопирует все совпадающие по имени реквизиты простых типов
ЗаполнитьЗначенияСвойств(ОбъектПриемник, COMОбъектИсточник);

Если же требуется выборочный перенос с проверкой типов или сопоставлением ссылок, разберем по шагам правильный алгоритм динамического сопоставления:


&НаСервере
Процедура ПеренестиРеквизиты(ВнешняяБаза, COMИсточник, ОбъектПриемник)
    
    МетаданныеПриемника = ОбъектПриемник.Метаданные();
    МетаданныеИсточника = COMИсточник.Метаданные();
    
    Для Каждого РеквизитПриемника Из МетаданныеПриемника.Реквизиты Цикл
        
        ИмяРеквизита = РеквизитПриемника.Имя;
        
        // Проверяем наличие реквизита в источнике
        РеквизитИсточника = МетаданныеИсточника.Реквизиты.Найти(ИмяРеквизита);
        
        Если РеквизитИсточника <> Неопределено Тогда
            
            // Динамически получаем значение из COM-источника
            ЗначениеИсточника = COMИсточник[ИмяРеквизита];
            
            // Простые типы переносим напрямую
            Если ТипЗнч(ЗначениеИсточника) = Тип("Строка") 
                Или ТипЗнч(ЗначениеИсточника) = Тип("Число")
                Или ТипЗнч(ЗначениеИсточника) = Тип("Дата")
                Или ТипЗнч(ЗначениеИсточника) = Тип("Булево") Тогда
                
                ОбъектПриемник[ИмяРеквизита] = ЗначениеИсточника;
                
            Иначе
                // Ссылочные типы переносятся через строковый GUID
                Если ЗначениеЗаполнено(ЗначениеИсточника) Тогда
                    СтрокаГУИД = Строка(ЗначениеИсточника.УникальныйИдентификатор());
                    УидПриемника = Новый УникальныйИдентификатор(СтрокаГУИД);
                    
                    // Пример поиска элемента в справочнике базы-приемника по GUID
                    // ОбъектПриемник[ИмяРеквизита] = Справочники[ИмяСправочника].ПолучитьСсылку(УидПриемника);
                КонецЕсли;
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

4. Важные особенности и ограничения COM-соединения

При проектировании механизмов обмена на базе технологии COM следует учитывать ряд технических нюансов платформы:

  1. Разрядность процессов (32 и 64 бита): Если сервер 1С работает в 64-битном режиме, а библиотека COMConnector зарегистрирована как 32-битная, прямое подключение вызовет ошибку отсутствия интерфейса. В таком случае требуется выносить COM-коннектор в отдельное приложение через «Службы компонентов» (dcomcnfg).
  2. Потребление лицензий: Каждое активное подключение через COMConnector.Connect() занимает отдельную клиентскую лицензию платформы 1С на все время активности сеанса.
  3. Кроссплатформенность: Технология COM является частью операционной системы Windows. Если сервер 1С развернут на базе ОС Linux, использование COM-соединений невозможно. В качестве современной альтернативы рекомендуется использовать HTTP-сервисы (REST API), Web-сервисы (SOAP) или обмен пакетами в формате EnterpriseData / XML.
← На главную