Как вызывать методы объектов 1С и передавать Таблицу Значений из внешней компоненты на C++

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

Разработка внешних компонент (ВК) для 1С 7.7 — это мощный инструмент, позволяющий расширить функционал системы за счет низкоуровневого программирования на C++. Однако новички часто сталкиваются с трудностями при попытке «подружить» мир C++ и внутренние объекты 1С, такие как ТаблицаЗначений. Разберем подробно, как организовать это взаимодействие, используя технологию COM и интерфейс IDispatch.

Основы взаимодействия: интерфейс IDispatch

Для того чтобы внешняя компонента могла «общаться» с 1С, она должна использовать механизмы автоматизации COM. Основным инструментом здесь выступает интерфейс IDispatch. Проанализируем ситуацию: когда вы подключаете ВК, 1С передает ей указатель на свое окружение. В методе Init вашей компоненты вы получаете объект pConnection. Это и есть ваш «мостик» в мир 1С.

Многие ошибочно полагают, что передать сложные объекты вроде ТаблицаЗначений в ВК невозможно. На самом деле, хотя C++ не знает внутренней структуры класса 1С, он может работать с ним как с объектом IDispatch. Это означает, что мы можем запрашивать список методов объекта и вызывать их по идентификаторам (DISPID).

Как вызвать метод 1С через Invoke

Рассмотрим по шагам процесс вызова метода объекта 1С из кода на C++. Допустим, у нас есть объект ТаблицаЗначений, и мы хотим вызвать её метод НоваяСтрока. Посмотрим на алгоритм:

  1. Получение DISPID: Сначала нам нужно узнать числовой идентификатор метода. Для этого используется функция GetIDsOfNames. Мы передаем ей строку "НоваяСтрока", а она возвращает нам DISPID.
  2. Подготовка параметров: Параметры передаются в виде массива структур VARIANT, упакованных в структуру DISPPARAMS. Важно помнить: в COM параметры в массиве располагаются в обратном порядке.
  3. Вызов Invoke: Сама процедура вызова выполняется через метод Invoke, куда передается полученный ранее DISPID, параметры и контекст выполнения.

Пример реализации вызова метода на C++ может выглядеть следующим образом:


HRESULT Call1CMethod(IDispatch* pDisp, LPOLESTR methodName) {
    DISPID dispid;
    // 1. Получаем ID метода по его имени
    HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, &methodName, 1, LOCALE_USER_DEFAULT, &dispid);
    if (FAILED(hr)) return hr;

    // 2. Подготавливаем пустые параметры (если метод их не требует)
    DISPPARAMS params = { NULL, NULL, 0, 0 };
    VARIANT result;
    VariantInit(&result);
    EXCEPINFO excep;
    UINT argErr;

    // 3. Вызываем метод
    hr = pDisp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, &excep, &argErr);
    
    VariantClear(&result);
    return hr;
}

Передача и возврат Таблицы Значений

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

Вариант 1: Заполнение таблицы «на лету»

Вместо того чтобы пытаться «создать» таблицу в C++ и вернуть её, гораздо эффективнее создать пустую ТаблицаЗначений в 1С и передать её в метод вашей ВК как параметр. Внутри C++ кода вы получите её как VARIANT с типом VT_DISPATCH.

Выясним причину, почему это лучше: вам не нужно заботиться о выделении памяти под объект 1С, вы просто используете методы этого объекта (НоваяСтрока, УстановитьЗначение), чтобы наполнить его данными из вашего Recordset ADO. Это избавляет от проблем с типами данных и преобразованием строк.

Вариант 2: Сериализация через ЗначениеВСтроку

Если работа с IDispatch кажется слишком громоздкой, можно воспользоваться встроенными функциями 1С ЗначениеВСтрокуВнутр и ЗначениеИзСтрокиВнутр. Проанализируем этот путь: вы можете передать в ВК строку, представляющую объект, или же ВК может сформировать строку в специальном внутреннем формате 1С и вернуть её. Однако помните, что для больших таблиц этот метод может быть медленным и потреблять много оперативной памяти.

Работа с глобальным контекстом 1С

Иногда требуется создать объект 1С (например, ту же таблицу) непосредственно внутри ВК. Для этого мы можем обратиться к глобальному контексту 1С через переданный при инициализации указатель pConnection. Мы можем вызвать у него метод AppDispatch (или аналогичный в зависимости от реализации интерфейса), чтобы получить доступ к функции СоздатьОбъект.

Разберем пример логики:

  1. Через pConnection вызываем IDispatch::Invoke для функции EvalExpr (ВычислитьВыражение).
  2. Передаем строку "СоздатьОбъект(\"ТаблицаЗначений\")".
  3. В качестве результата Invoke получаем VARIANT, содержащий указатель IDispatch на новую таблицу.

Важные технические нюансы для Visual Studio

При использовании современных версий Visual Studio настоятельно рекомендуем использовать умные указатели ATL, такие как CComPtr<IDispatch> или CComVariant. Это значительно упрощает управление жизненным циклом объектов и предотвращает утечки памяти, которые в 1С 7.7 могут привести к падению системы при частом вызове ВК.

Особое внимание уделите типам данных:

Использование внешних событий для длительных операций

Если ваш запрос через ADO занимает значительное время, выполнение метода ВК заблокирует интерфейс 1С. В этом случае рассмотрим использование интерфейса IAsyncEvent. Вы можете запустить выборку данных в отдельном потоке внутри вашей DLL, а по завершении вызвать метод ExternalEvent. 1С получит уведомление в процедуре ПриВнешнемСобытии, где вы сможете передать, например, путь к сформированному файлу или идентификатор кэшированных данных.

Таким образом, взаимодействие между 1С 7.7 и внешней компонентой на C++ строится на стандартных принципах COM. Использование прямого управления объектами через IDispatch::Invoke является наиболее гибким и производительным способом передачи данных, превосходящим по эффективности передачу строк или простых массивов.

← На главную