На предприятии эксплуатируется весовой комплекс для взвешивания железнодорожных вагонов. Исторически работа с ним выполнялась через приложение на FoxPro, и прямой интеграции с  не было. Документация к комплексу отсутствовала, а попытки восстановить протокол обмена через COM-порт не дали результата.

Решением стала разработка внешней компоненты 1С на C++, которая использует существующий DLL-драйвер весового комплекса и транслирует его функции в методы, доступные из 1С.

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

Почему интеграция устаревшего оборудования с 1С - актуальная задача

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

Типичный конфликт:

оборудование и драйвер - “старые”, закрытые, без документации;

учетная система - современная, требует интеграции и надежного обмена данными.

Исходные условия: весовой комплекс и FoxPro-приложение
Весовой комплекс для завешивания ЖД вагонов. Работа с комплексом выполнялась через приложение, написанное на FoxPro.

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

Проблемы при прямой интеграции с 1С

Отсутствует документация к весовому комплексу и протоколу обмена. Поиск информации в интернете результата не дал (нет описаний команд/протокола/SDK). 

Прослушивание COM порта не помогло: 

  • либо обмен шел не в “чистом” виде через COM,

  • либо использовался нестандартный формат/скорость/инициализация,

  • либо взаимодействие шло через драйвер, который скрывал реальный обмен.

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

Формулировка задачи: подключение оборудования к 1С через рабочий драйвер
Разработать механизм интеграции, который:

  • позволяет 1С получать данные с весового комплекса;

  • минимально зависит от неизвестного протокола;

  • использует существующий рабочий драйвер, с которым уже работает FoxPro приложение

Идея решения: использовать уже работающий драйвер
Поскольку FoxPro приложение успешно работало с комплексом, было принято решение:

взять DLL драйвер, который использовался этим приложением, понять, какие функции драйвера вызываются, реализовать внешнюю компоненту 1С на C++, которая будет:

1) подключать DLL,
2) вызывать нужные функции,
3) отдавать данные в 1С в удобном виде.

Анализ FoxPro-приложения: выявление нужных функций драйвера
Был выполнен анализ исходного кода FoxPro приложения для выявления:

  • мест, где происходит инициализация весового комплекса;

  • вызовов DLL;

  • последовательности действий: открыть/настроить/получить вес/закрыть.

Был составлен перечень функций драйвера (методов), которые обеспечивали работу комплекса:

Connect_VATS (подключение к комплксу);

Read_VATS (чтение данных с комплекса);

Disconnect_VATS (отключение).

Главное: стало понятно какие именно вызовы нужно “поднять” на уровень 1С.

Выбор технологии: внешняя компонента 1С на C++
Варианты интеграции могли быть такими:

  • прямое чтение COM порта из 1С;

  • внешняя компонента 1С;

  • замена оборудования.

Учитывая отсутствие документации и наличие рабочей DLL, оптимальным стал путь внешней компоненты:

- компонента может напрямую работать с WinAPI и DLL;
- можно аккуратно контролировать загрузку/выгрузку и типы данных;
- 1С получает простой API: «подключись» → «дай вес» → «отключись»

Основа проекта
За основу был взят шаблон внешней компоненты, скачанный с сайта ИТС (типовой каркас проекта).

Это снижает риски, потому что:

  • уже реализованы обязательные точки входа и структура;

  • проще правильно “подружить” C++ и интерфейсы 1С;

  • ускоряется разработка и отладка.

Архитектура решения: «мост» между 1С и весовым комплексом
Общая схема 1С (конфигурация / обработка) → вызывает методы компоненты

Внешняя компонента (C++) → динамически подключает DLL драйвера → вызывает функции драйвера

DLL драйвера → общается с весовым комплексом

Весовой комплекс → возвращает измерения/статусы

Принцип “трансляции” методов
Компонента выступает как “адаптер”: в драйвере - функции с низкоуровневыми параметрами (указатели, буферы, коды ошибок);
в 1С - понятные методы и результаты (число, строка, структура, признак ошибки).

Подключение драйвера: почему DLL сохраняется во временный каталог
Требование к развертыванию
Чтобы упростить эксплуатацию и избежать ручной настройки на рабочих местах, выбран подход:

Подключение DLL и динамическая загрузка в C++

ДвоичныеДанные = ПолучитьОбщийМакет("ДрайверЖДВесов");
    АдресДвоичныхДанных = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресДвоичныхДанных);
    ДвоичныеДанные.Записать(ПутьКДрайверу);

Путь к DLL передается в компоненту.
Компонента загружает DLL и начинает работать

