Как создать дочерний COM-объект в 1С, если он не инициализируется напрямую

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

При работе с внешним оборудованием или сложными программными комплексами через COM-интерфейс программисты 1С часто сталкиваются с ситуацией, когда основной объект создается без проблем, но получить доступ к его дочерним классам или передать их в качестве параметров методов не удается. Типичный пример — работа с топливораздаточными колонками через систему Gilbarco PSS, где для вызова метода требуется передать объект специфического типа, который невозможно создать стандартной командой Новый COMОбъект.

В этой статье мы подробно разберем, почему возникает такая проблема, как работают механизмы раннего и позднего связывания и какими способами можно инициализировать нужные классы для успешной работы в среде 1С.

Проанализируем причину проблемы: Раннее vs Позднее связывание

Для начала выясним, почему в средах разработки вроде Visual Basic (VB) или Delphi работа с такими объектами происходит «автоматически», а в 1С возникает ошибка несоответствия типов. Ключевое различие заключается в способе обращения к COM-серверу:

  1. Раннее связывание (Early Binding): Используется в компилируемых языках. При подключении библиотеки через References, IDE считывает файл описания типов (Type Library — TLB). Программа заранее знает структуру всех классов, их методы и адреса в памяти. Это позволяет создавать объекты типов, которые даже не зарегистрированы в реестре Windows как отдельные сущности (они помечены как non-creatable).
  2. Позднее связывание (Late Binding): Используется в 1С. Система обращается к объекту через универсальный интерфейс IDispatch. Чтобы создать объект, 1С ищет его идентификатор (ProgID) в реестре. Если дочерний класс (например, PriceGroup) не является самостоятельным приложением и не прописан в реестре отдельно от родителя, 1С просто «не видит», как его создать.

Рассмотрим подробнее пути решения этой задачи, от простых к более сложным.

Решение 1: Поиск методов-фабрик и коллекций

Прежде чем приступать к написанию программных «прослоек», проанализируем структуру самого родительского объекта. Очень часто разработчики COM-серверов предусматривают специальные методы для порождения дочерних объектов. Внимательно изучите документацию или воспользуйтесь обозревателем объектов (Object Browser) в VB.

Попробуйте найти следующие элементы:


// Попытка получить объект через фабричный метод родителя
РодительскийОбъект = Новый COMОбъект("PSS.Forecourt");
ДочернийОбъект = РодительскийОбъект.CreatePriceGroup(); 
// Теперь объект создан внутри самого COM-сервера и готов к передаче
РодительскийОбъект.GetPrice(ДочернийОбъект);

// Получение объекта из внутренней коллекции
ДочернийОбъект = РодительскийОбъект.PriceGroups.Add();
РодительскийОбъект.GetPrice(ДочернийОбъект);

Решение 2: Использование VBScript как промежуточного звена

Если прямое создание в 1С невозможно, можно попробовать делегировать инициализацию скриптовому движку Windows, который иногда более гибко работает с типами IDispatch. Рассмотрим вариант использования MSScriptControl.ScriptControl.

Этот способ поможет, если объект позволяет создание через внутренние механизмы скриптов, но 1С блокирует передачу параметров из-за строгой проверки типов Variant.


Скрипт = Новый COMОбъект("MSScriptControl.ScriptControl");
Скрипт.Language = "VBScript";
Скрипт.AddCode("
|Function GetProcessedObject(parent)
|  Dim child
|  ' Здесь логика работы на языке VBScript
|  Set child = parent.CreateSomething() ' Если это доступно
|  parent.GetPrice child
|  Set GetProcessedObject = child
|End Function
|");

Результат = Скрипт.Run("GetProcessedObject", РодительскийОбъект);

Решение 3: Создание внешней компоненты-обертки (Wrapper)

Если ни один из вышеперечисленных методов не помог, значит, объект действительно жестко ориентирован на раннее связывание. Единственный надежный способ в этом случае — написать небольшую «обертку» на языке, который поддерживает TypeLib (например, C# или VB.NET).

Разберем этот процесс по шагам:

  1. Создайте проект библиотеки классов (.NET Class Library) в Visual Studio.
  2. Подключите COM-библиотеку (например, PSS 5000) через References.
  3. Напишите публичный класс, который будет выполнять роль моста.

Пример кода на C# для создания такой обертки:


using System;
using System.Runtime.InteropServices;
using PSSLibrary; // Имя вашей библиотеки

namespace PSSWrapper
{
    [ComVisible(true)]
    [Guid("ВАШ-GUID-ЗДЕСЬ")]
    public class PSSHelper
    {
        public object CreatePriceGroup()
        {
            // Здесь используется раннее связывание, доступное в C#
            // Мы создаем объект, который 1С создать не может
            return new PriceGroup();
        }
    }
}

После компиляции и регистрации этой библиотеки (через regasm), в 1С вы сможете работать следующим образом:


// Создаем нашу обертку
Помощник = Новый COMОбъект("PSSWrapper.PSSHelper");

// Получаем через нее нужный дочерний объект
НужныйТипПараметра = Помощник.CreatePriceGroup();

// Используем его в основном объекте
Forecourt = Новый COMОбъект("PSS.Forecourt");
Forecourt.GetPrice(НужныйТипПараметра);

Важные нюансы передачи параметров по ссылке

Проанализируем ситуацию, описанную в исходном вопросе: метод GetPrice(PriceGroupParam) принимает ссылку и заполняет её данными. В 1С при работе с COM-объектами параметры передаются по значению, если не указано иное. Однако, если передаваемый объект является типом IDispatch (COM-объектом), то передается указатель на этот объект.

Важный момент: Если COM-сервер ожидает инициализированный объект определенного интерфейса, передача Неопределено или пустого значения вызовет ошибку "Несоответствие типов". Именно поэтому создание «пустой заготовки» через обертку или фабричный метод является критически важным шагом.

Выводы

Столкнувшись с невозможностью создания дочернего класса COM-объекта, выполните следующие действия:

  1. Проверьте наличие фабричных методов в родительском объекте через Object Browser.
  2. Попробуйте обратиться к коллекциям родительского объекта.
  3. Если объект требует строгого раннего связывания, разработайте внешнюю компоненту-обертку на C# или C++. Это самый стабильный и профессиональный путь решения подобных интеграционных задач.

Использование прослойки позволяет скрыть сложности реализации COM-интерфейсов и предоставить 1С простой и понятный программный интерфейс для работы с любым оборудованием.

← На главную