При самостоятельной разработке внешних компонент и драйверов подключаемого оборудования по технологии Native API на C++ разработчики регулярно сталкиваются с двумя неочевидными сложностями. Во-первых, возникает вопрос реализации методов стандартов БПО (Библиотеки подключаемого оборудования), таких как ПолучитьОписание (GetDescription), где требуется вернуть сразу несколько выходных параметров разного типа. Во-вторых, часто возникает проблема с вызовом методов на русском языке, когда платформа 1С сообщает, что метод не найден, а в отладчике C++ вместо русских букв отображаются искаженные символы. Разберем обе эти проблемы и пошагово реализуем их решение.
Проанализируем механику вызова методов внешних компонент в 1С. По стандарту разработки драйверов подключаемого оборудования метод ПолучитьОписание принимает семь параметров по ссылке (выходные параметры): наименование драйвера, описание, тип оборудования, версия стандарта и другие данные.
Посмотрим на типовую сигнатуру вызова метода в интерфейсе ILanguageExtender на C++:
virtual bool CallAsFunc(const long lMethodNum,
tVariant* pvarRetValue,
tVariant* paParams,
const long lSizeArray);
Типичное заблуждение заключается в попытке создать сложную структуру или упаковать все семь параметров в возвращаемое значение pvarRetValue. В архитектуре Native API платформа 1С передает аргументы по ссылке:
pvarRetValue используется только для возврата результата выполнения функции. В него передается логическое значение (тип VTYPE_BOOL): True, если операция выполнена успешно, или False, если метод не поддерживается или завершился с ошибкой.paParams представляет собой массив структур tVariant, размер которого передается в lSizeArray. Если в описании метода параметры помечены как выходные (out-параметры), компонента должна модифицировать значения непосредственно в ячейках массива paParams[0] ... paParams[6].Разберем, как выглядит вызов такого метода в коде 1С:
Наименование = "";
Описание = "";
ТипОборудования = "";
ВерсияФормата = 0;
// Вызываем метод с передачей переменных по ссылке
Если ОбъектДрайвера.ПолучитьОписание(Наименование, Описание, ТипОборудования, ВерсияФормата) Тогда
// Переменные уже содержат данные, заполненные драйвером
КонецЕсли;
Рассмотрим правила заполнения значений в paParams. При передаче простых типов (например, целых чисел или логических значений) достаточно указать тип в поле vt и присвоить значение. Однако при передаче строк критически важно соблюдать дисциплину управления памятью 1С.
Если выделить память под возвращаемую строку стандартными функциями C++ (такими как malloc или new), платформа 1С аварийно завершит работу (Access Violation / Crash) в момент освобождения переданного значения. Память для строковых параметров структуры tVariant обязательно должна выделяться через менеджер памяти платформы IMemoryManager, полученный в методе SetMemManager.
Посмотрим на практический пример реализации метода GetDescription в функции CallAsFunc:
// m_iMemory - указатель на IMemoryManager, сохраненный при инициализации
if (lMethodNum == METHOD_GET_DESCRIPTION)
{
// 1. Заполняем строковый параметр paParams[0] - Наименование
const wchar_t* driverName = L"MyLabelPrinterDriver";
size_t len = wcslen(driverName);
paParams[0].vt = VTYPE_PWSTR;
paParams[0].wstrLen = (uint32_t)len;
// Выделяем память через менеджер платформы 1С
if (m_iMemory->AllocMemory((void**)&paParams[0].pwstrVal, (len + 1) * sizeof(wchar_t)))
{
wcscpy(paParams[0].pwstrVal, driverName);
}
// 2. Заполняем числовой параметр (например, версия требований)
paParams[3].vt = VTYPE_I4;
paParams[3].lVal = 2001; // Версия 2.1
// 3. Возвращаем результат успешности вызова функции
pvarRetValue->vt = VTYPE_BOOL;
pvarRetValue->bVal = true;
return true;
}
Разберем вторую частую ошибку: проект собирается без ошибок, методы на английском языке (например, Open, Close) успешно вызываются из 1С, но при вызове русскоязычных синонимов (Включить, ПолучитьОписание) платформа сообщает, что метод или свойство не найдено.
Выясним причину этой неполадки. При отладке библиотеки в Visual Studio в строковых массивах русских имен методов (например, g_PropNamesRu или g_MethodNamesRu) видны искаженные символы (кракозябры). Это происходит из-за несовпадения кодировки исходных файлов исходного кода C++ и ожиданий компилятора MSVC.
Исходные файлы демонстрационных шаблонов с диска ИТС нередко сохранены в кодировке UTF-8 без специальной сигнатуры порядка байтов (BOM). Компилятор Microsoft Visual C++ в этом случае трактует исходный файл в соответствии с текущей системной ANSI-кодовой страницей (Windows-1251), что приводит к некорректной генерации строковых литералов wchar_t.
Для устранения проблемы воспользуемся одним из двух проверенных способов:
AddInNative.cpp) в текстовом редакторе (Notepad++, Visual Studio Code или самом Visual Studio) и выполним команду «Сохранить с кодировкой» (Save with Encoding), выбрав формат UTF-8 with BOM (Подпись UTF-8). После перекомпиляции строковые константы L"..." сформируются корректно.C/C++ -> Командная строка (Command Line) и добавим ключ компиляции /utf-8. Этот параметр указывает компилятору трактовать все файлы как UTF-8 независимо от наличия метки BOM.После реализации логики методов и устранения проблем с кодировкой подготовим драйвер к установке в типовые конфигурации 1С. Для того чтобы конфигурация смогла распознать внешнюю компоненту через БПО, выполним следующие действия:
.so сборки).info.xml, содержащий информацию о версии стандарта, идентификаторе оборудования, типах поддерживаемых устройств и именах загружаемых библиотек.info.xml в единый ZIP-архив без вложенных папок верхнего уровня. Полученный архив загружается в справочник «Драйверы оборудования» 1С штатными средствами интерфейса.Таким образом, для успешного создания драйвера по технологии Native API достаточно корректно заполнять массив входных аргументов paParams с выделением памяти через IMemoryManager и контролировать кодировку исходного кода при сборке проекта.