ОчиститьСообщения();

        Весы = Новый("AddIn.Weigher.WeightData");

        ПараметрыПодключения = НастройкиПодключенияOnComm(Склад);

        Если ПараметрыПодключения = Неопределено Тогда

        ТекстСообщения = НСтр("ru = 'Для данного склада не найдено настроек подключения для весов'");
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения);
        Возврат;
    КонецЕсли;

        Весы.НомерПорта = ПараметрыПодключения.CommPort;
    Весы.ИмяФайла = ПутьКДрайверу;
        Весы.ПолучитьДанныеВеса();
        Если Весы.Статус = -1 Тогда
        ТекстОшибки = НСтр("ru = 'Ошибка подключения драйвера весов'");
    ИначеЕсли Весы.Статус = -2 Тогда
        ТекстОшибки = НСтр("ru = 'Ошибка работы драйвера весов'");
    ИначеЕсли Весы.Статус = -3 Тогда
        ТекстОшибки = НСтр("ru = 'Ошибка подключения к весам'");
    ИначеЕсли Весы.Статус = 1 Тогда
        ТекстОшибки = НСтр("ru = 'Груз на весах вне диапазона'");
    ИначеЕсли Весы.Статус = 2 Тогда
        ТекстОшибки = НСтр("ru = 'Вес не стабилен'");
    ИначеЕсли Весы.Статус = 8 Тогда
        ТекстОшибки = НСтр("ru = 'Таймаут по связи'");
    КонецЕсли;
        Если ЗначениеЗаполнено(ТекстОшибки)Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстОшибки);
        Возврат;
    КонецЕсли;

        Вес = Весы.ВесБрутто;

Как это реализуется на стороне C++
Технически (в общем виде) применяется динамическая загрузка:

  • загрузить библиотеку по пути (аналог LoadLibrary);

  • получить адреса нужных функций (аналог GetProcAddress);

  • вызывать их, соблюдая соглашение о вызовах и типы параметров;

  • при завершении корректно выгрузить библиотеку.

bool CAddInNative::CallAsProc(const long lMethodNum,
                    tVariant* paParams, const long lSizeArray)
{
     HMODULE hDLL = LoadLibraryW(FileName);
        if (!hDLL) {
         Status = -1;
         return true;
     }

    // Получаем адреса функций из DLL
    typedef int (WINAPI Connect_VATSPROC)(int);
    typedef int (WINAPI Read_VATSPROC)(double&, double&, long&);
    typedef void (WINAPI Disconnect_VATSPROC)();

    auto pConnect_VATS = (Connect_VATSPROC*)::GetProcAddress(hDLL, "Connect_VATS");
    auto pRead_VATS = (Read_VATSPROC*)::GetProcAddress(hDLL, "Read_VATS");
    auto pDisconnect_VATS = (Disconnect_VATSPROC*)::GetProcAddress(hDLL, "Disconnect_VATS");

   if (!pConnect_VATS !pRead_VATS !pDisconnect_VATS) {
        FreeLibrary(hDLL);
        Status = -2;
        return true;
    }

    pDisconnect_VATS();

    // Соединяемся с устройством
    if (pConnect_VATS(PortNumber) == 0) { // Успешное соединение возвращает ненулевое значение
        pDisconnect_VATS();
        FreeLibrary(hDLL);
        Status = -3;
        return true;
    }

    long W_Status = 0l;

    // Читаем значения с весов
    pRead_VATS(Brutto, Tara, W_Status);

    Status = static_cast<int>(W_Status);

    pDisconnect_VATS();
    FreeLibrary(hDLL);

    return true; 
}

Реализация API компоненты для 1С и обработка ошибок
Экспортируемые методы (логика)
Компонента предоставляет минимально необходимый набор:

  • Инициализация/подключение: загрузка DLL, подготовка к работе, настройка порта.

  • Получение данных: чтение веса, статуса стабильности.

  • Завершение: закрытие сеанса, освобождение ресурсов, выгрузка DLL.

Ошибки и диагностика
Так как драйвер “чужой” и документации нет, критично:

  • возвращать в 1С коды ошибок и читаемые сообщения;

  • логировать ключевые события: загрузка DLL, успех/неуспех получения адресов функций, ответы драйвера.

Практический результат: эксплуатация становится управляемой - при сбое есть что анализировать, а не “просто не работает”.

Результаты внедрения и практическая ценность
В результате создана внешняя компонента на C++, которая:

  • обеспечивает работу 1С с весовым комплексом без необходимости знать внутренний протокол;

  • использует проверенный в эксплуатации драйвер;

  • предоставляет в 1С понятный интерфейс получения данных взвешивания;

  • упрощает развертывание за счет загрузки DLL по пути (через временный каталог).

Фактически, предприятие получило “мост” между современным учетом в 1С и устаревшим, но рабочим оборудованием.

Данный кейс показывает практический путь интеграции с устаревшим оборудованием при отсутствии документации: вместо попыток восстановить протокол на уровне порта был использован работающий драйвер и проанализирован код существующего FoxPro решения. 

На базе шаблона ИТС разработана внешняя компонента 1С на C++, которая динамически подключает DLL драйвера и транслирует его методы в удобные вызовы 1С.

Это позволило обеспечить надежное получение веса в 1С и сохранить работоспособность производственного процесса без замены оборудования.