Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Фабрики класів

Інтерфейс COM - об' єктів.

Тепер виникає важливе питання - як клієнт може створювати COM об' єкти CoBook і CoJournal?

Два важливі принципи COM:

· Незалежність від мови

Відповідно до ідеології моделі COM, класи COM (коклассы) можуть реалізовуватися на різних мовах і повинні зберігатися в бінарному виді (dll або exe файл). Клієнт може бути реалізований на будь-якому з тих, що підтримують модель COM мові і, отже, повинен мати можливість створювати (активізувати) COM об'єкт не використовуючи яких-небудь специфічних для цієї мови методів, а за допомогою спеціального стандартного інтерфейсу.

· Прозорість місця розташування сервера. Є три місця, де може розміщуватися COM сервер:

· В процесі клієнта

Цей спосіб забезпечує найшвидший зв'язок клієнта і сервера (який реалізується у вигляді dll). Але є і проблеми. Наприклад, при помилці в сервері ''вилітає'' увесь процес (тобто і клієнт).

· Поза процесом клієнта, але на одній з ним машині Це так назывемая локальний зв'язок (зазвичай використовується exe -сервер). Вона забезпечує надійність (при помилках в сервері клієнт не гине), але потрібна організація передачі даних між клієнтом і сервером через межі процесів. Це COM бере на себе, забезпечуючи кодування, передачу і декодування даних. При цьому створюються проксі об'єкт в процесі клієнта і заглушка в процесі сервера. Проксі імітує для клієнта сервер, а заглужка імітує для сервера клієнта. У зв'язку з цим код клієнта не залежить від того, де розташовується сервер. Усе перетворення даних і їх пересилка здійснюється парою прокси-заглушка. Комутація проксі і заглушки заснована на протоколі спрощеного видаленого виклику процедур (LRPC - Lightweight Remote Procedure Call).

· На видаленій машині При цьому зв'язок найбільш повільний. Архітектура схожа на архітектуру, описану в попередньому пункті, тільки замість LRPC використовується RPC - протокол видаленого виклику процедур.

Помітимо, що клієнт не зобов'язаний знать, де саме розташований використовуваний сервер. Код клієнта не міняється при зміні місця розташування сервера. Більше того, сервер може розташовуватися в декількох місцях, і на прохання клієнта система (менеджер управління сервісом), може встановлювати зв'язок клієнта з найближчою до нього копією сервера.

Отже, потрібний стандартний інтерфейс для активації COM об' єкту. Такий інтерфейс в COM є і називається IClassFactory

