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

от автора

Введение

Эта статья дает представление о работе внешних компонент в системе «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. Добавить свойство строкового типа, доступное для чтения и записи, которое хранит тип данных последнего установленного свойства. При установке значения свойства никаких действий не производится
  4. Убедиться в работоспособности произведенных изменений


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

Внесем изменения в функцию 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"); 	пер = ДемоКомп.Тест("Привет, ", "Мир!"); 	Сообщить(пер); КонецПроцедуры  

После запуска конфигурации получим сообщение: «Привет, Мир!», что говорит о том, что метод отработал успешно.

Таймер

Задача:

  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[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 происходит по следующему алгоритму:

  1. Определение типа данных, которые в данный момент хранятся в переменной
  2. Обращение к соответствующему полю смеси, для непосредственного доступа к данным

Использование типа tVariant значительно упрощает взаимодействие системы «1С: Предприятие» и внешней компоненты

Приложение

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

ссылка на оригинал статьи http://habrahabr.ru/post/191014/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *