Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
- Дата:20.06.2024
- Категория: Компьютеры и Интернет / Программирование
- Название: Сущность технологии СОМ. Библиотека программиста
- Автор: Дональд Бокс
- Просмотров:3
- Комментариев:0
Шрифт:
Интервал:
Закладка:
[ uuid(F99D19A3-D8BA-11d0-8C4F-0080C73925BA), version(1.0)]
library SportsLib {
importlib(«stdole32.tlb»);
[
uuid(F99D1907-D8BA-11D0-8C4F-0080C73925BA), object,
oleautomation
]
interface IWrestler : IUnknown {
import «oaidl.idl»;
HRESULT HalfNelson([in] double nmsec);
} }
Наличие атрибута [oleautomation] информирует функцию RegisterTypeLib , что при регистрации библиотеки типов ей следует добавить следующие дополнительные элементы реестра:
[HKCRInterface{F99D1907-D8BA-11d0-8C4F-0080C73925BA}]
@="IWrestler"
[HKCRInterface{F99D1907-D8BA-11d0-8C4F-0080C73925BA}ProxyStubClsid32]
@="{O0020424-0000-0000-C000-000000000046}"
[HKCRInterface{F99D1907-D8BA-11d0-8C4F-0080C73925BA}ProxyStubClsid]
@="{O0020424-0000-0000-C000-000000000046}"
[HKCRInterface{F99D1907-D8BA-11d0-8C4F-0080C73925BA}TypeLib]
@="{F99D19AЗ-08BA-11d0-8C4F-0080C73925BA}"
Version="1.0"
CLSID {O0020424-0000-0000-C000-000000000046} соответствует универсальному маршалеру, который предварительно устанавливается на всех платформах, поддерживающих СОМ, в том числе в 16-разрядных Windows.
Основное преимущество использования универсального маршалера заключается в том, что это – единственная поддерживаемая методика осуществления стандартного маршалинга между 16– и 32-разрядными приложениями. Кроме того, универсальный маршалер совместим с Microsoft Transaction Server. Другое преимущество универсального марщалера заключается в следующем: если библиотека типов установлена на хост-машинах и клиента, и объекта, то не потребуется никакой дополнительной DLL интерфейсного марщалера. Основной же недостаток использования универсального маршалера – ограниченная поддержка типов данных параметров. Это то же самое ограничение, которое устанавливают динамический вызов и среды выполнения сценариев, но является серьезным ограничением при разработке интерфейсов системного программирования низкого уровня[3]. Под Windows NT 4.0 начальные затраты на вызов CoMarshalInterface / CoUnmarshalInterface несколько повысятся при использовании универсального маршалера. Однако после обработки интерфейсных заместителя и заглушки затраты на вызов метода становятся эквивалентными затратам на /0icf -маршалер.
Стандартный маршалинг, потоки и протоколы
Подробности того. как СОМ на самом деле преобразует запросы ORPC в потоки, нигде не документированы и подлежат изменениям но мере развития реализации библиотеки СОМ. Описания, содержащиеся в данном разделе, относятся только ко времени написания этого текста, но, конечно, некоторые детали реализации могут измениться в последующих выпусках СОМ.
Когда в процессе инициализируется первый апартамент, СОМ включает RPC-слой времени выполнения, переводя процесс в RPC-сервер. Если апартамент имеет тип МТА или RTA, то используется RPC-протокол ncalrpc , который является оберткой вокруг портов LPC (local procedure call – локальный вызов процедуры) под Windows NT. Если тип апартамента – STA, то используется последовательность закрытого протокола, основанная на очередях сообщений MSG Windows. При первом обращении внехостовых клиентов к объектам, постоянно находящимся в процессе, в процессе регистрируются дополнительные сетевые протоколы. Когда процесс впервые начинает использовать протоколы, отличные от протокола MSG Windows , запускается кэш потоков RPC. Этот кэш потоков начинается с одного потока, который ожидает приходящих запросов на установление соединения, запросов RPC или других действий, специфических для протоколов. Как только произойдет любое из этих событий, кэш потоков RPC переключит поток на обслуживание запроса и будет ждать следующих действий. Для предотвращения излишних затрат на создание/уничтожение потоков эти потоки возвращаются в потоковый кэш, где они будут ждать дальнейшей работы. Если работы нет, то потоки самоуничтожатся по истечении заранее определенного периода бездействия. Теневая сторона этого заключается в том, что кэш потоков RPC растет или сжимается в зависимости от занятости объектов, экспортированных из апартаментов процессов. С точки зрения программирования важно заметить, что кэш потоков RPC динамически размещает потоки, основанные на ORPC-запросах, приходящие по любым протоколам, кроме протокола Windows MSG, который будет обсуждаться позднее в этом разделе.
Когда поступающий ORPC-запрос переадресуется потоку из кэша. поток выделяет из заголовка ORPC-вызова IPID (идентификатор указателя интерфейса) и находит соответствующий администратор заглушек и интерфейсную заглушку. Поток определяет тип того апартамента, в котором хранится объект, и если объект находится в апартаменте типа МТА или RTA, поток входит в апартамент объекта и вызывает метод IRpcStubBuffer::Invoke на интерфейсную заглушку. Если апартамент имеет тип RTA, то в течение вызова метода последующие потоки не будут допускаться к объекту. Если апартамент имеет тип МТА, то последующие потоки могут обращаться к объекту одновременно. В случае внутрипроцессных RTA/MTA-связей канал может сократить кэш потоков RPC и использовать поток клиента повторно, временно входя в апартамент объекта. Если бы МТА и RTA были единственными типами апартаментов, то этого было бы достаточно.
Диспетчеризация вызовов в STA более сложна, так как в существующий STA не могут войти никакие другие потоки. К сожалению, когда ORPC-запросы поступают от внехостовых клиентов, они координируются с использованием потоков из RPC кэша потоков, которые по определению не могут выполняться в STA объекта. Для того чтобы войти в STA и направить вызов потока STA, RPC-поток использует АРI-функцию PostMessage , которая ставит сообщение в специальную MSG -очередь сообщений STA-потоков, как показано на рис. 5.5. Эта очередь представляет собой ту же очередь FIFO (first-in, first-out), которую применяет оконная система. Это означает, что для завершения диспетчеризации вызова STA-поток должен обслуживать очередь с помощью одной из вариаций следующего кода:
MSG msg;
while (GetMessage(&msg, 0, О, 0))
DispatchMessage(&msg);
Этот код означает, что STA-поток имеет по меньшей мере одно окно, которое может принимать сообщения. Когда поток входит в новый STA посредством вызова CoInitializeEx , СОМ создает новое невидимое окно, вызывая CreateWindowEx. Это окно связано с зарегистрированным в СОМ оконным классом, элемент которого WndProc ищет определенные заранее оконные сообщения и обслуживает соответствующий ORPC-запрос посредством вызова метода IRpcStubBuffer::Invoke на интерфейсную заглушку. Отметим, что поскольку окна, подобно объектам на основе STA, обладают потоковой привязкой, WndProc будет выполняться в апартаменте объекта. Чтобы избежать чрезмерного количества переключения потоков, в версии СОМ для Windows 95 предусмотрен транспортный RPC-механизм, который обходит RPC-кэш потоков и вызывает PostMessage из потока вызывающего объекта. Этот перенос возможен только в том случае, если клиент находится на том же хосте, что и объект, поскольку API-функция PostMessage не работает в сети.
Для предотвращения взаимоблокировки все типы апартаментов СОМ поддерживают реентерабельность (повторную входимость)[1]. Когда поток в апартаменте делает запрос на объект вне апартамента вызывающего объекта посредством заместителя, то могут обслуживаться и другие поступающие запросы методов, пока поток вызывающего объекта находится в ожидании ORPC-ответа па первый запрос. Без этой поддержки было бы невозможно создавать системы, основанные на совместно работающих объектах. При написании следующего кода предполагалось, что CLSID_Callback является внутрипроцессным сервером, поддерживающим модель вызывающего потока, и что CLSID_Object является классом, сконфигурированным для активации на удаленной машине:
ICallback *pcb = 0;
HRESULT hr = CoCreateInstance(CLSID_Callback, 0, CLSCTX_ALL,
IID_ICallback, (void**)&pcb);
assert(SUCCEEDED(hr));
// callback object lives in this apt.
// объект обратного вызова живет в этом апартаменте
I0bject "po = 0;
hr = CoCreateInstance(CLSID_Object, 0, CLSCTX_REMOTE_SERVER,
IID_Iobject, (void **)&po);
assert(SUCCEEDED(hr));
// object lives in different apt.
// объект живет в другом апартаменте
// make a call to remote object, marshaling a reference to
// the callback object as an [in] parameter
// делаем вызов удаленного объекта, маршалируя ссылку
// на объект обратного вызова как на [in]-параметр
hr = po->UseCallback(pcb);
// clean up resources
// очищаем ресурсы
pcb->Release();
pco->Release();
На рис. 5.6 показано, что если апартамент вызывающего объекта не поддерживает реентерабельность, то следующая реализация метода UseCallback вызовет взаимоблокировку:
STDMETHODIMP Object::UseCallback(ICallback *pcb) {
HRESULT hr = pcb->GetBackToCallersApartment();
assert(SUCCEEDED(hr));
return S_OK;
Напомним, что когда [in]–параметр передается через метод заместителя UseCallback, то заместитель вызывает CoMarshalInterface для маршалинга интерфейсного указателя ICallback. Поскольку указатель ссылается на объект, находящийся в апартаменте вызывающего объекта, то этот апартамент становится экспортером объектов и поэтому любые межапартаментные вызовы объекта должны обслуживаться в апартаменте вызывающего объекта. Когда заглушка интерфейса IObject демаршалирует интерфейс ICallback, она создает заместитель для передачи его реализации метода UseCallback. Этот заместитель представляет объект при промежуточном соединении с объектом обратного вызова, которое продолжается на протяжении всего времени вызова. Время существования этого заместителя/соединения может превысить время вызова, если реализация метода просто вызовет AddRef на заместитель[2]:
- Аквариум. (Новое издание, исправленное и переработанное) - Виктор Суворов (Резун) - Шпионский детектив
- Права на результаты интеллектуальной деятельности и средства индивидуализации: Комментарий к части четвертой Гражданского кодекса Российской Федерации - Вадим Погуляев - Юриспруденция
- У меня есть идея! Что дальше? - Михаил Соболев - О бизнесе популярно
- Ориентирование - К. М. Станич - Современные любовные романы
- Проект 365 - Константин Рочев - Поэзия