((((визначений в <unknwn.h>). Для шкірного кокласса, ''що живе'' в деякому сервері, в цьому ж сервері повинний ''жити'' клас що реалізовує так звану фабрику класу (чи об' єкт класу). Саме фабрика класу надає клієнтові інтерфейс

IClassFactory і більше ніяких інших інтерфейсів (окрім, природно, IUnknown, від якого IClassFactory породжений як і вусі інші COM інтерфейси).

Інтерфейс IClassFactory має два методи:

· CreateInstance

За допомогою цього методу клієнт, що має покажчик на фабрику деякого класу, може створити будь-яке число екземплярів цього класу і отримати покажчик на бажаний інтерфейс цього класу.

· LockServer

Для активації якого-небудь COM об' єкту потрібне розміщення сервера, в якому ''живе'' цей об' єкт, в оперативній пам' яті. Кожен об' єкт веде лічильник посилань на собі і автоматичний видаляє собі з пам' яті, коли посилань більше немає. Якщо немає активних об' єктів, ''що живуть'' в сервері, то сервер також може бути видалений з пам' яті. Але клієнт може цьому восприпятствовать, заблокувавши сервер в пам' яті для швидшої активації об' єктів в майбутньому. Для цього він і може викликати метод LockServer.

Далі для визначеності розглядатимемо побудову dll -сервера (сервера в процесі клієнта). Природно, цей вибір ніяк не позначиться на коді клієнта. Побудова локального сервера (сервер поза процесом клієнта, але на цій же машині) буде розглянуто пізніше.

Наступний код містить визначення фабрики класу для кокласса CoBook.

//////////////////////////////////////////////////

// // // // CoBookFactory.h: заголовний файл для класу CoBookFactory --

// // // // фабрика класу для класу CoBook

//////////////////////////////////////////////////

####ifndef _CoBookFactory_

####define _CoBookFactory_

####include "CoBook.h"

class CoBookFactory: public IClassFactory

{

public:

// // // // Конструктор і деструкція

CoBookFactory();

virtual ~CoBookFactory();

////////IUnknown

STDMETHODIMP QueryInterface(REFIID riid, void** pIFace);

STDMETHODIMP_(ULONG) AddRef();

STDMETHODIMP_(ULONG) Release();

////////IClassFactory

STDMETHODIMP LockServer(BOOL fLock);

STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter

REFIID riid, void** ppv);

private:

ULONG m_refCount; // Лічильник числа сылок на об' єкт

};

####endif

Тут стандартним чином оголошені конструктор, деструкція, три методи інтерфейсу IUnknown і два методи інтерфейсу

IClassFactory. Семантика усіх цих методів вже була викладена раніше. Додатково треба пояснити сенс параметрів

методів LockServer і CreateInstance.

Параметр fLock набуває значення TRUE - заблокувати сервер, або FALSE - розблоковувати сервер. Сервер веде підрахунок усіх блокувань, встановлених усіма його клієнтами, і дозволяє вивантажити собі з пам' яті, якщо тільки не залишилося активних об' єктів і спільний рахунок блокувань в пам' яті дорівнює нулю.

Перший параметр методу CreateInstance використовується тільки при агрегації, яка обговорювалася раніше. Саме, якщо клас CoBook проектується з можливістю його агрегації в іншій COM клас (клас CoBook готовий надати можливість

іншому класу видавати інтерфейси класу CoBook за свої), то через параметр pUnkOuter (тип якого визначається в

<unknwn.h> як typedef IUnknown __RPC_FAR * LPUNKNOWN) він отримує покажчик інтерфейсу IUnknown того об' єкту, який

його зібрався агрегувати. Якщо CoBook не проектувався з можливістю агрегації (так і є в нашому випадку), то він чекає отримання в цьому параметрі значення NULL, інакше тут буде бачена помилка CLASS_E_NOAGGREGATION.

Другий параметр методу CreateInstance задає посилання на ідентифікатор бажаного інтерфейсу, а третій повертає запрошений інтерфейс (якщо він є).

Реалізація фабрики класу CoBookFactory для класу CoBook представлена нижче.

//////////////////////////////////////////////////

// // // // CoBookFactory.cpp: реалізація класу CoBookFactory --

// // // // фабрики класу для класу CoBook.

//////////////////////////////////////////////////

####include "CoBookFactory.h"

extern ULONG g_lockCount; // Лічильник блокувань сервера в пам' яті

extern ULONG g_objCount; // Лічильник активних об' єктів

//////////////////////////////////////////////////

// // // // Конструктор і деструкція

//////////////////////////////////////////////////

CoBookFactory::CoBookFactory()

{

m_refCount = 0;

g_objCount++;

}

CoBookFactory::~CoBookFactory()

{

g_objCount--;

}

////////IUnknown

STDMETHODIMP_(ULONG) CoBookFactory::AddRef()

{

return ++m_refCount;

}

STDMETHODIMP_(ULONG) CoBookFactory::Release()

{

if (--m_refCount == 0)

{

delete this;

return 0;

}

else

return m_refCount;

}

STDMETHODIMP CoBookFactory::QueryInterface(REFIID riid, void** ppv)

{

if(riid == IID_IUnknown)

{

****ppv = (IUnknown*) this;

}

else if(riid == IID_IClassFactory)

{

****ppv = (IClassFactory*) this;

}

else

{

****ppv = NULL;

return E_NOINTERFACE;

}

((((((((IUnknown*)(*ppv)) ->AddRef();

return S_OK;

}

////////IClassFactory

STDMETHODIMP CoBookFactory::CreateInstance(

LPUNKNOWN pUnkOuter, REFIID riid, void** ppv)

{

if(pUnkOuter!= NULL)

{

return CLASS_E_NOAGGREGATION;

}

CoBook* pBookObj = NULL;

HRESULT hr;

pBookObj = new CoBook;

hr = pBookObj ->QueryInterface(riid, ppv);

if (FAILED(hr))

delete pBookObj;

return hr;

}

STDMETHODIMP CoBookFactory::LockServer(BOOL fLock)

{

if (fLock)

++++++++g_lockCount;

else

--------g_lockCount;

return S_OK;

}

У конструкторі обнуляється лічильник посилань на фабрику класу - член класу m_refCount (як завжди при створенні будь-якого об' єкту COM) і збільшується на одиницю глобальний лічильник числа активних об' єктів цього сервера (g_objCount).

У деструкції на одиницю зменшується глобальний лічильник активних об' єктів цього сервера.

Реалізація методів інтерфейсу IUnknown стандартна і вже обговорювалася раніше.

Перейдемо тепер до обговорення реалізації методів інтерфейсу

IClassFactory і почнемо з методу CreateInstance.

По-перше, не передбачається агрегація класу CoBook. У зв'язку з цим видається помилка CLASS_E_NOAGGREGATION, якщо перший параметр не рівний NULL.

У наступних рядках коду і проявляється зв'язок цієї фабрики класу саме з класом CoBook. Створюється екземпляр класу

CoBook і проситися покажчик на деякий інтерфейс цього класу:

CoBook* pBookObj = NULL;

HRESULT hr;

pBookObj = new CoBook;

hr = pBookObj ->QueryInterface(riid, ppv);

При невдачі отримання інтерфейсу, створений об' єкт знищується.

У методі LockServer глобальний лічильник блокувань сервера в пам' яті збільшується або зменшується на одиницю в залежності від значення параметра fLock.

Абсолютно аналогічно визначається і реалізується фабрика класу CoJournalFactory для кокласса CoJournal.

//////////////////////////////////////////////////

// // // // CoJournalFactory.h: заголовний файл для класу

// // // // CoJournalFactory -- фабрики класу для класу CoJournal

//////////////////////////////////////////////////

####ifndef _CoJournalFactory_

####define _CoJournalFactory_

####include "CoJournal.h"

class CoJournalFactory: public IClassFactory

{

public:

CoJournalFactory();

virtual ~CoJournalFactory();

////////IUnknown

STDMETHODIMP QueryInterface(REFIID riid, void** pIFace);

STDMETHODIMP_(ULONG) AddRef();

STDMETHODIMP_(ULONG) Release();

////////IClassFactory

STDMETHODIMP LockServer(BOOL fLock);

STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter

REFIID riid, void** ppv);

private:

ULONG m_refCount;

};

####endif

І тепер реалізація фабрики класу CoJournalFactory для класу CoJournal.

//////////////////////////////////////////////////

// // // // CoJournalFactory.cpp: реалізація фабрики класу CoJournalFactory

// // // // для кокласса CoJournal

//////////////////////////////////////////////////

####include "CoJournalFactory.h"

extern ULONG g_lockCount;

extern ULONG g_objCount;

//////////////////////////////////////////////////

// // // // Конструктор і деструкція

//////////////////////////////////////////////////

CoJournalFactory::CoJournalFactory()

{

m_refCount = 0;

g_objCount++;

}

CoJournalFactory::~CoJournalFactory()

{

g_objCount--;

}

////////IUnknown

STDMETHODIMP_(ULONG) CoJournalFactory::AddRef()

{

return ++m_refCount;

}

STDMETHODIMP_(ULONG) CoJournalFactory::Release()

{

if (--m_refCount == 0)

{

delete this;

return 0;

}

else

return m_refCount;

}

STDMETHODIMP CoJournalFactory::QueryInterface(REFIID riid, void** ppv)

{

if(riid == IID_IUnknown)

{

****ppv = (IUnknown*) this;

}

else if(riid == IID_IClassFactory)

{

****ppv = (IClassFactory*) this;

}

else

{

****ppv = NULL;

return E_NOINTERFACE;

}

((((((((IUnknown*)(*ppv)) ->AddRef();

return S_OK;

}

////////IClassFactory

STDMETHODIMP CoJournalFactory::CreateInstance(

LPUNKNOWN pUnkOuter, REFIID riid, void** ppv)

{

if(pUnkOuter!= NULL)

{

return CLASS_E_NOAGGREGATION;

}

CoJournal* pJournalObj = NULL;

HRESULT hr;

pJournalObj = new CoJournal;

hr = pJournalObj ->QueryInterface(riid, ppv);

if (FAILED(hr))

delete pJournalObj;

return hr;

}

STDMETHODIMP CoJournalFactory::LockServer(BOOL fLock)

{

if (fLock)

++++++++g_lockCount;

else

--------g_lockCount;

return S_OK;

}

Закінчуючи розмову про фабрику класу треба помітити, що для неї не треба задавати GUID.

<== предыдущая лекция | следующая лекция ==>
Основні поняття COM технологій | Мова опису інтерфейсів і бібліотека типів
Поделиться с друзьями:


Дата добавления: 2014-01-04; Просмотров: 268; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.072 сек.