При работе с внешним оборудованием или сложными программными комплексами через COM-интерфейс программисты 1С часто сталкиваются с ситуацией, когда основной объект создается без проблем, но получить доступ к его дочерним классам или передать их в качестве параметров методов не удается. Типичный пример — работа с топливораздаточными колонками через систему Gilbarco PSS, где для вызова метода требуется передать объект специфического типа, который невозможно создать стандартной командой Новый COMОбъект.
В этой статье мы подробно разберем, почему возникает такая проблема, как работают механизмы раннего и позднего связывания и какими способами можно инициализировать нужные классы для успешной работы в среде 1С.
Для начала выясним, почему в средах разработки вроде Visual Basic (VB) или Delphi работа с такими объектами происходит «автоматически», а в 1С возникает ошибка несоответствия типов. Ключевое различие заключается в способе обращения к COM-серверу:
References, IDE считывает файл описания типов (Type Library — TLB). Программа заранее знает структуру всех классов, их методы и адреса в памяти. Это позволяет создавать объекты типов, которые даже не зарегистрированы в реестре Windows как отдельные сущности (они помечены как non-creatable).IDispatch. Чтобы создать объект, 1С ищет его идентификатор (ProgID) в реестре. Если дочерний класс (например, PriceGroup) не является самостоятельным приложением и не прописан в реестре отдельно от родителя, 1С просто «не видит», как его создать.Рассмотрим подробнее пути решения этой задачи, от простых к более сложным.
Прежде чем приступать к написанию программных «прослоек», проанализируем структуру самого родительского объекта. Очень часто разработчики COM-серверов предусматривают специальные методы для порождения дочерних объектов. Внимательно изучите документацию или воспользуйтесь обозревателем объектов (Object Browser) в VB.
Попробуйте найти следующие элементы:
CreatePriceGroup(), GetNewObject() или InitChild(). Если такой метод существует, вызов в 1С будет выглядеть так:
// Попытка получить объект через фабричный метод родителя
РодительскийОбъект = Новый COMОбъект("PSS.Forecourt");
ДочернийОбъект = РодительскийОбъект.CreatePriceGroup();
// Теперь объект создан внутри самого COM-сервера и готов к передаче
РодительскийОбъект.GetPrice(ДочернийОбъект);
// Получение объекта из внутренней коллекции
ДочернийОбъект = РодительскийОбъект.PriceGroups.Add();
РодительскийОбъект.GetPrice(ДочернийОбъект);
Если прямое создание в 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", РодительскийОбъект);
Если ни один из вышеперечисленных методов не помог, значит, объект действительно жестко ориентирован на раннее связывание. Единственный надежный способ в этом случае — написать небольшую «обертку» на языке, который поддерживает TypeLib (например, C# или VB.NET).
Разберем этот процесс по шагам:
References.Пример кода на 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-объекта, выполните следующие действия:
Object Browser.Использование прослойки позволяет скрыть сложности реализации COM-интерфейсов и предоставить 1С простой и понятный программный интерфейс для работы с любым оборудованием.