- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
Шрифт:
Интервал:
Закладка:
class Monitor : public IExternalConnection, public IMonitor {
LONG m_cRef;
// normal COM reference count
// обычный счетчик ссылок СОМ
LONG m_cExtRef;
// external reference count
// счетчик внешних ссылок
Monitor(void) : m_cRef(0), m_cExtRef(0) { … }
STDMETHODIMP_(DWORD) AddConnection(DWORD extconn, DWORD) {
if (extconn & EXTCONN_STRONG)
// must check for this bit
// нужно проверить этот бит
return InterlockedIncrement(&m_cExtRef);
}
STDMETHODIMP_(DWORD) ReleaseConnection(DWORD extconn, DWORD,
BOOL bLastUnlockKillsStub) {
DWORD res = 0;
if (extconn & EXTCONN_STRONG) {
// must check for this bit
// нужно проверить этот бит
res = InterlockedDecrement(&m_cExtRef);
if (res == 0 && bLastUnlockKillsStub)
CoDisconnectObject(this, 0);
}
return res;
} }
: : :
: : : }
Получив эту реализацию, подпрограмма потока могла бы проверить состояние объекта и решить, выполнять или нет операцию регистрации, основываясь на уровне активности объекта:
DWORD WINAPI ThreadProc(void *pv) {
// assume ptr to real object is passed to CreateThread
// пусть указатель на действительный объект передается в CreateThread
Monitor *pm = (Monitor*)pv;
while (1) {
// sleep for 10 seconds
// ожидаем 10 секунд
Sleep(1OOOO);
// if object is not in use, perform a log operation
// если объект не используется, то выполняем операцию регистрации
if (pm->m_cExtRef == 0)
pm->TryToLogSampleData();
}
return 0; }
Если принять, что метод объекта TryToLogSampleData корректно поддерживает параллелизм, то данная поточная процедура будет регистрировать данные только при условии, что объект не используется внешними клиентами или не осуществляет активный контроль (напомним, что при контроле объект увеличивает счетчик внешних ссылок посредством CoLockObjectExternal). Хотя данный пример может показаться несколько запутанным, имеются случаи, когда отслеживание внешних ссылок является решающим для обеспечения правильности операции. Один классический пример описан в главе 6 и относится к регистрации объектов класса на внепроцессных серверах.
Специальный маршалинг
До сих пор внимание в данной главе было сосредоточено на стандартном маршалинге и вызове методов на основе ORPC. Для большого класса объектов этого было достаточно, чтобы достичь нужного баланса между производительностью, семантической корректностью и простотой реализации. В то же время существуют объекты, для которых ORPC-вызов по умолчанию является неэффективным и даже непригодным. Для таких объектов в СОМ предусмотрен специальный маршалинг (custom marshaling). Как уже упоминалось в этой главе, специальный маршалинг позволяет разработчику объекта обеспечить реализацию специальных заместителей (custom proxies ), которые будут созданы в импортирующих апартаментах. Объекты сообщают о своем желании поддерживать специальный маршалинг путем экспорта интерфейса IMarshal:
[uuid(00000003-0000-0000-C000-000000000046), local, object] interface IMarshal : IUnknown {
// get CLSID for custom proxy (CoMarshalInterface)
// получаем CLSID для специального заместителя (CoMarshalInterface)
HRESULT GetUnmarshalClass( [in] REFIID riid, [in, iid_is(riid) ] void *pv, [in] DWORD dwDestCtx, [in] void *pvDestCtx, [in] DWORD mshlflags, [out] CLSID *pclsid);
// get size of custom marshaled objref (CoGetMarshalSizeMax)
// получаем размер специально маршалированной объектной ссылки (CoGetMarshalSizeMax)
HRESULT GetMarshalSizeMax( [in] REFIID riid, [in, iid_is(riid)] void *pv, [in] DWORD dwDestCtx, [in] void *pvDestCtx, [in] DWORD mshlflags, [out] DWORD *pSize);
// write out custom marshaled objref (CoMarshalInterface)
// выполняем контрольное считывание специально маршалированной объектной ссылки (CoMarshalInterface)
HRESULT MarshalInterface([in] IStream *pStm, [in] REFIID riid, [in, iid_is(riid)] void *pv, [in] DWORD dwDestCtx, [in] void *pvDestCtx, [in] DWORD mshlflags);
// read objref and return proxy (CoUnmarshalInterface)
// читаем объектную ссылку и возвращаем заместитель (CoUnmarshalInterface)
HRESULT UnmarshalInterface([in] IStream *pStm, [in] REFIID riid, [out, iid_is(riid)] void **ppv);
// revoke a marshal (CoReleaseMarshalData)
// аннулируем маршалер (CoReleaseMarshalData)
HRESULT ReleaseMarshalData([in] IStream *pStm);
// tear down connection-state (CoDisconnectObject)
// разрываем связь между объектами (CoDisconnectObject)
HRESULT DisconnectObject([in] DWORD dwReserved);
}
Комментарии, предваряющие определения методов, показывают, какие именно API-функции вызывает каждый из них.
Когда метод CoMarshalInterface вызывается на объект, поддерживающий специальный маршалинг, маршалированная объектная ссылка имеет несколько другой (формат, как показано на рис. 5.7. Заметим, что после стандартного заголовка MEOW маршалированная объектная ссылка просто содержит CLSID, используемый для создания специального заместителя и непрозрачного байтового массива, предназначенного для инициализации этого специального заместителя. CoMarshalInterface находит CLSID специального заместителя посредством вызова на объект метода IMarshal::GetUnmarshalСlass. CoMarshalInterface заполняет непрозрачный байтовый массив, вызывая реализацию метода IMarshal::MarshalInterface объекта. Именно в MarshalInterface объект получает свой первый и единственный шанс послать инициализационное сообщение новому специальному заместителю, просто записав его в подаваемый байтовый поток.
При вызове CoUnmarshalInterface это сообщение будет передано вновь созданному специальному заместителю через его метод IMarshal::UnmarshalInterface. Это означает, что и объект, и специальный заместитель должны реализовать IMarshal . Метод объекта MarshalInterface записывает инициализационное сообщение. Метод заместителя UnmarshalInterface читает инициализационное сообщение. Когда метод UnmarshalInterface возвращается, СОМ больше не участвует ни в каких связях заместитель/объект. Реализация интерфейсных методов семантически корректным способом является делом специального заместителя. Если нужно произвести удаленный вызов метода на объект, то сделать это – задача заместителя. Если же метод может быть реализован в апартаменте клиента, то заместитель может сделать и это.
Преимуществом специального маршалинга является то, что клиент не имеет понятия о его использовании. Фактически клиент не может достоверно определить, является ли интерфейс стандартным заместителем, специальным заместителем или настоящим объектом. Специальный маршалинг является решением на уровне объект-объект. Два экземпляра одного и того же класса могут независимо друг от друга избрать стандартный или специальный маршалинг. Если объект выбирает реализацию специального маршалинга, то он должен делать это для всех интерфейсов. Если объект желает специально маршалировать только для части всех возможных контекстов, подлежащих маршалингу – например, внутрипроцессный, локальный, с другой машины, – то он может получить экземпляр стандартного маршалера и направить его методы IMarshal для маршалинга неподдерживаемых контекстов, так чтобы могли поддерживаться все контексты. Если бы объект мог безоговорочно направить все методы IMarshal к стандартному маршалеру, то он практически всегда использовал бы стандартный маршалинг.
Для получения указателя на стандартный маршалер объекты могут вызывать метод CoGetStandardMarshal:
HRESULT CoGetStandardMarshal( [in] REFIID riid,
// type of itf marshaled?
// тип, которым маршалирован интерфейс?
[in, iid_is(riid)] IUnknown *pUnk,
// the itf to marshal
// интерфейс для маршалинга
[in] DWORD dwDestCtx,
// MSHCTX [in] void *pvDestCtx,
// reserved // зарезервировано [in] DWORD mshlflags,
// normal vs. table // нормальный или табличный маршалинг
[out] IMarshal **ppMarshal); // ptr to std. Marshal
// указатель на стандартный маршалер
Предположим, что объект использует технологию специального маршалинга, которая работает только на локальном хосте, но не при связи с внехостовыми апартаментами. Реализация объектом метода GetMarshalSizeMax могла бы выглядеть примерно так:
STDMETHODIMP CustStd::GetMarshalSizeMax(
ULONG *pcb, REFIID riid, void *pv, DWORD dwDestCtx, void *pvDestCtx, DWORD mshlflags) {
// if context is supported, do work!
// если контекст поддерживается, то действуем!
if (dwDestCtx == MSHCTX_LOCAL || dwDestCtx == MSHCTX_INPROC) return this->MyCustomMarshalingRoutine(pcb);
// unsupported context, delegate to std marshal
// контекст не поддерживается, обращаемся к стандартному маршапингу
IMarshal *pMsh = 0;
HRESULT hr = CoGetStandardMarshal (riid, pv, dwDestCtx, pvDestCtx, mshlflags, &pMsh);
if (SUCCEEDED(hr)) {
hr = pMsh->GetMarshalSizeMax(pcb, riid, pv, dwDestCtx, pvDestCtx, mshlflags);
pMsh->Retease();
}
return hr;
}
В этом фрагменте кода не показано, как писать инициализационное сообщение для случая, когда действительно желателен специальный маршалинг. Дело в том, что не существует стандартной реализации каждого из методов IMarshal (отсюда и термин специальный (custom) маршалинг). Существует, однако, несколько общих сценариев, в которых специальный маршалинг чрезвычайно выигрышен и реализация IMarshal в этих сценариях – довольно обычное явление. Безусловно, наиболее общим приложением IMarshal является реализация маршалинга по значению (marshal-by-value).
Маршалинг по значению наиболее удобен для таких объектов, которые после инициализации никогда не изменяют своего состояния. Обертки СОМ для структур – вот типичный пример объекта, который просто инициализирован, передан другому объекту для запроса и затем уничтожен. Такой объект является первым кандидатом для специального маршалинга. При реализации маршалинга по значению реализация объекта почти всегда является внутрипроцессным сервером. Это позволяет объекту и заместителю разделять один и тот же класс реализации. Идея маршалинга по значению состоит в том, что специальный заместитель становится клоном исходного объекта. Из этого следует, что маршалированная объектная ссылка должна содержать все состояние исходного объекта, а также (для простоты) то, что CLSID специального заместителя должен быть тем же, что и у исходного объекта.