INotBusy (не занят), только если количество внешних интерфейсных указателей меньше десяти).

Использование маркера доступа (security token) вызывающего объекта для решения, удовлетворять или нет запрос QueryInterface . Как будет объяснено в главе 6, на самом деле это не обеспечивает никакой реальной безопасности из-за протокола передачи (wire protocol ), используемого СОМ.

Использование успешного захвата динамических ресурсов для решения вопроса о том, удовлетворять или нет запрос QueryInterface (например, выдавать интерфейс IHaveTonsOfMemory (у меня тонны памяти) только при успешном выполнении malloc(4096*4096)).

Эта последняя методика может быть до некоторой степени смягчена, если разработчик объекта желает поупражняться с выражением спецификации СОМ «barring catastrophic failure» (за исключением катастрофического сбоя).

Эти ограничения не означают, что два объекта одного и того же класса реализации не могут давать различные ответы «да/нет» при запросе одного и того же интерфейса. Например, класс может реализовать показанные ранее интерфейсы ICar, IBoat и IPlane , но может разрешить только одному интерфейсу быть использованным в каком-то определенном объекте. Эти ограничения также не означают, что объект не может использовать постоянную или временную информацию для решения вопроса о том, дать ли исходное «да» или «нет» для данного интерфейса. В примере для класса, который разрешает только один из трех интерфейсов, следующая идиома была бы вполне допустимой:

class СВР : public ICar, public IPlane, public IBoat

{

enum TYPE { CAR, BOAT, PLANE, NONE };

TYPE m_type;

CBP(void) : m_type(NONE) { }

STDMETHODIMP QueryInterface(REFIID riid, void **ppv)

{

if (md == IID_ICar)

{

// 1st QI Initializes type of object

// первая QI инициализирует тип объекта

if (m_type == NONE) m_type = CAR;

// only satisfy request if this object is a car

// удовлетворяем запрос, только если данный объект

// является car (автомобилем)

if (m_type == CAR) *ppv = static_cast<ICar*>(this);

else return (*ppv = 0), E_NOINTERFACE;

}

else if (md == IID_IBoat)

{

// similar treatment for IBoat and IPlane

// IBoat и IPlane обрабатываются сходным образом

}

};

Из требования, чтобы множество поддерживаемых интерфейсов было статичным, следует простой вывод, что разработчикам объектов не разрешается создавать конструкции, состоящие из одного объекта, который дает два различных ответа «да/нет» на запрос определенного интерфейса. Одна из причин того, что иерархия типов объекта должна оставаться неизменной на всем протяжении своего жизненного цикла, состоит в том, что СОМ не гарантирует отправления всех клиентских запросов QueryInterface такому объекту в случае, когда к нему имеется удаленный доступ. Неизменность иерархии типов позволяет «заместителям» на стороне клиента (client-side proxies) кэшировать результаты QueryInterface во избежание чрезмерных обменов клиент-объект. Такая оптимизация очень важна для эффективности СОМ, но она разрушает конструкции, использующие QueryInterface для передачи динамической семантической информации вызывающему объекту.

Единственность и идентификация

Предыдущий раздел был посвящен запросам QueryInterface, которые представляют собой ответы типа «да/нет» вызывающим объектам. QueryInterface действительно возвращает S_OK (да) или E_NOINTERFACE (нет). Впрочем, когда QueryInterface возвращает S_OK, то он также возвращает объекту интерфейсный указатель. Для СОМ значение этого указателя чрезвычайно важно, так как оно позволяет клиентам определить, действительно ли на один и тот же объект указывают два интерфейсных указателя.

QueryInterface и IUnknown

Свойство рефлективности QueryInterface гарантирует, что любой интерфейсный указатель сможет удовлетворить запросы на IUnknown, поскольку все интерфейсные указатели неявно принадлежат к типу IUnknown. Спецификация СОМ имеет немного больше ограничений при описании результатов запросов QueryInterface именно на IUnknown. Объект не только должен отвечать «да» на запрос, он должен также возвращать в ответ на каждый запрос в точности одно и то же значение указателя. Это означает, что в следующем коде оба утверждения всегда должны быть верны:

void AssertSameObject(IUnknown *pUnk)

{

IUnknown *pUnk1 = 0,

*pUnk2 = 0;

HRESULT hr1 = pUnk->QueryInterface(IID_IUnknown, (void **)&pUnk1);

HRESULT hr2 = pUnk->QueryInterface(IID_IUnknown, (void **)&pUnk2);

// QueryInterface(IUnknown) must always succeed

// QueryInterface(IUnknown) должно всегда быть успешным

assert(SUCCEEDED(hr1) && SUCCEEDED(hr2));

// two requests for IUnknown must always yield the

// same pointer values

// два запроса на IUnknown должны всегда выдавать

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

0

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

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