Как инициировать выполнение кода 1С из внешней компоненты?

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

При разработке внешних компонент (DLL) часто возникает задача «обратной связи»: когда не 1С вызывает метод компоненты, а сама компонента должна инициировать выполнение какого-либо алгоритма в 1С. Это необходимо для работы с торговым оборудованием (сканеры штрихкодов, весы), при получении данных из сокетов или при завершении длительных фоновых вычислений в библиотеке. В данной статье мы подробно разберем, как заставить 1С выполнить ваш код, используя интерфейсы COM и Native API.

Способ 1: Использование механизма внешних событий (IAsyncEvent)

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

Для реализации этого механизма в вашей ВК (написанной на C++) необходимо воспользоваться интерфейсом IAsyncEvent. Рассмотрим, как это выглядит на практике. Сначала мы получаем указатель на интерфейс при инициализации компоненты, а затем вызываем метод ExternalEvent.


// Пример на C++
if (pIAsyncEvent) {
    // Устанавливаем глубину буфера событий
    pIAsyncEvent->SetEventBufferDepth(2);  
    
    // Генерируем событие: Источник, Сообщение, Данные
    pIAsyncEvent->ExternalEvent(L"MyComponentSource", L"DataReceived", L"Значение_из_DLL");
}

Проанализируем параметры метода ExternalEvent:

  1. Источник (Source): Строка, позволяющая 1С понять, какая именно компонента прислала данные.
  2. Сообщение (Message): Код события или команда.
  3. Данные (Data): Сама полезная нагрузка (строка).

Теперь посмотрим на сторону 1С. Чтобы поймать это событие, в форме или в модуле обычного приложения (или в модуле управляемого приложения) должна быть определена процедура ОбработкаВнешнегоСобытия. Разберем пример кода на языке 1С:


Процедура ОбработкаВнешнегоСобытия(Источник, Сообщение, Данные)
    Если Источник = "MyComponentSource" Тогда
        Если Сообщение = "DataReceived" Тогда
            Сообщить("Получены данные из DLL: " + Данные);
            // Здесь можно вызвать любую процедуру 1С
            ВыполнитьНужноеДействие(Данные);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Важное замечание: Главное преимущество этого способа — потокобезопасность. Вы можете вызывать ExternalEvent из любого фонового потока вашей DLL. 1С сама поставит событие в очередь и выполнит его в основном интерфейсном потоке, когда будет готова.

Способ 2: Использование AppDispatch для прямого вызова методов

Если вам недостаточно просто отправить событие и вы хотите напрямую вызывать методы глобального контекста 1С или создавать объекты 1С (например, Запрос или ТаблицаЗначений) прямо из кода библиотеки, вам понадобится свойство AppDispatch.

При подключении компоненты через метод Init, платформа передает указатель pConnection (типа IDispatch). Из этого указателя можно извлечь контекст приложения. Рассмотрим, как это реализовать на Delphi:


// Сохраняем переданный коннект
var
  PConnect: IDispatch;
  AppDispatch: OleVariant;

// В процедуре Init сохраняем указатель
PConnect := pConnection;

// Позже, например в CallAsFunc, получаем доступ к приложению
AppDispatch := OleVariant(PConnect).AppDispatch;

Имея AppDispatch, мы можем обращаться к 1С так же, как если бы мы работали через COM-соединение. Выясним, какие возможности это открывает:


// Создание объекта 1С прямо из DLL
var
  Запрос: OleVariant;
begin
  Запрос := AppDispatch.NewObject('Запрос');
  Запрос.Текст := 'ВЫБРАТЬ ПЕРВЫЕ 1 Наименование ИЗ Справочник.Номенклатура';
  // ... выполнение запроса
end;

Также вы можете вызвать экспортную функцию из общего модуля 1С. Для этого в 1С создайте общий модуль (например, ВзаимодействиеСВК) и отметьте галки «Глобальный» и «Сервер/Клиент». Напишите там вспомогательную функцию для выполнения произвольного кода:


// В общем модуле 1С
Функция ИсполнитьКодИзВК(ТекстКода) Экспорт
    Попытка
        Выполнить(ТекстКода);
        Возврат "ОК";
    Исключение
        Возврат ОписаниеОшибки();
    КонецПопытки;
КонецФункции

Теперь из кода DLL вы сможете вызвать эту функцию через AppDispatch.ИсполнитьКодИзВК("Сообщить('Привет из DLL!')"). Это дает практически безграничную власть над системой, но требует осторожности.

Особенности работы на стороне сервера (Threading и контекст)

Проанализируем ситуацию, когда компонента работает на сервере в многопользовательском режиме. Здесь возникают нюансы, которые могут привести к нестабильности:

  1. Глобальный контекст: AppDispatch на сервере может «не видеть» некоторые методы, доступные только на клиенте (например, методы работы с формами).
  2. Потоки: Если ваша ВК создает несколько экземпляров, убедитесь, что в коде библиотеки установлены правильные флаги блокировки общих ресурсов. В Delphi секция инициализации должна содержать IsMultiThread := True;.
  3. Разрядность: Помните, что 32-битная DLL не загрузится в 64-битный рабочий процесс сервера 1С.

Сравнение подходов: что выбрать?

Рассмотрим подробнее, какой метод лучше подходит под ваши задачи:

Внешние события (ExternalEvent):

Прямой вызов (AppDispatch):

Рекомендации по реализации

Посмотрим на практический совет: если ваша задача — просто уведомить 1С о событии (например, «карта считана» или «файл загружен»), всегда используйте ExternalEvent. Это гарантирует, что основной поток 1С обработает ваше сообщение корректно в рамках своего жизненного цикла.

Если же вы строите сложную интеграцию, где DLL должна выступать в роли «хозяина», управляющего логикой 1С, используйте AppDispatch. В этом случае полезно реализовать в 1С специальный «шлюз» — экспортную функцию в глобальном модуле, которая будет принимать команды от ВК, проверять их на безопасность и выполнять.

В современных версиях 8.3 (особенно при работе в Linux или через веб-клиент) рекомендуется переходить на Native API. В нем вместо IDispatch используется интерфейс IAddInDefBase, но принцип генерации внешних событий остается таким же простым и эффективным.

← На главную