Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Обмен массивами данных с внешними компонентами 1С

Anna | 24.06.2014 | нет комментариев

Как вестимо, подходы к созданию внешних компонент 1С подразумевают применение 2-х спецтехнологий — Native API и COM. Пример с Native API хорошо раскрыт в статье.

Но задача в том, что в случае использования спецтехнологии Native API появляется достаточно нетривиальная задача обмена массивами информации между внешней компонентой и 1С: Предприятием. Как верно было подмечено в комментах к статье, эту задачу доводится решать либо многократным вызовов процедур, либо сериализацией содержимого массива.

Но если использовать COM-спецтехнологию, то все в существенной степени упрощается. Дело в том, что в 1С есть такой малоизвестный, но в данном случае необходимый тип данных, как COMSafeArray.

Выдержка из синтакс-помощника:

COMSafeArray (COMSafeArray)

Изложение:
Объектная оболочка над многомерным массивом SAFEARRAY из COM. Разрешает создавать и применять SAFEARRAY для обмена данными между COM-объектами.
Для передачи массива в качестве параметра способа COM-объекта нужно возвести COMSafeArray требуемой размерности с необходимым типом элемента и указать построенный COMSafeArray в качестве значения входного параметра. Другие объекты 1С: Предприятия дозволено применять в качестве значений входных параметров типа Массив только при наличии доскональной информации о типах параметров в библиотеке типа COM-объекта.
Итог способа COM-объекта либо значение выходного параметра типа Массив неизменно представляется объектом COMSafeArray.

Помимо предоставления самого типа COMSafeArray 1С сопровождает его доскональным комплектом способов, разрешающим преобразовывать типовые массивы 1С в значения этого типа и обратно.

Каждый фокус состоит в том, что если передать данный объект в качестве параметра в функцию внешней компоненты, то в самой внешней компоненте, построенной по спецтехнологии COM, данный массив будет получен в виде указателя на массив типа SAFEARRAY.

Подобно, если воротить указатель на такой массив из функции внешней компоненты, в 1С итог будет интерпретирован как объект типа COMSafeArray.

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

Покажем собственным примером.

В 1С все может быть помещено в простом событии кнопки:

Процедура КнопкаНажатие(Элемент)

	// Создание массива 1С.
	Массив = Новейший Массив;
	Массив.Добавить(10.1);
	Массив.Добавить(20.2);
	Массив.Добавить(30.3);

	// Создание объекта COMSafeArray, содержащего значения типа double
	// на основании массива 1С.
	МассивПараметровКОМ = Новейший COMSafeArray(Массив, "VT_R8");

	// Вызов функции внешней компоненты.
	МассивРезультатовКОМ = Компонента2.ФункцияМассив(МассивПараметровКОМ);

	// Создание массивов 1С на основании объектов COMSafeArray.
	МассивПараметров  = МассивПараметровКОМ.Выгрузить();
	МассивРезультатов = МассивРезультатовКОМ.Выгрузить();

КонецПроцедуры

Т.е. сделали и заполнили обыкновенный массив, сделали на его основе объект типа COMSafeArray и скормили его функции внешней компоненты.
Функция как-то преобразовывает входной COMSafeArray и что-то возвращает тоже в виде COMSafeArray.
Дальше оба полученных объекта COMSafeArray мы выгружаем в обыкновенные массивы 1С и просмотрщиком (Alt F9) глядим итог.

На стороне внешней компоненты всё выглядит ненамного труднее. В соответствующем блоке switch-case, расположенном в функции CallAsFunc мы будем не только создавать результирующий массив, но и изменять сам входной массив.

