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

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

HRESULT CreateAGorillaAndEatBanana

{

IClassFactory *pcf = 0;

// find the class object находим объект класса

HRESULT hr = CoGetClassObject(CLSIDGorilla, CLSCTXALL, 0, IIDIClassFactory, (void **)&pcf);

if (SUCCEEDED(hr))

{

IApe *pApe = 0;

// use the class object to create a gorilla

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

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

// we're done with the class object, so release it

// мы закончили с объектом класса, поэтому освобождаем его

pcf->Release;

if (SUCCEEDED(hr))

{

// tell the new gorilla to eat a banana

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

hr = pApe->EatBanana;

pApe->Release;

}

}

return hr;

}

Этот код является семантически идентичным варианту с функцией, которая использовала интерфейс IApeClass вместо интерфейса IClassFactory.

Для того чтобы предыдущий пример работал корректно, объекту класса Gorilla следует реализовать

IClassFactory : class GorillaClass : public IClassFactory

{

public:

IMPLEMENTUNKNOWNNODELETE(GorillaClass)

BEGININTERFACETABLE(GorillaClass)

IMPLEMENTSINTERFACE(IClassFactory)

ENDINTERFACETABLE

STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)

{

*ppv = 0;

if (pUnkOuter != 0)

// we don't support aggregation yet

// мы еще не поддерживаем агрегирование

return CLASSENOAGGREGATION;

// create a new instance of our C++ class Gorilla

// создаем новый экземпляр нашего С++-класса Gorilla

Gorilla *p = new Gorilla;

if (p == 0) return EOUTOFMEMORY:

// increment reference count by one

// увеличиваем счетчик ссылок на единицу

p->AddRef;

// store the resultant interface pointer into *ppv

// записываем результирующий указатель интерфейса в *ppv

HRESULT hr = p->QueryInterface(riid, ppv);

// decrement reference count by one, which will delete the

// object if QI fails

// уменьшаем на единицу счетчик ссылок,

// что уничтожит объект при отказе QI

p->Release;

// return result of Gorilla::QueryInterface

// возвращаем результат работы Gorilla::QueryInterface

return hr;

STDMETHODIMP LockServer(BOOL bLock);

};

Реализация LockServer будет обсуждаться в этой главе позже. Отметим, что реализация CreateInstance, в первую очередь, создает новый объект C++ на базе класса Gorilla и запрашивает объект, поддерживает ли он нужный интерфейс. Если объект поддерживает требуемый интерфейс, то вызов QueryInterface инициирует вызов AddRef, и клиент в конечном счете выполнит соответствующий вызов Release. Если же произойдет отказ QueryInterface, то потребуется некоторый механизм для уничтожения созданного нового объекта. Предыдущий пример использует стандартную технологию «заключения в скобки» (bracketing) вызова QueryInterface между парой AddRef/Release. Если произошел сбой вызова QueryInterface, то вызов Release сбросит счетчик ссылок на нуль, запуская тем самым удаление объекта. Если же вызов QueryInterface прошел успешно, то вызов Release установит счетчик ссылок на единицу. Остающаяся ссылка принадлежит клиенту, который и выполнит последний вызов Release, когда объект более не нужен.

<p>Оптимизации</p>

Одно из преимуществ использования стандартного интерфейса для создания экземпляров (instantiation ) состоит в том, что СОМ может обеспечить более эффективную технологию реализации. Рассмотрим следующий код, который создает новый экземпляр класса Chimp:

HRESULT CreateChimp(/* [out] */ IApe * &rpApe)

{

extern const CLSID CLSID_Chimp;

rpApe = 0;

IClassFactory *pcf = 0;

HRESULT hr = CoGetClassObject(CLSID_Chimp, CLSCTX_ALL, 0, IID_IClassFactory, (void**)&pcf);

if (SUCCEEDED(hr))

{

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

pcf->Release;

}

return hr;

}

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже