Домой / Видео / Написание native компоненты 1с на c. Технология внешних компонентов (). А теперь - горбатый методы

Написание native компоненты 1с на c. Технология внешних компонентов (). А теперь - горбатый методы

Эта статья посвящена работе с внешними компонентами, а именно: их подключению. На данный момент для расширения возможностей 1С Предприятия используются две технологии внешних компонент:

  • 1 С использованием Native API
  • 2 С использованием технологии COM
В этой статье я решил осветить работу с компонентами Native API.
Итак, приступим, от простого к сложному:
Выдержка из ИТС

1. Допустим ВК у нас расположена в определенном каталоге на диске:

Возможно использование в "Толстом Клиенте (обычное приложение)";

Это самый простой пример работы с компонентой Native. Следует обратить внимание на то, что компонент этого типа не требует регистрацию в системе, что значительно упрощает администрирование.

2. Рассмотренный выше пример совсем не жизненный. Чаще всего компонент располагают в макете. Макет должен содержать zip архив c файлами компонента и файлом MANIFEST.xml
Пример файла манифеста:

3. При работе в тонком и web клиенте обязательно использования метода .
Цитата с ИТС:

пояснение:
%APPDATA%\1C\1Cv82\ExtCompT - каталог установки компонентов для Толстого, Тонкого клиентов.
%APPDATA%\Roaming\Mozilla\Extensions - каталог (в моем случае) расширений для Mozilla FF/
При использовании метода УстановитьВнешнююКомпоненту() , в зависимости от используемого клиента, в соответствующий каталог будут распакованы расширения.

Пример процедуры установки внешнего компонента:

УстановитьВнешнююКомпоненту - метод должен вызываться лишь при первичной установке компонента и в случае, когда необходимо обновить установленную версию компонента.

В случае тонкого и толстого клиента:
Достаточно повторно выполнить операцию установки внешней компоненты с помощью метода УстановитьВнешнююКомпоненту ().

В случае web клиента для обновления компонента:

  • Необходимо удалить плагин через механизм работы с дополнениями веб-браузера (Mozilla FF)
  • Воспользоваться методом УстановитьВнешнююКомпоненту
Для подключения ВК можно использовать следующую процедуру:

Если компонент не был установлен, то будет вызвано исключение.

2. бывают случаи, когда компонент необходимо установить из временного хранилища (файл получен со стороннего источника, внешняя обработка), в этом случае необходимо первым параметров в методы ПодключитьВнешнююКомпоненту и УстановитьВнешнююКомпоненту адрес архива во временном хранилище. Ниже приведу возможный пример работы:

&НаКлиенте Перем АдресАрхиваКомпонента; &НаКлиенте Перем Компонент; &НаКлиенте Процедура ПриОткрытии(Отказ) // адрес, содержит строку (навигационную ссылку на двоичные данные zip архива во // временном хранилище) АдресАрхиваКомпонента = ПолучитьАдресАрхиваВоВременномХранилище(); КонецПроцедуры // ПриОткрытии() &НаСервере // методы ПодключитьВнешнююКомпоненту,УстановитьВнешнююКомпоненту, могут принимать в // качестве первого параметра строку в формате "навигационная ссылка" // (URL к внешней компоненте, упакованной в ZIP-архив, в формате, аналогичном // ПолучитьНавигационнуюСсылку). Функция ПолучитьАдресАрхиваВоВременномХранилище() ОбъектОбработки = РеквизитФормыВЗначение("ОбработкаОбъект"); СсылкаНаАрхив = ПоместитьВоВременноеХранилище(ОбъектОбработки.ПолучитьМакет("MIKO_phone_IP"), Новый УникальныйИдентификатор); Возврат СсылкаНаАрхив; КонецФункции // ПолучитьАдресАрхиваВоВременномХранилище() &НаКлиенте // Процедура должна вызываться лишь один раз, в случае, если компонент еще не установлен // или нуждается в обновлении Процедура УстановитьКомпонент(Команда) Попытка УстановитьВнешнююКомпоненту(АдресАрхиваКомпонента); Исключение Сообщить("Не удалось устанвить внешнюю компоненту."); КонецПопытки; КонецПроцедуры // УстановитьКомпонент() &НаКлиенте // основная процедура инициализации комопнента Процедура Инициализаровать(Команда) Попытка ПодключитьВнешнююКомпоненту(АдресАрхиваКомпонента,"Comp" ,ТипВнешнейКомпоненты.Native); Компонент = Новый ("AddIn.Comp.MIKO_phone_IP"); Исключение Сообщить("Исключение при инициализации. Возможно компонент еще не был установлен."); КонецПопытки; КонецПроцедуры

