Содержание:
1. Что такое внешняя компонента. Подключение компоненты 1С
2. Установка компонент 1С. Подключение внешней компоненты.
Перед тем как подключить внешнюю компоненту 1С, давайте рассмотрим, что же она собой представляет в плане теории.
1. Что такое внешняя компонента. Подключение компоненты 1С
Ни для кого не секрет, что 1С является очень динамичной платформой для работы с основными технологиями, к которым мы можем получить доступ из конфигурации. Явным примером этого является Ole, COM, web сервисы, обмен данными через xml и т.д. Имея навыки программирования можно легко настроить подключение и/или обмен данными с любой cms системой в сети интернет либо той, которая имеет api функционал. Но иногда появляется необходимость в расширении функционала, которого мы не можем добиться, используя язык 1С. В этом плане на помощь нам приходят внешние компоненты. Говоря простым языком, внешние компоненты — это в 1С стандартные библиотеки с наборами функций, скомпилированные (собранные) для работы с внешней программой. Для работы с внешними компонентами нам в первую очередь нужно их подключить, это можно делать либо динамически (подключить в конкретном куске кода для выполнения некоторого функционала, нужно лишь в этот момент), либо зарегистрировать ее в системе.
Наиболее оптимально хранить компоненты как макеты в конфигурации. Это дает возможность не зависеть от конкретного «железа», а также программного обеспечения. Для такого хранения нам подойдет макет с типом «Двоичные данные»:
2. Установка компонент 1С. Подключение внешней компоненты.
Хранение компоненты мы организовали. Далее нам надо рассмотреть, как подключить компоненту. Если внешняя компонента используется впервые, перед подключением ее нужно установить. Пример установки и подключения компоненты приведен ниже:
Для вызова функций нашей компоненты нам нужно ее использовать как переменную. Пример вызова функции:
В данном примере мы рассмотрели, как подключить компоненту, и что собой представляет внешняя компонента 1С.
Разнообразие внешних компонент весьма большое. С их помощью мы можем работать с графикой, подключать разнообразное оборудование, производить потоковое сканирование. Исходя из этого заметно то, что возможности внешних компонент ограничиваются лишь их целесообразностью и фантазией специалиста, который их создает.
Стоит также отметить, что при использовании компоненты нужно учесть, в какой операционной системе она будет работать, а также какую разрядность ОС поддерживает.
Специалист компании ООО «Кодерлайн»
Сергей Кулажевский
06.12.201115:3806-12-2011 15:38
Эта статья посвящена работе с внешними компонентами, а именно: их подключению. На данный момент для расширения возможностей 1С Предприятия используются две технологии внешних компонент:
- 1 С использованием Native API
- 2 С использованием технологии COM
В этой статье я решил осветить работу с компонентами Native API.
Итак, приступим, от простого к сложному:[spoiler]
Выдержка из ИТС
При работе компоненты на сервере, вызов ПодключитьВнешнююКомпоненту() необходимо выполнять каждый раз перед созданием экземпляра внешней компоненты, т. к. в общем случае неизвестно, на каком сервере будет исполняться вызов (это может быть Windows, Linux, 32-разрядная или 64-разрядная ОС).
Я бы добавил, что метод ПодключитьВнешнююКомпоненту лучше использовать всегда, независимо от типа клиента.
1. Допустим ВК у нас расположена в определенном каталоге на диске :
// подключаем компонент Попытка ПодключитьВнешнююКомпоненту("D:MIKO_phone_IP.dll", "Comp", ТипВнешнейКомпоненты.Native); // Создаем объект компонента, обратите внимание на использование // конструкции «Новый ()» ОбъектКомпоненты = Новый("AddIn.Comp.MIKO_phone_IP"); Компонент.Host= "sip.host.com"; Компонент.Port = "5038"; Комопнент.LogIn(); Исключение Сообщить("Исключение при инициализации"); КонецПопытки;
Возможно использование в “Толстом Клиенте (обычное приложение)”;
Это самый простой пример работы с компонентой Native. Следует обратить внимание на то, что компонент этого типа не требует регистрацию в системе, что значительно упрощает администрирование.
2. Рассмотренный выше пример совсем не жизненный. Чаще всего компонент располагают в макете. Макет должен содержать zip архив c файлами компонента и файлом MANIFEST.xml
Пример файла манифеста:
<?xml version=”1.0″ encoding=”UTF-8″?>
<bundle xmlns=”http://v8.1c.ru/8.2/addin/bundle”>
<component os=”Windows” path=”MIKO_phone_IP.dll” type=”native” arch=”i386″/>
<component os=”Windows” path=”1CEAdnWebFF.xpi” type=”plugin” object=”@vendor.ru/ClassService;1″ arch=”i386″ client=”Firefox” clientVersion=”5.*”/>
</bundle>
Итого в архиве возможен следующий состав файлов:
- MIKO_phone_IP.dll (компонент native)
- MANIFEST.xml
- 1CEAdnWebFF.xpi (zip архив – расширение для Mozilla FF, содержит компонент native)
Пример работы для толстого клиента (обычное приложение)
ПутьКМакету = "Обработка.МИКО_ПанельТелефонии.Макет.AddInWindows32"; Если ПодключитьВнешнююКомпоненту(ПутьКМакету,"Component") Тогда Компонент = Новый ("AddIn.Component.MIKO_phone_IP"); КонецЕсли;
3. При работе в тонком и web клиенте обязательно использования метода УстановитьВнешнююКомпоненту().
Цитата с ИТС:
В момент установки внешние компоненты устанавливаются в каталог %APPDATA%1C1Cv82ExtCompT. Каталог установки внешних компонент не считается кешем и не очищается при вызове «1С:Предприятия» с ключом командной строки ClearCache. Использование метода УстановитьВнешнююКомпоненту() для тонкого клиента является обязательным.
пояснение:
%APPDATA%1C1Cv82ExtCompT – каталог установки компонентов для Толстого, Тонкого клиентов.
%APPDATA%RoamingMozillaExtensions – каталог (в моем случае) расширений для Mozilla FF/
При использовании метода УстановитьВнешнююКомпоненту(), в зависимости от используемого клиента, в соответствующий каталог будут распакованы расширения.
Пример процедуры установки внешнего компонента:
&НаКлиенте // Процедура должна вызываться лишь один раз Процедура УстановитьКомпонент(Команда) Попытка УстановитьВнешнююКомпоненту(АдресАрхиваКомпонента); Исключение Сообщить("Не удалось устанвить внешнюю компоненту."); КонецПопытки; КонецПроцедуры
УстановитьВнешнююКомпоненту – метод должен вызываться лишь при первичной установке компонента и в случае, когда необходимо обновить установленную версию компонента.
В случае тонкого и толстого клиента:
Достаточно повторно выполнить операцию установки внешней компоненты с помощью метода УстановитьВнешнююКомпоненту().
В случае web клиента для обновления компонента:
- Необходимо удалить плагин через механизм работы с дополнениями веб-браузера (Mozilla FF)
- Воспользоваться методом УстановитьВнешнююКомпоненту
Для подключения ВК можно использовать следующую процедуру:
&НаКлиенте Процедура Инициализаровать(Команда) Попытка ПодключитьВнешнююКомпоненту("ОбщийМакет.MIKO_phone_IP","Comp" ,ТипВнешнейКомпоненты.Native); Компонент = Новый ("AddIn.Comp.MIKO_phone_IP"); Исключение Сообщить("Исключение при инициализации..."); КонецПопытки; КонецПроцедуры
Если компонент не был установлен, то будет вызвано исключение.
2. бывают случаи, когда компонент необходимо установить из временного хранилища (файл получен со стороннего источника, внешняя обработка), в этом случае необходимо первым параметров в методы ПодключитьВнешнююКомпоненту и УстановитьВнешнююКомпоненту адрес архива во временном хранилище. Ниже приведу возможный пример работы:
&НаКлиенте Перем АдресАрхиваКомпонента; &НаКлиенте Перем Компонент; &НаКлиенте Процедура ПриОткрытии(Отказ) // адрес, содержит строку (навигационную ссылку на двоичные данные zip архива во // временном хранилище) АдресАрхиваКомпонента = ПолучитьАдресАрхиваВоВременномХранилище(); КонецПроцедуры // ПриОткрытии() &НаСервере // методы ПодключитьВнешнююКомпоненту,УстановитьВнешнююКомпоненту, могут принимать в // качестве первого параметра строку в формате "навигационная ссылка" // (URL к внешней компоненте, упакованной в ZIP-архив, в формате, аналогичном // ПолучитьНавигационнуюСсылку). Функция ПолучитьАдресАрхиваВоВременномХранилище() ОбъектОбработки = РеквизитФормыВЗначение("ОбработкаОбъект"); СсылкаНаАрхив = ПоместитьВоВременноеХранилище(ОбъектОбработки.ПолучитьМакет("MIKO_phone_IP"), Новый УникальныйИдентификатор); Возврат СсылкаНаАрхив; КонецФункции // ПолучитьАдресАрхиваВоВременномХранилище() &НаКлиенте // Процедура должна вызываться лишь один раз, в случае, если компонент еще не установлен // или нуждается в обновлении Процедура УстановитьКомпонент(Команда) Попытка УстановитьВнешнююКомпоненту(АдресАрхиваКомпонента); Исключение Сообщить("Не удалось устанвить внешнюю компоненту."); КонецПопытки; КонецПроцедуры // УстановитьКомпонент() &НаКлиенте // основная процедура инициализации комопнента Процедура Инициализаровать(Команда) Попытка ПодключитьВнешнююКомпоненту(АдресАрхиваКомпонента,"Comp" ,ТипВнешнейКомпоненты.Native); Компонент = Новый ("AddIn.Comp.MIKO_phone_IP"); Исключение Сообщить("Исключение при инициализации. Возможно компонент еще не был установлен."); КонецПопытки; КонецПроцедуры
Рекомендую ознакомиться с материалами на сайте ИТС:
1. ИТС: Документация: Глава 31. Внешние Компоненты
2. ИТС: Технология создания внешних компонент.
Как добавить внешнюю компоненту в файловую базу
«1С: Предприятие» – расширяемая система. Для увеличения функционала системы можно использовать внешние компоненты. Добавить их можно следующим образом:
Для начала нужно вывести пункт “Функции” для технического специалиста. Для этого в правом верхнем углу необходимо вызвать меню – “Настройки” – “Параметры” и поставить галочку “Режим технического специалиста”- “Применить” .
В этом же меню в самом низу появится пункт “Функции для технического специалиста”. Нужно перейти в данный пункт, в поиске прописать внешние компоненты и выбрать соответствующий пункт.
Далее “Добавить из файла”. Если у вас отобразилось предупреждение безопасности, выбираете продолжить (этим вы подтверждаете что уверены в источнике данной компоненты), открывается проводник и вы выбираете нужную вам компоненту. Она отобразится в окне создания внешней компоненты, Записать и закрыть.
Готово
Уже более 10 000 компаний работают
в облачной 1С от 42Clouds
– Консультация по 1С Бесплатно!
– Поддержка 24/7 по техническим вопросам: в чате, по телефону, по почте
– Все типовые конфигурации онлайн, доступ через RDP, Remote App, Web
Время на прочтение
16 мин
Количество просмотров 145K
Введение
Эта статья дает представление о работе внешних компонент в системе «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С.
Ниже приведен код модуля управляемого приложения.
перем ДемоКомп;
Процедура ПриНачалеРаботыСистемы()
ПодключитьВнешнююКомпоненту("...bindAddInNative.dll", "DemoVK", ТипВнешнейКомпоненты.Native);
ДемоКомп = Новый("AddIn.DemoVK.AddInNativeExtension");
КонецПроцедуры
Если при запуске конфигурации 1С не было сообщено об ошибке, то ВК была успешно подключена.
В результате выполнения приведенного кода в глобальной видимости конфигурации появляется объект ДемоКомп, имеющий свойства и методы, которые определены в коде внешней компоненты.
Демонстрация заложенного функционала
Проверим работоспособность демонстрационной ВК. Для этого попробуем установить и прочитать некоторые свойства, вызвать некоторые методы ВК, а также получить и обработать сообщение ВК.
В документации, поставляемой на диске ИТС заявлен следующий функционал демонстрационной ВК:
- Управление состоянием объекта компоненты
Методы: Включить, Выключить
Свойства: Включен - Управлением таймером
Каждую секунду компонента посылает сообщение системе «1C: Предприятие» с параметрами Component, Timer и строкой счетчика системных часов.
Методы: СтартТаймер, СтопТаймер
Свойства: ЕстьТаймер - Метод ПоказатьВСтрокеСтатуса, который отображает в строке статуса текст, переданный методу в качестве параметров
- Метод ЗагрузитьКартинку. Загружает изображение из указанного файла и передает его в систему «1C: Предприятие» в виде двоичных данных.
Убедимся в работоспособности этих функций. Для этого исполним следующий код:
перем ДемоКомп;
Процедура ПриНачалеРаботыСистемы()
ПодключитьВнешнююКомпоненту(...);
ДемоКомп = Новый("AddIn.DemoVK.AddInNativeExtension");
ДемоКомп.Выключить();
Сообщить(ДемоКомп.Включен);
ДемоКомп.Включить();
Сообщить(ДемоКомп.Включен);
ДемоКомп.СтартТаймер();
КонецПроцедуры
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
Сообщить(Источник + " " + Событие + " " + Данные);
КонецПроцедуры
Результат запуска конфигурации приведен на изображении
На панель «Сообщения» выведены результаты вызовов методов ДемоКомп.Выключить() и Демо.Комп.Включить(). Последующие строки на той же панели содержат результаты обработки полученных от ВК сообщений — Источник, Событие и Данные соответственно.
Произвольное имя внешней компоненты
Задача: Изменить имя внешней компоненты на произвольное.
В предыдущем разделе использовался идентификатор AddInNativeExtension, смысл которого не был пояснен. В данном случае AddInNativeExtension — это наименование расширения.
В коде ВК определен метод RegisterExtensionAs, возвращающий системе «1С: Предприятие» имя, которое необходимо для последующей регистрации ВК в системе. Рекомендуется указывать идентификатор, который в известной мере раскрывает суть внешней компоненты.
Приведем полный код метода RegisterExtensionAs с измененным наименованием расширения:
bool CAddInNative::RegisterExtensionAs(WCHAR_T** wsExtensionName)
{
wchar_t *wsExtension = L"SomeName";
int iActualSize = ::wcslen(wsExtension) + 1;
WCHAR_T* dest = 0;
if (m_iMemory)
{
if(m_iMemory->AllocMemory((void**)wsExtensionName, iActualSize * sizeof(WCHAR_T)))
::convToShortWchar(wsExtensionName, wsExtension, iActualSize);
return true;
}
return false;
}
В приведенном примере имя ВК изменено на SomeName. Тогда при подключении ВК необходимо указывать новое имя:
ДемоКомп = Новый("AddIn.DemoVK.SomeName");
Расширение списка свойств ВК
Задача:
- Изучить реализацию свойств ВК
- Добавить свойство строкового типа, доступное для чтения и записи
- Добавить свойство строкового типа, доступное для чтения и записи, которое хранит тип данных последнего установленного свойства. При установке значения свойства никаких действий не производится
- Убедиться в работоспособности произведенных изменений
Для определения свойств создаваемой компоненты разработчику необходимо реализовать следующие методы в коде библиотеки AddInNative.cpp:
GetNProps
Возвращает количество свойств данного расширения, 0 – при отсутствии свойств
FindProp
Возвращает порядковый номер свойства, имя которого передается в параметрах
GetPropName
Возвращает имя свойства по его порядковому номеру и по переданному идентификатору языка
GetPropVal
Возвращает значение свойства с указанным порядковым номером
SetPropVal
Устанавливает значение свойства с указанным порядковым номером
IsPropReadable
Возвращает флаг флаг возможности чтения свойства с указанным порядковым номером
IsPropWritable
Возвращает флаг флаг возможности записи свойства с указанным порядковым номером
Полное описание методов, включая список параметров подробно описан в документации, поставляемой на диске ИТС.
Рассмотрим реализацию приведенных методов класса CAddInNative.
В демонстрационной ВК определены 2 свойства: Включен и ЕстьТаймер (IsEnabled и IsTimerPresent).
В глобальной области видимости кода библиотеки определено два массива:
static wchar_t *g_PropNames[] = {L"IsEnabled", L"IsTimerPresent"};
static wchar_t *g_PropNamesRu[] = {L"Включен", L"ЕстьТаймер"};
которые хранят русское и английское названия свойств. В заголовочном файле AddInNative.h определяется перечисление:
enum Props
{
ePropIsEnabled = 0,
ePropIsTimerPresent,
ePropLast // Always last
};
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 имеем:
static wchar_t *g_PropNames[] = {L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"};
static wchar_t *g_PropNamesRu[] = {L"Включен", L"ЕстьТаймер", L"Тест", L"ПроверкаТипа"};
Перечисление Props будет иметь вид:
enum Props
{
ePropIsEnabled = 0,
ePropIsTimerPresent,
ePropTest1,
ePropTest2,
ePropLast // Always last
};
Для значительного упрощения кода будем использовать STL C++. В частности, для работы со строками WCHAR, подключим библиотеку wstring.
Для сохранения значения метода Тест, определим в классе CAddInNative в области видимости private поле:
string test1;
Для передачи строковых параметров между «1С: Предприятие» и внешней компонентов используется менеджер памяти «1С: Предприятие». Рассмотрим его работу подробнее. Для выделения и освобождения памяти соответственно используются функции AllocMemory и FreeMemory, определенные в файле ImemoryManager.h. При необходимости передать системе «1С: Предприятие» строковый параметр, внешняя компонента должна выделить под нее память вызовом функции AllocMemory. Ее прототип выглядит следующим образом:
virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
где pMemory — адрес указателя, в который будет помещен адрес выделенного участка памяти,
ulCountByte — размер выделяемого участка памяти.
Пример выделения памяти под строку:
WCHAR_T *t1 = NULL, *test = L"TEST_STRING";
int iActualSize = wcslen(test1)+1;
m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T));
::convToShortWchar(&t1, test1, iActualSize);
Для удобства работы с строковыми типами данными опишем функцию wstring_to_p. Она получает в качестве параметра wstring-строку. Результатом функции является заполненная структура tVariant. Код функции:
bool CAddInNative::wstring_to_p(std::wstring str, tVariant* val) {
char* t1;
TV_VT(val) = VTYPE_PWSTR;
m_iMemory->AllocMemory((void**)&t1, (str.length()+1) * sizeof(WCHAR_T));
memcpy(t1, str.c_str(), (str.length()+1) * sizeof(WCHAR_T));
val -> pstrVal = t1;
val -> strLen = str.length();
return true;
}
Тогда соответствующая секция case оператора switch метода GetPropVal примет вид:
case ePropTest1:
wstring_to_p(test1, pvarPropVal);
break;
Метода SetPropVal:
case ePropTest1:
if (TV_VT(varPropVal) != VTYPE_PWSTR)
return false;
test1 = std::wstring((wchar_t*)(varPropVal -> pstrVal));
break;
Для реализации второго свойства определим поле класса CaddInNative
uint8_t last_type;
в котором будем сохранять тип последнего переданного значения. Для этого в метод CaddInNative::SetPropVal добавим команду:
last_type = TV_VT(varPropVal);
Теперь при запросе чтения значения второго свойства будем возвращать значение last_type, чего требует обозначенное задание.
Проверим работоспособность произведенных изменений.
Для этого приведем внешний вид конфигурации 1С к виду:
перем ДемоКомп;
Процедура ПриНачалеРаботыСистемы()
ПодключитьВнешнююКомпоненту("...", "DemoVK", ТипВнешнейКомпоненты.Native);
ДемоКомп = Новый("AddIn.DemoVK.SomeName");
ДемоКомп.ПроверкаТипа = 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.
Полное описание методов, включая список параметров подробно описан в документации, поставляемой на диске ИТС.
Рассмотрим реализацию описанных выше методов.
В в коде компоненты определены два массива:
static wchar_t *g_MethodNames[] = {L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"};
static wchar_t *g_MethodNamesRu[] = {L"Включить", L"Выключить", L"ПоказатьВСтрокеСтатуса", L"СтартТаймер", L"СтопТаймер", L"ЗагрузитьКартинку"};
и перечисление:
enum Methods
{
eMethEnable = 0,
eMethDisable,
eMethShowInStatusLine,
eMethStartTimer,
eMethStopTimer,
eMethLoadPicture,
eMethLast // Always last
};
Они используются в функциях 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 к виду:
static wchar_t *g_MethodNames[] = {L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"};
static wchar_t *g_MethodNamesRu[] = {L"Включить", L"Выключить", L"ПоказатьВСтрокеСтатуса", L"СтартТаймер", L"СтопТаймер", L"ЗагрузитьКартинку", L"Тест"};
enum Methods
{
eMethEnable = 0,
eMethDisable,
eMethShowInStatusLine,
eMethStartTimer,
eMethStopTimer,
eMethLoadPicture,
eMethTest,
eMethLast // Always last
};
Отредактируем функцию GetNProps, чтобы она возвращала количество параметров метода «Тест»:
long CAddInNative::GetNParams(const long lMethodNum)
{
switch(lMethodNum)
{
case eMethShowInStatusLine:
return 1;
case eMethLoadPicture:
return 1;
case eMethTest:
return 2;
default:
return 0;
}
return 0;
}
Внесем изменения в функцию CAddInNative::GetParamDefValue:
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue)
{
TV_VT(pvarParamDefValue)= VTYPE_EMPTY;
switch(lMethodNum)
{
case eMethEnable:
case eMethDisable:
case eMethShowInStatusLine:
case eMethStartTimer:
case eMethStopTimer:
case eMethTest:
// There are no parameter values by default
break;
default:
return false;
}
return false;
}
Благодаря добавленной строке
case eMethTest:
в случае отсутствия одного или нескольких аргументов соответствующие параметры будут иметь пустое значение (VTYPE_EMPTY). Если необходимо наличие значения по умолчанию для параметра, следует задать его в секции eMethTest оператора switch функции CAddInNative::GetParamDefValue.
Так как метод «Тест» может возвращать значение, необходимо внести изменения в код функции HasRetVal:
bool CAddInNative::HasRetVal(const long lMethodNum)
{
switch(lMethodNum)
{
case eMethLoadPicture:
case eMethTest:
return true;
default:
return false;
}
return false;
}
И добавим исполняемый код метода в функцию CallAsFunc:
bool CAddInNative::CallAsFunc(const long lMethodNum,
tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray)
{
...
std::wstring s1, s2;
switch(lMethodNum)
{
case eMethLoadPicture:
...
break;
case eMethTest:
if (!lSizeArray || !paParams)
return false;
s1 = (paParams) -> pwstrVal;
s2 = (paParams+1) -> pwstrVal;
wstring_to_p(std::wstring(s1+s2), pvarRetValue);
ret = true;
break;
}
return ret;
}
Скомпилируем компоненту и приведем код конфигурации к виду:
перем ДемоКомп;
Процедура ПриНачалеРаботыСистемы()
ПодключитьВнешнююКомпоненту("...", "DemoVK", ТипВнешнейКомпоненты.Native);
ДемоКомп = Новый("AddIn.DemoVK.SomeName");
пер = ДемоКомп.Тест("Привет, ", "Мир!");
Сообщить(пер);
КонецПроцедуры
После запуска конфигурации получим сообщение: «Привет, Мир!», что говорит о том, что метод отработал успешно.
Таймер
Задача:
- Изучить реализацию таймера в демонстрационной ВК
- Модифицировать метод «СтартТаймер», добавив возможность передавать в параметрах интервал срабатывания таймера (в миллисекундах)
- Убедиться в работоспособности произведенных изменений
В WinAPI для работы со временем можно воспользоваться сообщением WM_TIMER. Данное сообщение будет посылаться вашей программе через интервал времени, который вы зададите при создании таймера.
Для создания таймера используется функция SetTimer:
UINT SetTimer(HWND hWnd, // описатель окна
UINT nIDevent, // идентификатор (номер) таймера
UINT nElapse, // задержка
TIMERPROC lpTimerFunc); // указатель на функцию
Операционная система будет посылать сообщение WM_TIMER в программу с интервалом указанным в аргументе nElapse (в миллисекундах). В последнем параметре можно указать функцию, которая будет выполняться при каждом срабатывании таймера. Заголовок этой функции должен выглядеть так (имя может быть любым):
void __stdcall TimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Рассмотрим реализацию таймера в демонстрационной ВК.
Так как мы рассматриваем процесс разработки внешней компоненты для ОС семейства Windows, не будем рассматривать реализацию таймера в других операционных системах. Для ОС GNU/Linux, в частности, реализация будет отличаться синтаксисом функции SetTimer и TimerProc.
В исполняемом коде вызывается метод SetTimer, в который передается функция MyTimerProc:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
Идентефикатор созданного таймера помещается в переменную m_uiTimer, чтобы в последствии его можно было отключить.
Функция MyTimerProc выглядит следующим образом:
VOID CALLBACK MyTimerProc(
HWND hwnd, // handle of window for timer messages
UINT uMsg, // WM_TIMER message
UINT idEvent, // timer identifier
DWORD dwTime // current system time
)
{
if (!pAsyncEvent)
return;
wchar_t *who = L"ComponentNative", *what = L"Timer";
wchar_t *wstime = new wchar_t[TIME_LEN];
if (wstime)
{
wmemset(wstime, 0, TIME_LEN);
::_ultow(dwTime, wstime, 10);
pAsyncEvent->ExternalEvent(who, what, wstime);
delete[] wstime;
}
}
Суть функции сводится к тому, что вызывается метод ExternalEvent, который посылает сообщение системе «1С: Предприятие».
Для расширения функционала метода СтартТаймер произведем следующие действия:
Модифицируем код метода GetNParams так, чтобы он для метода eMethStartTimer возвращал значение 1:
case eMethStartTimer:
return 1;
Приведем код метода CallAsProc к виду:
case eMethStartTimer:
if (!lSizeArray || TV_VT(paParams) != VTYPE_I4 || TV_I4(paParams) <= 0)
return false;
pAsyncEvent = m_iConnect;
#ifndef __linux__
m_uiTimer = ::SetTimer(NULL,0,TV_I4(paParams),(TIMERPROC)MyTimerProc);
#else
// код для GNU/Linux
#endif
break;
Теперь проверим работоспособность. Для этого в модуле управляемого приложения конфигурации напишем код:
перем ДемоКомп;
Процедура ПриНачалеРаботыСистемы()
ПодключитьВнешнююКомпоненту("...", "DemoVK", ТипВнешнейКомпоненты.Native);
ДемоКомп = Новый("AddIn.DemoVK.SomeName");
ДемоКомп.СтартТаймер(2000);
КонецПроцедуры
После запуска конфигурации в программу будут поступать сообщения с интервалом в 2 секунды, что говорит о корректной работе таймера.
Взаимодействие с системой «1С: Предприятие»
Для взаимодействия между внешней компонентой и системой «1С: Предприятие» используются методы класса IAddInDefBase, описанного в файле AddInDefBase.h. Перечислим наиболее часто используемые:
Генерация сообщения об ошибке
virtual bool ADDIN_API AddError(unsigned short wcode, const WCHAR_T* source, const WCHAR_T* descr, long scode)
wcode, scode — коды ошибки (список кодов ошибок с описанием можно найти на диске ИТС)
source — источник ошибки
descr — описание ошибки
Отправка сообщения системе «1С: Предприятие»
virtual bool ADDIN_API ExternalEvent(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wszSource — источник сообщения
wszMessage — текст сообщения
wszData — передаваемые данные
Перехват сообщения осуществляется процедурой ОбработкаВнешнегоСобытия
Регистрация внешней компоненты в системе «1С: Предприятие»
virtual bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wszProfileName — имя компоненты.
Этих методов достаточно для полноценного взаимодействия ВК и 1С. Для получения данных внешней компонентой от системы «1С: Предприятие» и наоборот внешняя компонента отправляет специальное сообщение, которое в свою очередь перехватывается системой «1С» и, при необходимости вызывает методы внешней компоненты для обратной передачи данных.
Тип данных tVariant
При обмене данными между внешней компонентой и системой «1С: Предприятие» используется тип данных tVariant. Он описан в файле types.h, который можно найти на диске с ИТС:
struct _tVariant
{
_ANONYMOUS_UNION union
{
int8_t i8Val;
int16_t shortVal;
int32_t lVal;
int intVal;
unsigned int uintVal;
int64_t llVal;
uint8_t ui8Val;
uint16_t ushortVal;
uint32_t ulVal;
uint64_t ullVal;
int32_t errCode;
long hRes;
float fltVal;
double dblVal;
bool bVal;
char chVal;
wchar_t wchVal;
DATE date;
IID IDVal;
struct _tVariant *pvarVal;
struct tm tmVal;
_ANONYMOUS_STRUCT struct
{
void* pInterfaceVal;
IID InterfaceID;
} __VARIANT_NAME_2/*iface*/;
_ANONYMOUS_STRUCT struct
{
char* pstrVal;
uint32_t strLen; //count of bytes
} __VARIANT_NAME_3/*str*/;
_ANONYMOUS_STRUCT struct
{
WCHAR_T* pwstrVal;
uint32_t wstrLen; //count of symbol
} __VARIANT_NAME_4/*wstr*/;
} __VARIANT_NAME_1;
uint32_t cbElements; //Dimension for an one-dimensional array in pvarVal
TYPEVAR vt;
};
Тип tVariant представляет из себя структру, которая включает себя:
- смесь (union), предназначенную непосредственно для хранения данных
- идентификатор типа данных
В общем случае работа с переменными типа tVariant происходит по следующему алгоритму:
- Определение типа данных, которые в данный момент хранятся в переменной
- Обращение к соответствующему полю смеси, для непосредственного доступа к данным
Использование типа tVariant значительно упрощает взаимодействие системы «1С: Предприятие» и внешней компоненты
Приложение
Каталог «examples» содержит примеры к статье
examples/1 — запуск демонстрационной компоненты
examples/2 — демонстрация расширения списка свойств
examples/3 — демонстрация расширения списка методов
Каждый каталог содержит проект VS 2008 и готовую конфигурацию 1C.
Скачать приложение
С этой ошибкой мы сталкивались, как правило, в клиент-серверном варианте. При чем ошибка может быть при первоначальном запуске 1С, так и в процессе работе с функциями, подсистемами и сервисами.
Дальнейшие выводы и советы являются общими, при подробном разборе требуется анализ журнала, детальное изучение сообщений, кода и поиск причины.
Наиболее вероятный сценарий — файл компоненты находился на сервере, но потом по какой-то причине удаляется/блокируется. И 1С уже не может к нему обратиться, т. к. по заданному пути его нет либо нет доступа. Сработала программа/скрипт очистки, действия администратора сервера или антивирусное ПО.
Кстати, с последним — добавьте исключение для каталога временных файлов технического пользователя, от имени которого работает Агент 1С. Стандартные рекомендации для исключений антивируса — здесь. Например, по умолчанию (учетная запись USR1CV8):
C:UsersUSR1CV8AppDataLocalTemp
Что можно сделать
- Первым делом перезапустите сервер 1С — завершите клиентские соединения и сделайте рестарт службы «Агент сервера 1С:Предприятия 8.3». Скорее, после перезапуска ошибка исчезнет. Это базовая рекомендация, когда требуется быстрое решение.
- Очистите кэш сервера 1С.
- Проверьте наличие регистра сведений «Кэш файлов» для используемого сервиса. В главном меню откройте пункт «Функции для технического специалиста…», выберите «Регистры сведений», а затем найдите регистр «Кэш файлов» и очистите кэш.
- В крайнем случае, когда ничего не помогает — переустановите/обновите платформу 1С.
✅ Вывод простой: сначала перезагружаете сервер 1С и проверяете. Если ошибка повторяется — подключаете специалистов и разбираете детально. На «корню».
_____________________________________
⚡ Подписывайтесь на канал или задавайте вопрос на сайте — постараемся помочь всеми техническими силами. Безопасной и производительной работы в Windows и 1С.