- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
Шрифт:
Интервал:
Закладка:
FADF_EMBEDDEO
/* array is embedded in a structure */
/* массив вложен в структуру */
FADF_FIXEDSIZE
/* may not be resized or reallocated */
/* не может изменить размеры или быть перемещен*/
FADF_BSTR
/* an array of BSTRs */
/* массив из BSTR */
FADF_UNKNOWN
/* an array of IUnknown* */
/* массив из IUnknown* */
FADF_DISPATCH
/* an array of IDispatch* */
/* массив из IDispatch* */
FADF_VARIANT
/* an array of VARIANTS */
/* массив из VARIANTS */
Для предоставления SAFEARRAY возможности определять типы данных своих элементов, компилятор IDL распознает специальный, специфический для SAFEARRAY, синтаксис:
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)
{
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
// копируем текущий курсор нумератора