ansmirnov 22 августа 2013 в 14:12

Внешние компоненты в 1С 8.2

  • Программирование ,
  • C++
  • Tutorial

Введение

Эта статья дает представление о работе внешних компонент в системе «1С: Предприятие».
Будет показан процесс разработки внешней компоненты для системы «1С: Предприятие» версии 8.2, работающей под управлением ОС семейства Windows с файловым вариантом работы. Такой вариант работы используется в большинстве решений, предназначенных для предприятий малого бизнеса. ВК будет реализована на языке программирования C++.

Внешние компоненты «1C: Предприятие»

«1С: Предприятие» является расширяемой системой. Для расширения функциональных возможностей системы используются внешние компоненты (ВК). С точки зрения разработчика ВК представляет собой некоторый внешний объект, который имеет свойства и методы, а также может генерировать события для обработки системой «1С: Предприятие».
Внешние компоненты можно использовать для решения класса задач, которые сложно или даже невозможно реализовать на встроенном в «1C: Предприятие» языке программирования. В частности, к такому классу можно отнести задачи, требующие низкоуровневого взаимодействия с операционной системой, например, для работы с специфичным оборудованием.
В системе «1С: Предприятие» используются две технологии создания внешних компонент:
  • с использованием Native API
  • с использованием технологии COM
При заданных ограничениях между двумя вышеозначенными технологиями разница незначительна, поэтому будем рассматривать разработку ВК с использованием Native API. При необходимости, реализованные наработки могут быть применены для разработки ВК с использованием технологии COM, а также, с незначительными доработками, применены для использования в системе «1С: Предприятие» с другими вариантами работы, отличными от файлового режима работы.
Структура ВК
Внешняя компонента системы «1С: Предприятие» представлена в виде DLL-библиотеки. В коде библиотеки описывается класс-наследник IComponentBase. В создаваемом классе должны быть определены методы, отвечающие за реализацию функций внешней компоненты. Более подробно переопределяемые методы будут описаны ниже по ходу изложения материала.

Запуск демонстрационной ВК

Задача:
  1. Выполнить сборку внешней компоненты, поставляемой с подпиской ИТС и предназначенной для демонстрации основных возможностей механизма внешних компонент в 1С
  2. Подключить демонстрационную компоненту к конфигурации 1С
  3. Убедиться в корректной работоспособности заявленных функций
Компиляция
Демонстрационная ВК расположена на диске подписки ИТС в каталоге «/VNCOMP82/example/NativeAPI».
Для сборки демонстрационной ВК будем использовать Microsoft Visual Studio 2008. Другие версии данного продукта не поддерживают используемый формат проекта Visual Studio.


Открываем проект AddInNative. В настройках проекта подключаем каталог с заголовочными файлами, необходимыми для сборки проекта. По умолчанию они располагаются на диске ИТС в каталоге /VNCOMP82/include .
Результатом сборки является файл /bind/AddInNative.dll . Это и есть скомпилированная библиотека для подключения к конфигурации 1С.
Подключение ВК к конфигурации 1С
Создадим пустую конфигурацию 1С.
Ниже приведен код модуля управляемого приложения.
перем ДемоКомп; Процедура ПриНачалеРаботыСистемы() ПодключитьВнешнююКомпоненту("...\bind\AddInNative.dll", "DemoVK", ТипВнешнейКомпоненты.Native); ДемоКомп = Новый("AddIn.DemoVK.AddInNativeExtension"); КонецПроцедуры
Если при запуске конфигурации 1С не было сообщено об ошибке, то ВК была успешно подключена.
В результате выполнения приведенного кода в глобальной видимости конфигурации появляется объект ДемоКомп , имеющий свойства и методы, которые определены в коде внешней компоненты.
Демонстрация заложенного функционала
Проверим работоспособность демонстрационной ВК. Для этого попробуем установить и прочитать некоторые свойства, вызвать некоторые методы ВК, а также получить и обработать сообщение ВК.
В документации, поставляемой на диске ИТС заявлен следующий функционал демонстрационной ВК:
  1. Управление состоянием объекта компоненты
    Методы: Включить , Выключить
    Свойства: Включен
  2. Управлением таймером
    Каждую секунду компонента посылает сообщение системе «1C: Предприятие» с параметрами Component , Timer и строкой счетчика системных часов.
    Методы: СтартТаймер , СтопТаймер
    Свойства: ЕстьТаймер
  3. Метод ПоказатьВСтрокеСтатуса , который отображает в строке статуса текст, переданный методу в качестве параметров
  4. Метод ЗагрузитьКартинку . Загружает изображение из указанного файла и передает его в систему «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");

