1С, обмен данными, web-services, RLS, Регистры накопления, СКД и полезности
Содержание
- Страницы
- 17 июл. 2013 г.
- Общее описание
- Порядок создания и подключения внешней компоненты
- Порядок тестирования и отладки
- Варианты работы компоненты
Страницы
17 июл. 2013 г.
Внешняя компонента для 1С на C#
Захотелось мне создать внешнюю компоненту на C#.
Начал собирать информацию:
UPD (2015/01/18): Название "Native API" используемое фирмой 1С, часто путают с внутренней технологией Windows NT API см. Inside the Native API.
Введение
Эта статья дает представление о работе внешних компонент в системе «1С: Предприятие».
Будет показан процесс разработки внешней компоненты для системы «1С: Предприятие» версии 8.2, работающей под управлением ОС семейства Windows с файловым вариантом работы. Такой вариант работы используется в большинстве решений, предназначенных для предприятий малого бизнеса. ВК будет реализована на языке программирования C++.
Внешние компоненты «1C: Предприятие»
«1С: Предприятие» является расширяемой системой. Для расширения функциональных возможностей системы используются внешние компоненты (ВК). С точки зрения разработчика ВК представляет собой некоторый внешний объект, который имеет свойства и методы, а также может генерировать события для обработки системой «1С: Предприятие».
Внешние компоненты можно использовать для решения класса задач, которые сложно или даже невозможно реализовать на встроенном в «1C: Предприятие» языке программирования. В частности, к такому классу можно отнести задачи, требующие низкоуровневого взаимодействия с операционной системой, например, для работы с специфичным оборудованием.
В системе «1С: Предприятие» используются две технологии создания внешних компонент:
- с использованием Native API
- с использованием технологии COM
При заданных ограничениях между двумя вышеозначенными технологиями разница незначительна, поэтому будем рассматривать разработку ВК с использованием Native API. При необходимости, реализованные наработки могут быть применены для разработки ВК с использованием технологии COM, а также, с незначительными доработками, применены для использования в системе «1С: Предприятие» с другими вариантами работы, отличными от файлового режима работы.
Структура ВК
Внешняя компонента системы «1С: Предприятие» представлена в виде DLL-библиотеки. В коде библиотеки описывается класс-наследник IComponentBase. В создаваемом классе должны быть определены методы, отвечающие за реализацию функций внешней компоненты. Более подробно переопределяемые методы будут описаны ниже по ходу изложения материала.
Запуск демонстрационной ВК
Задача:
- Выполнить сборку внешней компоненты, поставляемой с подпиской ИТС и предназначенной для демонстрации основных возможностей механизма внешних компонент в 1С
- Подключить демонстрационную компоненту к конфигурации 1С
- Убедиться в корректной работоспособности заявленных функций
Компиляция
Демонстрационная ВК расположена на диске подписки ИТС в каталоге «/VNCOMP82/example/NativeAPI».
Для сборки демонстрационной ВК будем использовать Microsoft Visual Studio 2008. Другие версии данного продукта не поддерживают используемый формат проекта Visual Studio.
Открываем проект AddInNative. В настройках проекта подключаем каталог с заголовочными файлами, необходимыми для сборки проекта. По умолчанию они располагаются на диске ИТС в каталоге /VNCOMP82/include.
Результатом сборки является файл /bind/AddInNative.dll. Это и есть скомпилированная библиотека для подключения к конфигурации 1С.
Подключение ВК к конфигурации 1С
Создадим пустую конфигурацию 1С.
Ниже приведен код модуля управляемого приложения.
Если при запуске конфигурации 1С не было сообщено об ошибке, то ВК была успешно подключена.
В результате выполнения приведенного кода в глобальной видимости конфигурации появляется объект ДемоКомп, имеющий свойства и методы, которые определены в коде внешней компоненты.
Демонстрация заложенного функционала
Проверим работоспособность демонстрационной ВК. Для этого попробуем установить и прочитать некоторые свойства, вызвать некоторые методы ВК, а также получить и обработать сообщение ВК.
В документации, поставляемой на диске ИТС заявлен следующий функционал демонстрационной ВК:
- Управление состоянием объекта компоненты
Методы: Включить, Выключить
Свойства: Включен - Управлением таймером
Каждую секунду компонента посылает сообщение системе «1C: Предприятие» с параметрами Component, Timer и строкой счетчика системных часов.
Методы: СтартТаймер, СтопТаймер
Свойства: ЕстьТаймер - Метод ПоказатьВСтрокеСтатуса, который отображает в строке статуса текст, переданный методу в качестве параметров
- Метод ЗагрузитьКартинку. Загружает изображение из указанного файла и передает его в систему «1C: Предприятие» в виде двоичных данных.
Убедимся в работоспособности этих функций. Для этого исполним следующий код:
Результат запуска конфигурации приведен на изображении
На панель «Сообщения» выведены результаты вызовов методов ДемоКомп.Выключить() и Демо.Комп.Включить(). Последующие строки на той же панели содержат результаты обработки полученных от ВК сообщений — Источник, Событие и Данные соответственно.
Произвольное имя внешней компоненты
Задача: Изменить имя внешней компоненты на произвольное.
В предыдущем разделе использовался идентификатор AddInNativeExtension, смысл которого не был пояснен. В данном случае AddInNativeExtension — это наименование расширения.
В коде ВК определен метод RegisterExtensionAs, возвращающий системе «1С: Предприятие» имя, которое необходимо для последующей регистрации ВК в системе. Рекомендуется указывать идентификатор, который в известной мере раскрывает суть внешней компоненты.
Приведем полный код метода RegisterExtensionAs с измененным наименованием расширения:
В приведенном примере имя ВК изменено на SomeName. Тогда при подключении ВК необходимо указывать новое имя:
Расширение списка свойств ВК
Задача:
- Изучить реализацию свойств ВК
- Добавить свойство строкового типа, доступное для чтения и записи
- Добавить свойство строкового типа, доступное для чтения и записи, которое хранит тип данных последнего установленного свойства. При установке значения свойства никаких действий не производится
- Убедиться в работоспособности произведенных изменений
Для определения свойств создаваемой компоненты разработчику необходимо реализовать следующие методы в коде библиотеки AddInNative.cpp:
GetNProps
Возвращает количество свойств данного расширения, 0 – при отсутствии свойств
FindProp
Возвращает порядковый номер свойства, имя которого передается в параметрах
GetPropName
Возвращает имя свойства по его порядковому номеру и по переданному идентификатору языка
GetPropVal
Возвращает значение свойства с указанным порядковым номером
SetPropVal
Устанавливает значение свойства с указанным порядковым номером
IsPropReadable
Возвращает флаг флаг возможности чтения свойства с указанным порядковым номером
IsPropWritable
Возвращает флаг флаг возможности записи свойства с указанным порядковым номером
Полное описание методов, включая список параметров подробно описан в документации, поставляемой на диске ИТС.
Рассмотрим реализацию приведенных методов класса CAddInNative.
В демонстрационной ВК определены 2 свойства: Включен и ЕстьТаймер (IsEnabled и IsTimerPresent).
В глобальной области видимости кода библиотеки определено два массива:
которые хранят русское и английское названия свойств. В заголовочном файле AddInNative.h определяется перечисление:
ePropIsEnabled и ePropIsTimerPresent, соответственно имеющие значения 0 и 1 используются для замены порядковых номеров свойств на осмысленные идентификаторы. ePropLast, имеющее значение 2, используется для получения количества свойств (методом GetNProps). Эти имена используются только внутри кода компоненты и недоступны извне.
Методы FindProp и GetPropName осужествляют поиск по массивам g_PropNames и g_PropNamesRu.
Для хранения значения полей в модуле библиотеки у класса CAddInNative определены свойства, которые хранят значение свойств компоненты. Методы GetPropVal и SetPropVal соответственно возвращают и устанавливают значение этих свойств.
Методы IsPropReadable и IsPropWritable и возвращают trure или false, в зависимости от переданного порядкового номера свойства в соответствии с логикой приложения.
Для того, чтобы добавить произвольное свойство необходимо:
- Добавить имя добавляемого свойства в массивы g_PropNames и g_PropNamesRu (файл AddInNative.cpp)
- В перечисление Props (файл AddInNative.h) перед ePropLast добавить имя, однозначно идентифицирующее добавляемое свойство
- Организовать память под хранение значений свойств (завести поля модуля компоненты, хранящие соответствующие значения)
- Внести изменения в методы GetPropVal и SetPropVal для взаимодействия с выделенной на предыдущем шаге памятью
- В соответствии с логикой приложения внести изменения в методы IsPropReadable и IsPropWritable
Пункты 1, 2, 5 не нуждаются в пояснении. С деталями реализации этих шагов можно ознакомиться, изучив приложение к статье.
Дадим названия тестовым свойствам Тест и ПроверкаТипа соответственно. Тогда в результате выполнения пункта 1 имеем:
Перечисление Props будет иметь вид:
Для значительного упрощения кода будем использовать STL C++. В частности, для работы со строками WCHAR, подключим библиотеку wstring.
Для сохранения значения метода Тест, определим в классе CAddInNative в области видимости private поле:
Для передачи строковых параметров между «1С: Предприятие» и внешней компонентов используется менеджер памяти «1С: Предприятие». Рассмотрим его работу подробнее. Для выделения и освобождения памяти соответственно используются функции AllocMemory и FreeMemory, определенные в файле ImemoryManager.h. При необходимости передать системе «1С: Предприятие» строковый параметр, внешняя компонента должна выделить под нее память вызовом функции AllocMemory. Ее прототип выглядит следующим образом:
где pMemory — адрес указателя, в который будет помещен адрес выделенного участка памяти,
ulCountByte — размер выделяемого участка памяти.
Пример выделения памяти под строку:
Для удобства работы с строковыми типами данными опишем функцию wstring_to_p. Она получает в качестве параметра wstring-строку. Результатом функции является заполненная структура tVariant. Код функции:
Тогда соответствующая секция case оператора switch метода GetPropVal примет вид:
Для реализации второго свойства определим поле класса CaddInNative
в котором будем сохранять тип последнего переданного значения. Для этого в метод CaddInNative::SetPropVal добавим команду:
Теперь при запросе чтения значения второго свойства будем возвращать значение last_type, чего требует обозначенное задание.
Проверим работоспособность произведенных изменений.
Для этого приведем внешний вид конфигурации 1С к виду:
В результате запуска получим последовательность сообщений:
3
Вася
Петя
22
Второе и третье сообщения являются результатом чтения свойства, установленного на предыдущем шаге. Первое и второе сообщения содержат код типа последнего установленного свойства. 3 соответствует целочисленному значению, 22 — строковому. Соответствие типов и их кодов устанавливается в файле types.h, который находится на диске ИТС.
Расширение списка методов
Задача:
- Расширить функционал внешней компоненты следующим функционалом:
- Изучить способы реализации методов внешней компоненты
- Добавить метод-функцию Функц1, которая в качестве параметра принимает две строки («Параметр1» и «Параметр2»). В качестве результата возвращается строка вида: «Проверка. Параметр1, Параметр2»
- Убедиться в работоспособности произведенных изменений
Для определения методов создаваемой компоненты разработчику необходимо реализовать следующие методы в коде библиотеки AddInNative:
GetNMethods, FindMethod, GetMethodName
Предназначены для получения соответственно количества методов, поиска номера и имени метода. Аналогичны соответствующим методам для свойств
GetNParams
Возвращает количество параметров метода с указанным порядковым номером; если метод с таким номером отсутствует или не имеет параметров, возвращает 0
GetParamDefValue
Возвращает значение по умолчанию указанного параметра указанного метода
HasRetVal
Возвращает флаг наличия у метода с указанным порядковым номером возвращаемого значения: true для методов с возвращаемым значением и false в противном случае
CallAsProc
Выполняет метод с указанным порядковым номером. Если метод возвращает false, возникает ошибка времени выполнения и выполнение модуля 1С: Предприятия прекращается. Память для массива параметров выделяется и освобождается 1С: Предприятием.
CallAsFunc
Выполняет метод с указанным порядковым номером. Если метод возвращает false, возникает ошибка времени выполнения и выполнение модуля 1С: Предприятия прекращается. Память для массива параметров выделяется 1С: Предприятием. Если возвращаемое значение имеет тип строка или двоичные данные, компонента выделяет память функцией AllocMemory менеджера памяти, записывает туда данные и сохраняет этот адрес в соответствующем поле структуры. 1С: Предприятие освободит эту память вызовом FreeMemory.
Полное описание методов, включая список параметров подробно описан в документации, поставляемой на диске ИТС.
Рассмотрим реализацию описанных выше методов.
В в коде компоненты определены два массива:
Они используются в функциях GetNMethods, FindMethod и GetMethodName, по аналогии с описанием свойств.
Методы GetNParams, GetParamDefValue, HasRetVal реализуют switch, в зависимости от переданных параметров и логики приложения возвращают требуемое значение. Метод HasRetVal в своем коде имеет список только методов, которые могут возвращать результат. Для них он возвращает true. Для всехо стальных методов возвращается false.
Методы CallAsProc и CallAsFunc содержат непосредственно исполняемый код метода.
Для добавления метода, который может вызываться только как функция необходимо произвести следующие изменения в исходном коде внешней компоненты:
- Добавить имя метода в массивы g_MethodNames и g_MethodNamesRu (файл AddInNative.cpp)
- Добавить осмысленный идентефикатор метода в перечисление Methods (файл AddInNative.h)
- Внести изменения в код функции GetNParams в соответствии с логикой программы
- При необходимости внести изменения в код метода GetParamDefValue, если требуется использовать значения по умолчанию параметров метода.
- Внести изменения в функцию HasRetVal
- Внести изменения в логику работы функций CallAsProc или CallAsFunc, поместив туда непосредственно исполняемый код метода
Приведем массивы g_MethodNames и g_MethodNamesRu, а также перечисление Methods к виду:
Отредактируем функцию GetNProps, чтобы она возвращала количество параметров метода «Тест»:
Внесем изменения в функцию CAddInNative::GetParamDefValue:
Благодаря добавленной строке
в случае отсутствия одного или нескольких аргументов соответствующие параметры будут иметь пустое значение (VTYPE_EMPTY). Если необходимо наличие значения по умолчанию для параметра, следует задать его в секции eMethTest оператора switch функции CAddInNative::GetParamDefValue.
Так как метод «Тест» может возвращать значение, необходимо внести изменения в код функции HasRetVal:
И добавим исполняемый код метода в функцию CallAsFunc:
Скомпилируем компоненту и приведем код конфигурации к виду:
После запуска конфигурации получим сообщение: «Привет, Мир!», что говорит о том, что метод отработал успешно.
Таймер
Задача:
- Изучить реализацию таймера в демонстрационной ВК
- Модифицировать метод «СтартТаймер», добавив возможность передавать в параметрах интервал срабатывания таймера (в миллисекундах)
- Убедиться в работоспособности произведенных изменений
В WinAPI для работы со временем можно воспользоваться сообщением WM_TIMER. Данное сообщение будет посылаться вашей программе через интервал времени, который вы зададите при создании таймера.
Для создания таймера используется функция SetTimer:
Операционная система будет посылать сообщение WM_TIMER в программу с интервалом указанным в аргументе nElapse (в миллисекундах). В последнем параметре можно указать функцию, которая будет выполняться при каждом срабатывании таймера. Заголовок этой функции должен выглядеть так (имя может быть любым):
Рассмотрим реализацию таймера в демонстрационной ВК.
Так как мы рассматриваем процесс разработки внешней компоненты для ОС семейства Windows, не будем рассматривать реализацию таймера в других операционных системах. Для ОС GNU/Linux, в частности, реализация будет отличаться синтаксисом функции SetTimer и TimerProc.
В исполняемом коде вызывается метод SetTimer, в который передается функция MyTimerProc:
Идентефикатор созданного таймера помещается в переменную m_uiTimer, чтобы в последствии его можно было отключить.
Функция MyTimerProc выглядит следующим образом:
Суть функции сводится к тому, что вызывается метод ExternalEvent, который посылает сообщение системе «1С: Предприятие».
Для расширения функционала метода СтартТаймер произведем следующие действия:
Модифицируем код метода GetNParams так, чтобы он для метода eMethStartTimer возвращал значение 1:
Приведем код метода CallAsProc к виду:
Теперь проверим работоспособность. Для этого в модуле управляемого приложения конфигурации напишем код:
После запуска конфигурации в программу будут поступать сообщения с интервалом в 2 секунды, что говорит о корректной работе таймера.
Взаимодействие с системой «1С: Предприятие»
Для взаимодействия между внешней компонентой и системой «1С: Предприятие» используются методы класса IAddInDefBase, описанного в файле AddInDefBase.h. Перечислим наиболее часто используемые:
Генерация сообщения об ошибке
wcode, scode — коды ошибки (список кодов ошибок с описанием можно найти на диске ИТС)
source — источник ошибки
descr — описание ошибки
Отправка сообщения системе «1С: Предприятие»
wszSource — источник сообщения
wszMessage — текст сообщения
wszData — передаваемые данные
Перехват сообщения осуществляется процедурой ОбработкаВнешнегоСобытия
Регистрация внешней компоненты в системе «1С: Предприятие»
wszProfileName — имя компоненты.
Этих методов достаточно для полноценного взаимодействия ВК и 1С. Для получения данных внешней компонентой от системы «1С: Предприятие» и наоборот внешняя компонента отправляет специальное сообщение, которое в свою очередь перехватывается системой «1С» и, при необходимости вызывает методы внешней компоненты для обратной передачи данных.
Тип данных tVariant
При обмене данными между внешней компонентой и системой «1С: Предприятие» используется тип данных tVariant. Он описан в файле types.h, который можно найти на диске с ИТС:
Тип tVariant представляет из себя структру, которая включает себя:
- смесь (union), предназначенную непосредственно для хранения данных
- идентификатор типа данных
В общем случае работа с переменными типа tVariant происходит по следующему алгоритму:
- Определение типа данных, которые в данный момент хранятся в переменной
- Обращение к соответствующему полю смеси, для непосредственного доступа к данным
Использование типа tVariant значительно упрощает взаимодействие системы «1С: Предприятие» и внешней компоненты
Общее описание
Внешние компоненты – это сторонние библиотеки, которые подключаются к системе "1С:Предприятие" для расширения ее возможностей. Внешние компоненты используются для решения задач, которые сложно или невозможно реализовать на встроенном языке "1С:Предприятия".
К таким задачам можно отнести:
- подключение торгового оборудования, например, сканера штрихкодов или принтера этикеток;
- обработку большого объема данных, например, код обработки больших текстов во внешней компоненте отработает в разы быстрее аналогичного кода на встроенном языке, и другие.
Внешние компоненты в системе "1С:Предприятие" используются как для сервера (Windows и Linux, 32 или 64 бит), так и для клиента ("тонкий" и веб-клиент).
Порядок создания и подключения внешней компоненты
Создание внешней компоненты
Создание внешней компоненты выполняется в программе Microsoft Visual Studio. В качестве примера рассмотрим создание компоненты, которая вырезает часть изображения для распознавания.
Скачать шаблон внешней компоненты (шаблон разработан для сервера Windows, 32 бит).
Самый простой способ создания компоненты — это заменить нижеперечисленные функции в готовом шаблоне внешней компоненты:
- Присвоить классу C1CGetImageFragment новое имя, например MyAddIn .
- Также пеименовать файлы, например 1CGetImageFragment.h на MyAddIn.h и 1CGetImageFragment.cpp на MyAddIn.cpp .
- В файле MyAddIn.h в перечислении enum Methods указать свои имена перечисления (помимо eVersion). Копировать в буфер обмена
- В массивах строк g_MethodNames и g_MethodNamesRu указать названия своих функций на английском и русском языках. Рекомендуется оставить функцию Версия , в дальнейшем она пригодится для поддержки работы компоненты.
- В строковом литерале g_kClassNames указать свое имя класса, например MyAddIn .
- В функции GetNParams указать число аргументов для своих методов.
- При необходимости в функции GetParamDefValue указать аргументы по умолчанию для своих методов.
- В функции HasRetVal указать, возвращает ли ваша функция значение. Например: Копировать в буфер обмена
- В функции CallAsFunc добавить код одной или нескольких новых функций.
После замены функций необходимо выполнить следующие шаги:
Шаг 1. Скомпилировать компоненту в Release-варианте и получить файл в виде dll-библиотеки, например MyAddIn.dll . Этот файл необходимо разместить рядом с файлом Manifest.xml .
Шаг 2. В файл Manifest.xml необходимо внести следующие изменения:
- вписать название компоненты в поле path=" MyAddIn.dll" ;
- при необходимости изменить разрядность в поле arch="i386" , значение по умолчанию — 32 бит;
- указать операционную систему в поле os="Windows" .
Шаг 3. Файлы MyAddIn.dll и Manifest.xml поместить в zip-архив с произвольным именем, например MyAddIn.zip .
Подключение внешней компоненты
Подключение внешней компоненты выполняется в конфигураторе и состоит из следующих шагов:
Шаг 1. Добавить общий макет с типом ДвоичныеДанные и назвать его, например МойМакет . Далее загрузить в макет файлы из подготовленного архива с внешней компонентой с помощью команды карточки макета Загрузить из файла — MyAddIn.zip .
Шаг 2. Если компонента еще не установлена (метод ПодключитьВнешнююКомпоненту возвращает Ложь ),нужно приступить к установке. Для этого предусмотрен вызов:
После установки компоненты не обходимо перейти к ее подключению.
Шаг 3. Подключение внешней компоненты выполняется в том месте конфигурации, где ее планируется использовать. Пример подключения внешней компоненты можно посмотреть в модуле РаботаСКартинкамиКлиент типовой конфигурации. Пример кода подключения:
Текст МойМакетAddIn — произвольный. Единственное условие — он должен совпадать в приведенных выше вызовах.
Строка AddInNativeExtension — уже указана в шаблоне компоненты ( RegisterExtensionAs ), ее не надо менять.
Переменную МояКомпонен та рекомендуется описать в мод уле управляемого и обычного приложения как Перем МояКомпонента Экспорт .
Шаг 4. Вызов кода внешней компоненты.
Скачать пример внешней компоненты в архиве 1CGetImageFragment.zip . Компонента вырезает часть изображения с заданными координатами и размером и предназначена только для работы в 32-разрядном Windows, в тонком клиенте.
Порядок тестирования и отладки
При написании внешней компоненты как правило возникает необходимость отладки. Самый простой способ отладки – это логирование в текстовый файл.
Более продвинутый способ – отладка в программе Microsoft Visual Studio. Для отладки в Microsoft Visual Studio необходимо:
- Создать компоненту в Debug-варианте, например MyAddIn.pdb .
- Расположить pdb-файл в каталог установки внешних компонент вида C:UsersИмя пользователяAppDataRoaming1C1Cv82ExtCompT ;
- В режиме конфигуратора запустить "тонкий" клиент "1С:Предприятия"( 1cv8c.exe );
- Поставить в конфигураторе точку останова перед вызовом МояКомпонента.МояФункция и дождаться ее срабатывания.
- В Microsoft Visual Studio подключиться отладчиком к 1cv8c.exe .
- В Microsoft Visual Studio создать точку останова.
- В "1С:Предприятии" выполнить вызов МояКомпонента.МояФункция , при этом в Microsoft Visual Studio должна сработать точка останова.
- В Microsoft Visual Studio отладить работу компоненты.
Важно: при перекомпиляции внешней компоненты, нужно не только заново подготовить zip-файл ( dll компоненты + manifest.xml ) и загрузить его в общий макет, но и стереть закешированную компоненту dll в каталоге вида C:UsersИмя пользователяAppDataRoaming1C1Cv82ExtCompT .
Варианты работы компоненты
При разработке внешней компоненты необходимо решить, в каких вариантах она будет работать: Windows/Linux, 32/64 бита, сервер/тонкий клиент/веб-клиент (разные браузеры).
Чтобы компонента работала на сервере, необходимо решить, будет ли она предназначена только для вашей организации или будет использоваться как тиражируемое решение. Для разработки тиражируемого решения необходимо предусмотреть четыре варианта работы – Windows 32бит, Windows 64бит, Linux 32бит, Linux 64бит. Подробнее .
Чтобы компонента работала на клиенте, необходимо решить, будет ли она предназначена только для вашей организации или будет использоваться как тиражируемое решение. Для разработки тиражируемого решения необходимо предусмотреть четыре варианта работы – Windows 32бит, Linux 32бит, Linux 64бит, сборки для разных веб-браузеров. Подробнее .