При разработке внешних компонент по технологии Native API для работы с торговым оборудованием (например, фискальными регистраторами), разработчики часто сталкиваются с ситуацией, когда параметры, описанные в TableParameters, корректно отображаются в форме настроек 1С, но не передаются в саму компоненту при инициализации. Рассмотрим подробно, как устроен механизм передачи этих данных и что нужно проверить в коде на стороне С++ и на стороне 1С.
Для начала разберем, как 1С:Предприятие (в частности, Библиотека подключаемого оборудования — БПО) взаимодействует с драйвером. Процесс инициализации оборудования сохраненными параметрами происходит не «одним пакетом», а через последовательные вызовы метода УстановитьПараметр (или SetParameter в англоязычной нотации).
Проанализируем типовой код в 1С, который отвечает за подключение устройства. Система обходит коллекцию сохраненных настроек в цикле и для каждого элемента вызывает метод драйвера:
Функция ПодключитьУстройство(ОбъектДрайвера, Параметры, ПараметрыПодключения, ВыходныеПараметры) Экспорт
...
Для Каждого Параметр Из Параметры Цикл
Если Лев(Параметр.Ключ, 2) = "P_" Тогда
ЗначениеПараметра = Параметр.Значение;
ИмяПараметра = Сред(Параметр.Ключ, 3);
// Прямой вызов метода внешней компоненты
ОбъектДрайвера.УстановитьПараметр(ИмяПараметра, ЗначениеПараметра);
КонецЕсли;
КонецЦикла;
...
КонецФункции
Важно понимать, что если в логах вашей компоненты вы видите только параметр EquipmentType, это означает, что цикл в 1С либо не доходит до ваших пользовательских параметров (IP, Password и т.д.), либо компонента отклоняет эти вызовы на этапе сопоставления имен.
Поскольку УстановитьПараметр является методом, а не свойством, в Native API за его обработку отвечает функция CallAsProc. Выясним, как правильно принять и обработать входящие данные.
Когда 1С вызывает ОбъектДрайвера.УстановитьПараметр("IP", "192.168.1.1"), платформа транслирует этот вызов в следующий код С++:
bool CAddInNative::CallAsProc(const long lMethodNum, tVariant* paParams, const long lSizeArray)
{
switch (lMethodNum)
{
case eMethSetParameter:
// Здесь lSizeArray должен быть равен 2
return MethSetParameter(paParams, lSizeArray);
...
}
return true;
}
Обратите внимание на массив paParams. Метод УстановитьПараметр принимает два аргумента:
ИмяПараметра (тип VTYPE_PWSTR) — находится в paParams[0].ЗначениеПараметра (тип зависит от настроек) — находится в paParams[1].Разберем пример реализации MethSetParameter, где мы извлекаем имя и значение:
bool CAddInNative::MethSetParameter(tVariant* paParams, const long lSizeArray)
{
if (lSizeArray < 2) return false;
// 1. Получаем имя параметра
std::wstring propName = paParams[0].pwstrVal;
// 2. Получаем значение параметра (нужно учитывать тип tVariant)
if (paParams[1].vt == VTYPE_PWSTR) {
std::wstring propValue = paParams[1].pwstrVal;
// Сохраняем значение в логике компоненты
} else if (paParams[1].vt == VTYPE_I4) {
long propValue = paParams[1].lVal;
}
return true;
}
Если вы уверены, что код С++ написан верно, но параметры всё равно не поступают, проанализируем следующие моменты:
1. Ошибка в регистрации имен свойств (g_PropNames)
В Native-компоненте есть массив имен свойств g_PropNames и соответствующее ему перечисление (enum Props). Если количество элементов в массиве меньше, чем в перечислении, или нарушен порядок, методы поиска (FindProp, FindMethod) будут возвращать некорректные индексы. Проверьте, что все параметры, которые вы используете, зарегистрированы в компоненте.
2. Кэширование параметров в 1С
1С очень агрессивно кэширует описание драйвера. Если вы добавили новые параметры в XML-описание (GetParameters), но не обновили версию компоненты в справочнике «Драйверы оборудования», 1С может продолжать использовать старую структуру данных. В этом случае в форме настройки новые поля могут появиться (если вы открываете её напрямую), но БПО не будет знать, что их нужно передавать в метод SetParameter.
3. Соответствие типов данных
В XML-описании TableParameters для каждого параметра указывается тип. Если в XML указан тип String, а 1С пытается передать туда объект или неопределенное значение, вызов может не произойти или завершиться ошибкой на стороне платформы. Убедитесь, что типы в XML соответствуют ожидаемым типам в С++.
Для корректной работы с современными версиями БПО компонента должна поддерживать актуальную ревизию интерфейса. Рассмотрим метод GetProperty для InterfaceRevision:
bool CAddInNative::GetPropVal(const long lPropNum, tVariant* pvarPropVal)
{
switch (lPropNum)
{
case ePropInterfaceRevision:
pvarPropVal->vt = VTYPE_I4;
pvarPropVal->lVal = 3001; // Соответствует версии 3.1
return true;
...
}
}
Если ревизия интерфейса указана неверно или не поддерживается вашей версией БПО, платформа может использовать устаревшие механизмы инициализации, которые не предусматривают последовательный вызов SetParameter для всех полей из XML.
Чтобы окончательно выяснить причину, воспользуйтесь следующими шагами:
CallAsProc с указанием номера метода. Если номер метода eMethSetParameter вообще не появляется для ваших параметров, значит, проблема на стороне 1С (параметры не считаны из базы или не инициирован вызов).GetParameters возвращает валидный XML. Любая синтаксическая ошибка в XML приведет к тому, что 1С проигнорирует весь список параметров.ОбъектДрайвера.УстановитьПараметр("Тест", "Значение"). Если этот вызов дойдет до С++, значит инфраструктура компоненты исправна, и проблему нужно искать в настройках БПО.Помните, что параметр EquipmentType передается платформой автоматически в большинстве случаев, поэтому его наличие в логах не является признаком того, что ваша пользовательская таблица параметров обработана успешно. Только корректная регистрация всех методов в g_MethodNames и правильная обработка индексов в CallAsProc гарантируют получение всех настроек.