Расширение списка свойств ВК

Задача:
  1. Изучить реализацию свойств ВК
  2. Добавить свойство строкового типа, доступное для чтения и записи
  3. Добавить свойство строкового типа, доступное для чтения и записи, которое хранит тип данных последнего установленного свойства. При установке значения свойства никаких действий не производится

Для определения свойств создаваемой компоненты разработчику необходимо реализовать следующие методы в коде библиотеки 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 , в зависимости от переданного порядкового номера свойства в соответствии с логикой приложения.
Для того, чтобы добавить произвольное свойство необходимо:

  1. Добавить имя добавляемого свойства в массивы g_PropNames и g_PropNamesRu (файл AddInNative.cpp )
  2. В перечисление Props (файл AddInNative.h ) перед ePropLast добавить имя, однозначно идентифицирующее добавляемое свойство
  3. Организовать память под хранение значений свойств (завести поля модуля компоненты, хранящие соответствующие значения)
  4. Внести изменения в методы GetPropVal и SetPropVal для взаимодействия с выделенной на предыдущем шаге памятью
  5. В соответствии с логикой приложения внести изменения в методы 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. Расширить функционал внешней компоненты следующим функционалом:
  2. Изучить способы реализации методов внешней компоненты
  3. Добавить метод-функцию Функц1 , которая в качестве параметра принимает две строки («Параметр1» и «Параметр2»). В качестве результата возвращается строка вида: «Проверка. Параметр1, Параметр2»
  4. Убедиться в работоспособности произведенных изменений

Для определения методов создаваемой компоненты разработчику необходимо реализовать следующие методы в коде библиотеки 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 содержат непосредственно исполняемый код метода.
Для добавления метода, который может вызываться только как функция необходимо произвести следующие изменения в исходном коде внешней компоненты:
  1. Добавить имя метода в массивы g_MethodNames и g_MethodNamesRu (файл AddInNative.cpp )
  2. Добавить осмысленный идентефикатор метода в перечисление Methods (файл AddInNative.h )
  3. Внести изменения в код функции GetNParams в соответствии с логикой программы
  4. При необходимости внести изменения в код метода GetParamDefValue , если требуется использовать значения по умолчанию параметров метода.
  5. Внести изменения в функцию HasRetVal
  6. Внести изменения в логику работы функций 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; }
Внесем изменения в функцию :
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"); пер = ДемоКомп.Тест("Привет, ", "Мир!"); Сообщить(пер); КонецПроцедуры
После запуска конфигурации получим сообщение: «Привет, Мир!», что говорит о том, что метод отработал успешно.

Таймер

Задача:
  1. Изучить реализацию таймера в демонстрационной ВК
  2. Модифицировать метод «СтартТаймер», добавив возможность передавать в параметрах интервал срабатывания таймера (в миллисекундах)
  3. Убедиться в работоспособности произведенных изменений

В 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; 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 происходит по следующему алгоритму:
  1. Определение типа данных, которые в данный момент хранятся в переменной
  2. Обращение к соответствующему полю смеси, для непосредственного доступа к данным
Использование типа tVariant значительно упрощает взаимодействие системы «1С: Предприятие» и внешней компоненты

Приложение

Каталог «examples» содержит примеры к статье
examples/1 - запуск демонстрационной компоненты
examples/2 - демонстрация расширения списка свойств
examples/3 - демонстрация расширения списка методов
Каждый каталог содержит проект VS 2008 и готовую конфигурацию 1C.

Технология внешних компонентов позволяет создавать программы (внешние компоненты), которые будут динамически подключаться и тесно взаимодействовать с системой 1С:Предприятие 8, расширяя ее возможности. Данная технология позволяет подключать к системе 1С:Предприятие 8 различное торговое оборудование: сканеры штрих-кодов, принтеры этикеток и т.д.

Native API

Для создания внешних компонентов используется технология Native API – собственный интерфейс системного программирования 1С:Предприятия 8. Она поддерживает операционные системы Windows и Linux, и дает возможность создавать внешние компоненты, работающие как под одной, так и под другой операционной системой. Компоненты, созданные по технологии Native API, могут быть подключены в толстом клиенте, в тонком клиенте, в веб-клиенте, внешнем соединении и в сервере приложений.

Расширение встроенного языка

Внешние компоненты позволяют расширять встроенный язык новыми объектами. Структуры механизмов внешних компонент максимально приближены к внутренним структурам системы 1С:Предприятие 8, что повышает эффективность работы.

Вызов процедуры обработки событий, контролируемых внешней компонентой

Внешняя компонента может порождать события, обрабатываемые в предопределенной процедуре языка ОбработкаВнешнегоСобытия . Это позволяет подключать к системе 1С:Предприятие 8 сканеры и другие устройства, требующие асинхронного обмена данными.

Добавление страницы свойств в параметры «1С:Предприятие 8»

Внешние компоненты могут добавлять свои страницы свойств в диалог параметров системы 1С:Предприятие 8. Таким образом, торговое оборудование может включаться в систему и управляться стандартным для системы 1С:Предприятие 8 способом.

Сохранение параметров компоненты через механизм сохранения параметров «1С:Предприятие 8»

При сохранении своих параметров внешняя компонента может использовать механизмы системы 1С:Предприятие 8.

Доступ к строке состояния

При работе состояние внешней компоненты может отражаться в панели состояния системы 1С:Предприятие 8.

ОЛЕГ ФИЛИППОВ , АНТ-Информ, заместитель начальника отдела разработки, [email protected]

Расширяем функциональность 1С:Предприятия
Часть 1. Внешние компоненты COM

В жизни каждого разработчика 1С наступает момент, когда задачи, перед ним поставленные, превосходят возможности платформы 1С. Рассмотрим способы, как «преодолеть границу возможного»

Опытные разработчики 1С уже, наверное, по первым трем словам названия статьи догадались, что речь пойдет о внешних компонентах для 1С:Предприятия. Эта технология существует еще со времен платформы 1С:Предприятие 7.7 (или более ранней). Исторически появилась в основном для решения задач взаимодействия с торговым оборудованием (сканерами ШК, электронными весами, ККМ), в ходе которых возникает необходимость обработки платформой 1С определенных событий, инициируемых оборудованием. Такие события являются не чем иным, как поступающими на COM/LPT-порты последовательностями байт. Конечно, адаптировать платформу 1С для работы с такими низкоуровневыми механизмами было бы не очень правильно, поэтому придумали технологию внешних компонент для 1С:Предприятия.

В данном цикле статей речь пойдет не только о внешних компонентах: внешние компоненты – достаточно мощный и сложный механизм, поэтому их использование для решения некоторых задач видится как «стрельба из пушки по воробьям». Тем не менее внешние компоненты являются наиболее универсальным средством для решения всевозможных задач, которые выходят за рамки платформы 1С:Предприятие, поэтому начнем мы именно с них. В статье будет рассмотрена наиболее старая, часто используемая и проверенная временем технология создания внешних компонент – на основе COM.

Что такое внешние компоненты

Внешние компоненты, как было сказано выше, появились в 1С:Предприятии еще с версии 7.7. Изначально по традиции разработчики платформы 1С «не заморачивались», и внешние компоненты представляли собой объект с определенными обязательными свойствами и методами. В том же виде компоненты существуют и по сей день. То есть компоненты, написанные для 1С:Предприятия 7.7, будут (в теории) работать и с 1С:Предприятием 8.3.

На практике существует ряд тонкостей: если внешняя компонента активно взаимодействует с самой платформой, то ее функции будут специализированными для конкретной версии.

С версии 8.2 в 1С:Предприятии появилась новая технология разработки внешних компонент, так называемая NativeAPI. Компоненты, написанные по этой технологии, уже не являются COM-объектами. С одной стороны, это плюс – данные компоненты не требуют регистрации, с другой, использование их еще где-либо, кроме платформы 1С:Предприятие, невозможно. Несколько сложнее стала разработка внешних компонент, чуть большее количество обязательных интерфейсов они должны поддерживать. Но о ней речь пойдет в следующей статье.

Внешние компоненты и технология COM

Подробно описывать саму технологию COM не буду, потому как литературы на эту тему масса. Стоит только, наверное, сказать, что многие «путают» создание обычного inproc-сервера с созданием внешних компонент для 1С:Предприятия, но это недалеко от истины. Очень часто можно обойтись только этим функционалом. Как создавать COM-объект на Visual Studio, описано во множестве различных источников. В частности, в человек детально написал, как это делается, с примером вызова из 1С:Предприятия.

Если же хочется все-таки сделать полноценную COM внешнюю компоненту для 1С:Предприятия (из вариантов, зачем это может понадобиться, могу придумать только один – компонента должна активно взаимодействовать с системой на платформе 1С, оповещать пользователей, изменять строку статуса, отображать диалоговые окна и т.п.), то надо воспользоваться непосредственно технологией внешних компонент. Итак, приступим.