Собственно, все описано в комментах:

	case arrayFunc:

		{

			// **********************************
			// *** РАБОТА С НАчАЛЬНЫМ МАССИВОМ ***
			// **********************************
			// Приобретение указателя на нулевой элемент массива SAFEARRAY
			// (содержит 1-й параметр функции 1С, тот, что тоже является массивом).
			long inputIdx = 0;
			void* inputVoidPtr = NULL;
			HRESULT hr = SafeArrayPtrOfIndex(*paParams, &inputIdx, &inputVoidPtr);

			// Приведение полученного указателя void* к типу VARIANT*
			// (т.к. мы верно знаем, что там именно VARIANT).
			VARIANT* inputVarPtr = (VARIANT*)inputVoidPtr;

			///////////// ОПРЕДЕЛЕНИЕ ГРАНИЦ МАССИВА.
			long iLowerBound;
			hr = SafeArrayGetLBound(inputVarPtr->parray, 1, &iLowerBound);
			if(FAILED(hr))
				return S_FALSE;

			long iUpperBound;
			hr = SafeArrayGetUBound(inputVarPtr->parray, 1, &iUpperBound);
			if(FAILED(hr))
				return S_FALSE;

			//////////////////////////////////////////////

			void* sourcePtr  = NULL; // Указатель на элемент, заполняемый функцией SafeArrayPtrOfIndex.
			double* sourceValPtr = NULL;
			// Перебор входного массива от нижней границы к верхней.
			for(long l = iLowerBound; l <= iUpperBound; l  )
			{
				// Заполнение указателя на элемент.
				hr = SafeArrayPtrOfIndex(inputVarPtr->parray, &l, &sourcePtr);

				// Приведение указателей void* к требуемому типу.
				sourceValPtr = (double*)sourcePtr;

				// Метаморфоза (инкремент) значения во входном массиве.
				  (*sourceValPtr);
			}

			///////////// СОЗДАНИЕ НОВОГО МАССИВА (С ТАКОЙ ЖЕ РАЗМЕРНОСТЬЮ).
			// Границы нового массива
			SAFEARRAYBOUND sBound[1];
			sBound[0].cElements = iUBound - iLBound   1;
			sBound[0].lLbound = 0;

			// Приобретение типа, хранящегося в начальном массиве.
			VARTYPE varType;
			hr = SafeArrayGetVartype(sArr, &varType);
			if(FAILED(hr))
				return S_FALSE;

			// Создание нового массива.
			SAFEARRAY* sArrNew = SafeArrayCreate(varType, 1, sBound);
			//////////////////////////////////////////////

			/////////// ПЕРЕБОР МАССИВА.
			// Указатели на элементы, заполняемые функцией SafeArrayPtrOfIndex.
			void* sourPtr  = NULL;
			void* destPtr  = NULL;

			// Перебор начального массива от нижней границы к верхней.
			for(long l = iLBound; l <= iUBound; l  )
			{
				// Заполнение указателя на элемент.
				hr = SafeArrayPtrOfIndex(sArr, &l, &sourPtr);

				hr = SafeArrayPtrOfIndex(sArrNew, &l, &destPtr);

				// Приведение указателей void* к требуемому типу
				// и присвоение значений целевому массиву (начальный, умноженный на 2).
				*((double*)destPtr) = *((double*)sourPtr) * 2;
			}
			////////////////////////////////////////////

			///////////// ПРИСВОЕНИЕ ВОЗВРАЩАЕМОМУ ЗНАЧЕНИЮ ЗНАЧЕНИЯ МАССИВА.
			V_VT(pvarRetValue) = VT_ARRAY;
			V_ARRAY(pvarRetValue) = sArrNew;

			break;
		}

Т.е. мы получили начальный массив и как-то изменили (в данном случае — инкрементировали) его.
Позже этого сделали новейший массив такой же размерности и заполнили его некими значениями (в данном случае — входные, умноженные на 2).

Таким образом, если до обработки функцией внешней компоненты мы имели массив:
МассивПараметров: { 10.1, 20.2, 30.3 }

То позже отрабатывания этой функции, полученные в 1С массивы примут дальнейший вид:
МассивПараметров: { 11.1, 21.2, 31.3 }
МассивРезультатов: { 22.2, 42.4, 62.6 }

Т.е. и массив-параметр и результирующий массив были обработаны функцией внешней компоненты и получены в 1С
в измененном виде.

Полный план внешней компоненты (с расширенным комплектом демонстрационных функций) находится тут.

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB