HRESULT Method([in] SAFEARRAY(type) *ppsa);

где type – тип элемента в SAFEARRAY. Соответствующий прототип данного метода в C++ выглядел бы примерно так:

HRESULT Method(SAFEARRAY **psa);

Отметим, что в определении IDL используется только один уровень косвенности; в то же время в соответствующем определении C++ используются два уровня косвенности. Рассмотрим следующее определение на IDL, задающее массив типа SAFEARRAY из коротких целых чисел:

HRESULT Method([in] SAFEARRAY(short) *psa);

Соответствующее определение на Visual Basic выглядело бы таким образом:

Sub Method(ByVal psa As Integer())

Отметим, что в варианте на Visual Basic не указано явно размерностей массива. Напомним, однако, что Visual Basic поддерживает массивы с фиксированной длиной.

Тип данных SAFEARRAY поддерживается весьма богатым набором API-функций, которые позволяют изменять размерность массивов и производить обход их содержимого переносимым образом. Для доступа к элементам типа SAFEARRAY СОМ предусматривает следующие вызовы API-функций:

// get a pointer to the actual array elements

// получаем указатель на фактически элементы массива

HRESULT SafeArrayAccessData([in] SAFEARRAY *psa, [out] void ** ppv);

// release pointer returned by SafeArrayAccessData

// освобождаем указатель, возвращенный функцией SafeArrayAccessData

HRESULT SafeArrayUnaccessData([in] SAFEARRAY *psa);

// Get number of dimensions

// Получаем количество измерений

ULONG SafeArrayGetDim([in] SAFEARRAY *psa);

// Get upper bound of a dimension

// Получаем верхнюю границу измерения

HRESULT SafeArrayGetUBound([in] SAFEARRAY *psa, [in] UINT nDim, [out] long *pUBound);

// Get lower bound of a dimension

// Получаем нижнюю границу измерения

HRESULT SafeArrayGetLBound([in] SAFEARRAY *psa, [in] UINT nDim, [out] long *pLBound);

Эти методы обеспечивают компактный и надежный способ доступа к текущему содержимому массива. Рассмотрим следующий код на IDL:

HRESULT Sum([in] SAFEARRAY(long) *ppsa, [out, retval] long *pSum);

Тогда следующая реализация метода будет вычислять сумму элементов массива типа SAFEARRAY, состоящего из длинных целых чисел (long integers):

STDMETHODIMP MyClass::Sum(SAFEARRAY **ppsa, long *pnSum)

{

assert(ppsa && *ppsa && pnSum);

assert(SafeArrayGetDim(*ppsa) == 1);

long iUBound, iLBound;

// note that dimension indices are one-based

// отметим, что индексы размерности начинаются с единицы

HRESULT hr = SafeArrayGetUBound(*ppsa, 1, &iUBound);

assert(SUCCEEDED(hr));

hr = SafeArrayGetLBound(*ppsa, 1, &iLBound);

assert(SUCCEEDED(hr));

long *prgn = 0;

hr = SafeArrayAccessData(*ppsa, (void**)&prgn);

*pnSum = 0;

for (long i = 0; i < iUBound – iLBound; i++)

*pnSum += prgn[i];

SafeArrayUnaccessData(*ppsa);

return S_OK;

}

Отметим, что вызовы любых API-функций, которые имеют дело с размерностями массива, используют индексы, начинающиеся с единицы.

Приведенный выше фрагмент кода просто манипулировал содержимым существующего SAFEARRAY-массива. Для создания одномерного массива типа SAFEARRAY для передачи его в качестве параметра метода в СОМ имеется следующая API-функция, которая выделяет память для структуры SAFEARRAY и элементов этого массива в одном непрерывном блоке памяти:

SAFEARRAY *SafeArrayCreateVector(

[in] VARTYPE vt, // element type

// тип элемента

[in] long iLBound, // index of lower bound

// индекс нижней границы

[in] unsigned int cElems); // # of elements

// число элементов

Кроме того, в СОМ имеются различные функции, предназначенные для размещения многомерных массивов, однако их рассмотрение выходит за рамки данной дискуссии. При таком определении метода на IDL:

HRESULT GetPrimes([in] long nStart, [in] long nEnd, [out] SAFEARRAY(long) *ppsa);

следующее определение метода на C++ возвращает вызывающей программе массив типа SAFEARRAY, размещенный в вызываемом методе:

STDMETHODIMP MyClass::GetPrimes (long nMin, long nMax, SAFEARRAY **ppsa)

{

assert(ppsa);

UINT cElems = GetNumberOfPrimes(nMin, nMax);

*ppsa = SafeArrayCreateVector(VT_I4, 0, cElems);

assert(*ppsa);

long *prgn = 0;

HRESULT hr = SafeArrayAccessData(*ppsa, (void**)&prgn);

assert(SUCCEEDED(hr));

for (UINT i=0; i < cElems; i++)

prgn[i] = GetNextPrime(i ? prgn[1 – 1] : nMin);

SafeArrayUnaccessData(*ppsa);

return S_OK;

}

Соответствующий код с клиентской стороны выглядел бы на Visual Basic примерно так:

Function GetSumOfPrimes(ByVal nMin as Long, ByVal nMax as Long) as Long

Dim arr() as Long

Dim n as Variant

Objref.GetPrimes nMin, nMax, arr

GetSumOfPrimes = 0

for each n in arr

GetSumOfPrimes = GetSumOfPrimes + n

Next n

End Function

что соответствует следующему коду на C++:

long GetSumOfPrimes (long nMin, long nMax)

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату