Чтение онлайн

на главную - закладки

Жанры

Сущность технологии СОМ. Библиотека программиста
Шрифт:

следующее определение метода на 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)

{

SAFEARRAY *pArray = 0;

HRESULT hr = g_pObjRef->GetPrimes(nMin, nMax, &pArray);

assert(SUCCEEDED(hr) && SafeArrayGetDim(pArray) == 1);

long *prgn = 0;

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

long iUBound, iLBound, result = 0;

SafeArrayGetUBound(pArray, 1, &iUBound);

SafeArrayGetLBound(pArray, 1, &iLBound);

for (long n = iLBound; n <= iUBound: n++)

result += prgn[n];

SafeArrayUnaccessData(pArray);

SafeArrayDestroy(pArray);

return n;

}

Отметим, что вызывающая программа ответственна за освобождение ресурсов, выделенных для SAFEARRAY-массива, возвращенного как [out]-параметр. Вызов функции SafeArrayDestroy корректно освобождает всю память и все ресурсы, удерживаемые структурой SAFEARRAY.

Управление потоками данных

Отметим, что в предыдущих примерах использования массивов, в том числе типа SAFEARRAY , вопрос о том, какое количество данных будет передано в ORPC-сообщении, решал отправитель данных. Рассмотрим следующее простое определение метода на IDL:

HRESULT Sum([in] long cElems, [in, size_is(cElems)] double *prgd, [out, retval] double *pResult);

Если бы вызывающая программа должна была запустить этот метод следующим образом:

double rgd[1024 * 1024 * 16];

HRESULT hr = p->Sum(sizeof(rgd)/sizeof(*rgd), rgd);

то размер результирующего ответного сообщения ORPC-запроса был бы не меньше 128 Мбайт. Хотя лежащий в основе RPC-протокол вполне в состоянии разбивать большие сообщения на несколько сетевых пакетов, при использовании больших массивов все же возникают некоторые проблемы. Одна очевидная проблема состоит в том, что вызывающая программа должна иметь свыше 128 Мбайт доступной памяти сверх той, которая занята существующим массивом. Дублирующий буфер необходим интерфейсному заместителю для создания ответного ORPC-сообщения, в которое в конечном счете будет скопирован этот массив. Подобная проблема заключается в том, что процесс объекта также должен иметь больше 128 Мбайт доступной памяти для реконструирования полученных RPC-пакетов в единое сообщение ORPC. Если бы массив использовал атрибут [length_is], то следовало бы выделить еще 128 Мбайт, чтобы скопировать этот массив в память для передачи его методу. Эта проблема относится к параметрам как типа [in], так и [out]. В любом случае отправитель массива может иметь достаточное буферное пространство для создания OPRC-сообщения, а получатель массива –

нет. Данная проблема является результатом того, что получатели не имеют механизма для управления потоками на уровне приложений.

Более сложная проблема с приведенным выше определением метода связана со временем ожидания (latency). Семантика ORPC-запроса требует, чтобы на уровне RPC/ORPC полное ORPC-сообшение реконструировалось до вызова метода объекта. Это означает, что объект не может начать обработку имеющихся данных, пока не получен последний пакет. Когда общее время передачи большого массива довольно велико, объект будет оставаться незанятым в течение значительного промежутка времени, ожидая получения последнего пакета. Возможно, что в течение этого времени ожидания многие элементы уже успешно прибыли в адресное пространство объекта; тем не менее, семантика вызова метода в СОМ требует, чтобы к началу текущего вызова присутствовали все элементы. Та же проблема возникает, когда массивы передаются как параметры с атрибутом [out], так как клиент не может начать обработку тех частичных результатов операции, которые, возможно, уже получены к этому моменту.

Для решения проблем, связанных с передачей больших массивов в качестве параметров метода, в СОМ имеется стандартная идиома разработки интерфейсов, позволяющая получателю данных явно осуществлять управление потоками элементов массива. Эта идиома основана на передаче вместо фактических массивов специального интерфейсного указателя СОМ. Этот специальный интерфейсный указатель, называемый нумератором (enumerator), позволяет извлекать элементы из отправителя со скоростью, подходящей для получателя. Чтобы применить эту идиому к приведенному выше определению метода, понадобится следующее определение интерфейса:

interface IEnumDouble : Unknown {

// pull a chunk of elements from the sender

// извлекаем порцию данных из отправителя

HRESULT Next([in] ULONG cElems, [out, size_is(cElems), length_is(*pcFetched)] double *prgElems, [out] ULONG *pcFetched);

// advance cursor past cElems elements

// переставляем курсор после элементов cElems

HRESULT Skip([in] cElems);

// reset cursor to first element

// возвращаем курсор на первый элемент

HRESULT Reset(void);

// duplicate enumerator's current cursor

// копируем текущий курсор нумератора

HRESULT Clone([out] IEnumDouble **pped);

}

Важно отметить, что интерфейс IEnum моделирует только курсор, а отнюдь не текущий массив. Имея такое определение интерфейса, исходное определение метода IDL:

HRESULT Sum([in] long cElems, [in, size_is(cElems)] double *prgd, [out, retval] double *pResult);

преобразуется следующим образом:

HRESULT Sum([in] IEnumDouble *ped, [out, retval] double *pResult);

Отметим, что подсчет элементов больше не является обязательным, так как получатель данных обнаружит конец массива, когда метод IEnumDouble::Next возвратит специальный HRESULT (S_FALSE ).

При наличии приведенного выше определения интерфейса корректной была бы следующая реализация метода:

STDMETHODIMP MyClass::Sum(IEnumDouble *ped, double *psum) {

assert(ped && psum);

*psum = 0; HRESULT hr; do {

Поделиться:
Популярные книги

Расческа для лысого

Зайцева Мария
Любовные романы:
современные любовные романы
эро литература
8.52
рейтинг книги
Расческа для лысого

Измена. Право на любовь

Арская Арина
1. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на любовь

Барон меняет правила

Ренгач Евгений
2. Закон сильного
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Барон меняет правила

Шериф

Астахов Евгений Евгеньевич
2. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
6.25
рейтинг книги
Шериф

Одержимый

Поселягин Владимир Геннадьевич
4. Красноармеец
Фантастика:
боевая фантастика
5.00
рейтинг книги
Одержимый

Князь Серединного мира

Земляной Андрей Борисович
4. Страж
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Князь Серединного мира

Законы Рода. Том 9

Андрей Мельник
9. Граф Берестьев
Фантастика:
городское фэнтези
попаданцы
аниме
дорама
фэнтези
фантастика: прочее
5.00
рейтинг книги
Законы Рода. Том 9

Звезда сомнительного счастья

Шах Ольга
Фантастика:
фэнтези
6.00
рейтинг книги
Звезда сомнительного счастья

Имперский Курьер. Том 4

Бо Вова
4. Запечатанный мир
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Имперский Курьер. Том 4

Ополченец

Криптонов Василий Анатольевич
1. Мир падающих звезд
Фантастика:
фэнтези
попаданцы
альтернативная история
5.00
рейтинг книги
Ополченец

Гоплит Системы

Poul ezh
5. Пехотинец Системы
Фантастика:
фэнтези
рпг
фантастика: прочее
5.00
рейтинг книги
Гоплит Системы

Брак по-драконьи

Ардова Алиса
Фантастика:
фэнтези
8.60
рейтинг книги
Брак по-драконьи

Убивать чтобы жить 3

Бор Жорж
3. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 3

Советник 2

Шмаков Алексей Семенович
7. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Советник 2