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

ЖАНРЫ

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

}

Для инициализации элемента GlobalInterfacePointer разработчик (который выполняется в апартаменте объекта) просто регистрирует обрабатываемые указатели, вызывая метод Globalize на каждый GlobalInterfacePointer:

SafeRect::SafeRect(void) : m_cRef (0), m_pUnkFTM(0) {

IPoint *pPoint = 0;

// create instance of class Point

// создаем экземпляр класса Point

HRESULT hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Ipoint, (void**)&pPoint);

assert (SUCCEEDED(hr));

// register interface pointer in GIT

//

регистрируем интерфейсный указатель в GIT

hr = m_gipTopLeft.Globalize(pPoint);

assert (SUCCEEDED(hr));

pPoint->Release;

// reference is now held in GIT

// теперь ссыпка хранится в GIT

// create instance of class Point

// создаем экземпляр класса Point

hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Iроint, (void**) &рРоint);

assert(SUCCEEDED(hr));

// register interface pointer in GIT

// регистрируем интерфейсный указатель в GIT

hr = m_gipBottomRight.Globalize(pPoint);

assert (SUCCEEDED (hr));

pPoint->Release;

// reference is now held in GIT

// теперь ссылка хранится в GIT

}

Те методы, которым нужен доступ к глобализованным указателям, могут импортировать локальную копию посредством метода Localize из GlobalInterfaсePointer:

STDMETHODIMP SafeRect::get_Top(long *pVal) {

IPoint *pPoint = 0;

// local imported pointer

// локальный импортированный указатель

HRESULT hr = m_gipTopLeft.Localize(&pPoint);

if (SUCCEEDED(hr)){

long x;

hr = pPoint->get_Coords(&x, pVal);

pPoint->Release; }

return hr;

}

Отметим, что в силу применения маршалера свободной поточной обработки (FreeThreaded Marshaler) исходный интерфейсный указатель не может быть кэширован, а должен импортироваться при каждом вызове метода, чтобы предотвратить попытку доступа из неверного апартамента.

Предыдущий фрагмент кода может быть автоматизирован еще больше. Поскольку большинство вызовов методов в классе GlobalInterfacePointer должны будут локализовать временный указатель в самом вызове метода, то приводимый ниже класс автоматизирует импорт временного указателя и его последующее освобождение, что очень напоминает интеллектуальный указатель (smart pointer):

template <class Itf, const IID* piid> class LocalInterfacePointer {

Itf *m_pItf;

// temp imported pointer

// временный импортированный указатель

// prevent misuse

// предотвращаем неверное использование

LocalInterfacePointer(const LocalInterfacePointer&);

operator = (const LocalInterfacePointer&);

public:

LocalInterfacePointer(const GlobalInterfacePointer<Itf, piid>& rhs, HRESULT& hr) { hr = rhs.Loca1ize(&m_pItf) ; }

LocalInterfacePointer(DWORD dwCookie, HRESULT& hr) { assert(g_pGIT != 0);

hr = g_pGIT-&gtGetInterfaceFromGlobal(dwCookie, *piid, (void**)&m_pItf); }

~LocalInterfacePointer(void) { if (m_pItf) m_pItf->Release; }

class SafeItf : public Itf { STDMETHOD_(ULONG, AddRef) (void) = 0;

// hide

// скрытый STDMETHOD_(ULONG, Release)(void) = 0;

// hide

//

скрытый

};

SafeItf *GetInterface(void) const { return (SafeItf*) m_pItf; }

SafeItf *operator ->(void) const { assert(m_pItf != 0);

return GetInterface;

}

};

#def1ne LIP(Itf) LocalInterfacePointer<Itf, &IID_##Itf>

С получением этого второго класса C++ обработка импортированных указателей становится намного проще:

STDMETHODIMP SafeRect::get_Area(long *pn) {

long top, left, bottom, right;

HRESULT hr, hr2;

// import pointers

// импортируем указатели

LIP(IPoint) lipTopLeft(m_gipTopLeft, hr);

LIP(IPoint) lipBottomRight(m_gipBottomRight, hr2);

assert(SUCCEEDED(hr) && SUCCEEDED(hr2));

// use temp tocal pointers

// используем временные локальные указатели

hr = lipTopLeft->GetCoords(&left, &top);

hr2 = lipBottomRight->GetCoords(&right, &bottom);

assert(SUCCEEDED(hr) && SUCCEEDED(hr2));

*pn = (right – left) * (bottom – top); return S_OK;

// LocalInterfacePointer auto-releases temp ptrs.

// LocalInterfacePointer сам освобождает

// временные указатели

}

Макросы GIP и LIP делают совместное использование GIT и FTM намного менее громоздким. До появления GIT использование FTM в классе с интерфейсными указателями было значительно более трудным, чем теперь обеспечивает любой из кодов, приведенных в данном разделе.

Где мы находимся?

В данной главе была описана абстракция апартаментов как логическое группирование объектов, которые подчиняются правилам параллелизма и реентерабельности. Процессы имеют один или более апартаментов. Потоки выполняются в ровно одном апартаменте, а для реализации межапартаментных связей СОМ поддерживает маршалинг объектных ссылок через границы апартаментов. Заместитель является локальным представителем объекта, постоянно находящимся в другом апартаменте. Стандартные заместители для передачи запросов методов с удаленного объекта используют ORPC. Специальные заместители имеют полную свободу для обеспечения корректной семантики. Апартамент является фундаментальной абстракцией, которая используется во всей архитектуре удаленного доступа модели СОМ.

Глава 6. Приложения

int process_id == fork;

if (process_id == 0)

exec(«…/bin/serverd»);

Аноним, 1981

В предыдущей главе были представлены основы апартаментов COM и проиллюстрирована COM-архитектура удаленного доступа с изрядным количеством деталей. Были исследованы правила управления ссылками на объекты COM в условиях многопоточной среды, а также методика реализации классов и объектов COM, работающих в потоках. В этой главе будут рассматриваться проблемы, возникающие при управлении процессами и приложениями при использовании COM. Основное внимание будет сосредоточено на том, как апартаменты соотносятся с локализацией ошибок, доверительными отношениями и контекстом защиты.

Поделиться с друзьями: