clsid:571F1680-CC83-11d0-8C48-0080C73925BA:

Отметим, что префикс «сlsid» является программным идентификатором ProgID для Class Moniker. Следующий код демонстрирует использование МkParseDisplayName для создания Class Moniker, который затем используется для связи с объектом класса Gorilla:

HRESULT GetGorillaClass(IApeClass * &rpgc)

{ rpgc = 0;

// declare the CLSID for Gorilla as a display name

// объявляем CLSID как отображаемое имя для Gorilla

const OLECHAR pwsz[] = OLESTR(«clsid:571F1680-CC83-11d0-8C48-0080C73925BA:»);

// create a new binding context for parsing

// and binding the moniker

// создаем новый связующий контекст

// для анализа и связывания моникера

IBindCtx *pbc = 0;

HRESULT hr = CreateBindCtx(0, &pbc);

if (SUCCEEDED(hr))

{

ULONG cchEaten; IMoniker *pmk = 0;

// ask СОМ to convert the display name to a moniker object

// запрашиваем СОМ преобразовать отображаемое имя

// в объект моникера

hr = MkParseDisplayName(pbc, pwsz, &cchEaten, &pmk);

if (SUCCEEDED(hr))

{

// ask the moniker to find or create the object that it

// refers to // запрашиваем моникер найти или создать объект,

// на который моникер ссылается

hr = pmk->BindToObject(pbc, 0, IID_IApeClass, (void**)&rpgc);

// we now have a pointer to the desired object, so release

// the moniker and the binding context

// теперь у нас есть указатель на желаемый объект, так что

// освобождаем моникер и связующий контекст

pmk->Release();

}

pbc->Release();

}

return hr;

}

Связующий контекст, который передается одновременно в MkParseDisplayName и IMoniker::BindToObject, является просто вспомогательным объектом, который позволяет дополнительным параметрам передаваться алгоритмам синтаксического анализа и связывания моникера. В случае нашего простого примера все, что требуется, – это новый связующий контекст в роли заполнителя (placeholder), который запрашивается путем вызова API-функции СОМ CreateBindCtx[2].

В Windows NT 4.0 введена API-функция, упрощающая вызовы MkParseDisplayName и IMoniker::BindToObject:

HRESULT CoGetObject( [in, string] const OLECHAR *pszName, [in, unique] BIND_OPTS *pBindOptions, [in] REFIID riid, [out, iid_is(riid)] void **ppv);

Эта API-функция реализована следующим образом:

// pseudo-code from OLE32.DLL

// псевдокод из OLE32.DLL

HRESULT CoGetObject(const OLECHAR *pszName, BIND_OPTS *p0pt, REFIID riid, void **ppv)

{

// prepare for failure

// подготовка на случай сбоя

*ppv = 0;

// create a bind context

// создаем контекст связывания

IBindCtx *pbc = 0;

HRESULT hr = CreateBindCtx(0, &pbc);

if (SUCCEEDED(hr))

{

// set bind options if provided

// устанавливаем опции связывания, если они требуются

if (pOpt) hr = pbc->SetBindOptions(pOpt);

if (SUCCEEDED(hr))

{

// convert the display name into a moniker

// преобразуем отображаемое имя в моникер

ULONG cch;

IMoniker *pmk = 0;

hr = MkParseDisplayName(pbc, pszName, &cch, &pmk);

if (SUCCEEDED(hr)) {

// ask the moniker to bind to the named object

// запрашиваем моникер связаться с именованным объектом

hr = pmk->BindToObject(pbc, 0, riid, ppv);

pmk->Release();

}

}

pbc->Release();

}

return hr;

}

При наличии этой функции создание новой гориллы сводится к простому нахождению объекта класса и вызову метода CreateInstance:

HRESULT CreateAGorillaAndEatBanana() {

IClassFactory *pcf = 0;

// declare the CLSID for Gorilla as a display name

// объявляем CLSID как отображаемое имя для Gorilla

const OLECHAR pwsz[] = OLESTR(«clsid:571F1680-CC83-11d0-8C48-0080C73925BA:»);

// find the class object via the gorilla's class moniker

// находим объект класса через gorilla's class moniker

HRESULT hr = CoGetObject(pwsz, 0, IID_IClassFactory, (void**)&pcf);

if (SUCCEEDED(hr))

{

IApe *pApe = 0;

// use the class object to create a gorilla

// используем объект класса для создания gorilla

hr = pcf->CreateInstance(0, IID_IApe, (void**)&pApe);

if (SUCCEEDED(hr)) {

// tell the new gorilla to eat a banana

// говорим новой горилле съесть банан

hr = pApe->EatBanana();

pApe->Release();

}

pcf->Release();

}

return hr;

}

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

Рисунок 3.5 иллюстрирует, какие объекты создаются или находятся посредством каждой операции.

Visual Basic предоставляет функциональные возможности API-функции CoGetObject через встроенную функцию GetObject. Следующий код на Visual Basic также создает новую gorilla и предписывает ей есть бананы:

Sub CreateGorillaAndEatBanana()

Dim gc as IApeClass

Dim ape as IApe

Dim sz as String sz = «clsid:571F1680-CC83-11d0-8C48-0080C73925BA:»

' get the class object for gorillas

' получаем объект класса для gorilla

Set gc = GetObject(sz)

' ask Gorilla class object to create a new gorilla

' запрашиваем объект класса Gorilla создать новую gorilla

Set ape = gc.CreateApe()

' ask gorilla to eat a banana

' просим gorilla есть бананы

ape.EatBanana

End Sub

Отметим, что версия этой функции на Visual Basic использует интерфейс IApeClass для обработки объекта. Это связано с тем, что Visual Basic не может использовать интерфейс IClassFactory из-за ограничений языка.

Моникеры и композиция

Моникеры часто составляются из других моникеров, чтобы с помощью текстового описания пути можно было осуществлять навигацию по иерархиям объектов. Чтобы обеспечить простую поддержку этого типа управления, в СОМ предусмотрена стандартная реализация моникеров, которая, будучи поставленной справа от другого моникера, запрашивает объект связать ссылку с другим объектом в иерархии. Такой моникер называется моникером элемента (Item Moniker) и использует интерфейс объекта IOleItemContainer для преобразования имени объекта в интерфейсный указатель.

Следующее отображаемое имя показывает, как моникер элемента использован в тандеме с классовым моникером:

clsid:571F1680-CC83-11d0-8C48-0080C73925BA:!Ursus

Отметим использование символа "!" для отделения отображаемого имени Class Moniker от имени элемента (item name) «Ursus». При анализе MkParseDisplayName сначала использует префикс "clsid " в качестве ProgID для контакта с реализацией Сlass Moniker. Затем MkParseDisplayName предложит реализации Class Moniker проанализировать часть строки – столько, сколько она сможет распознать. Это означает, что после того, как Сlass Moniker извлек свой GUID из строки, ее следующий фрагмент все еще нуждается в анализе: !Ursus

Поскольку это имя имеет смысл только в области действия объекта, именованного моникером слева от него, фактически MkParseDisplayName присваивает значение крайнему левому моникеру (моникеру классового типа) и запрашивает объект, который он именует (объект класса Gorilla) проанализировать оставшуюся часть строки. Для поддержки анализа отображаемых имен СОМ определяет стандартный интерфейс IParseDisplayName:

вернуться

2 Контексты связывания используются композитными моникерами для оптимизации операций синтаксического анализа и связывания. Кроме того, контексты связывания позволяют клиентам выставить флаги CLSCTX, а также COSERVERINFO, хотя текущая реализация Class Moniker проигнорирует оба эти атрибута. Вместо этого Class Moniker предполагает, что он будет скомпонован с тем моникером, который ссылается на реализацию интерфейса IClassActivator, допускающим намного большую гибкость.


Перейти на страницу:
Изменить размер шрифта: