Сущность технологии СОМ. Библиотека программиста
Шрифт:
Напомним, что начальная точка входа в класс СОМ проходит через объект этого класса. Чтобы связаться с объектом класса, необходим моникер классового типа (Class Moniker). Это моникеры встроенного типа, предоставляемые моделью СОМ. Классовые моникеры поддерживают CLSID в качестве своего начального состояния и могут быть созданы либо с помощью явной API-функции СОМ CreateClassMoniker.
HRESULT CreateClassMoniker([in] REFCLSID rclsid, [out] IMoniker **ppmk);
либо путем передачи отображаемого имени от Class Moniker в MkParseDisplayName [1] :
clsid:571F1680-CC83-11d0-8C48-0080C73925BA:
Отметим,
1 Хотя использование MkParseDisplayName будет несколько менее эффективным, оно обладает гораздо большей гибкостью. Как отмечалось ранее, отображаемое имя может быть прочитано из файла или даже из пользовательского интерфейса. Отличным примером такого приложения является Internet Explorer фирмы Microsoft, так как он позволяет пользователям набирать произвольные имена объектов (URL), которые превращаются в моникеры (с использованием расширенной API-функции MkParseDisplayNameEx).
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] .
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;
}
Рисунок 3.5 иллюстрирует, какие объекты создаются или находятся посредством каждой операции.