конспект лекцій (ТСПП). Конспект лекцій з дисципліни 07 технологія створення програмних продуктів напряму 050101 Компютерні науки
Скачать 14.87 Mb.
|
6.2. Основні поняття COM технологій.Технологія COM (Component Object Model - компонентна об' єктна модель) від Microsoft Перепишемо додаток про книги і журнали, використовуючи ідеологію моделі COM - Component Object Model від Microsoft. Виклад основ цій моделі буде проведень на прикладах. Інтерфейси Нагадаємо, що в моделі COM вусі засновано на інтерфейсах. Інтерфейс - це контракт між тим, що реалізовує цей інтерфейс компонентом і клієнтом, представлень набором визначень методів (нічого окрім визначень методів в інтерфейс включати не можна). Один і тій же інтерфейс можуть реалізувати різні компоненти, написані на різних мовах, але будь-хто компонент, що реалізовує цей інтерфейс, гарантує повну реалізацію його семантики, тобто певний набір методів. Часто базову архітектуру COM визначають за допомогою наступної формули Базова архітектура COM = сервер/клас/інтерфейс/метод Компонент реалізується у вигляді сервера (одного з трьох видів). Сервер є сховищем для одного або декількох класів. Кожен клас реалізує один або декілька інтерфейсів. Кожен інтерфейс визначає один або декілька методів і обов'язково наслідує від стандартного інтерфейсу IUnknown (прямо або побічно). Визначимо спочатку абстрактний базовий інтерфейс IPub (публікація), від якого далі будуть породжені інтерфейси IBook і IJournal (книга і журнал). Тут потрібно відмітити, що в COM немає множинного спадкоємства інтерфейсів і кожен призначений для користувача інтерфейс повинний породжуватися від якого-небудь іншого інтерфейсу (хоч би від IUnknown). Визначення цього інтерфейсу IPub у вигляді заголовного файлу для З++ (IPub.h) наводитися нижче. // // // // IPub.h -- Базовий інтерфейс публікації IPub ####ifndef _IPub_ ####define _IPub_ ####include DECLARE_INTERFACE_(IPub, IUnknown) { STDMETHOD(BSTR bstrTitle) PURE; STDMETHOD(int nYear) PURE; STDMETHOD(BSTR * pbstrInfo) PURE; }; ####endif У цьому прикладі визначений інтерфейс IPub, успадковний від стандартного інтерфейсу IUnknown. У інтерфейсі Ipub визначено 3 методи : .. . . . SetTitle - завдання назви публікації .. . . . SetYear - завдання року публікації .. . . . GetInfo - отримання інформації про публікацію. При описі як самого інтерфейсу, так і методів, що входять в нього, використані наступні макросі: ####define DECLARE_INTERFACE_(iface, baseiface) interface iface: public baseiface ####define STDMETHOD(method) virtual HRESULT __stdcall method ####define PURE = 0 Таким чином DECLARE_INTERFACE_(IPub, IUnknown) означає, що IPub є інтерфейс (ті ж що і struct в С), породжений від IUnknown, а STDMETHOD(BSTR bstrTitle) PURE означає, що чисто віртуальний метод SetTitle повертає стандартну для COM величину типу HRESULT - 32 - бітове значення, що дозволяє визначити успішно або ні пройшов виклик методу, і, у разі неуспіху, де сталася і яка помилка. Очевидно, що можливість аналізу помилок дуже важлива в розподілених застосуваннях. При цьому __stdcall означає, що параметри методу заносяться в стек в порядку справа наліво і перед поверненням функція видаляє із стека свої параметри. При визначенні інтерфейсів завжди використовуються чисто віртуальні функції. Це означає, що не існує реалізації інтерфейсу. Це тільки контракт, що ніяк не обмежує конкретну реалізацію. Для використання цього інтерфейсу треба визначити клас, що наслідує цей інтерфейс (і, можливо, інші інтерфейси), і вже реалізувати цей клас. Відомо, що в різних мовах програмування рядка організовані по- різному. У COM вибрано представлення рядки, що дозволяє працювати з ним в програмах, написаных на різних мовах. Змінна типу BSTR (BASIC String) є рядок, представлень у форматі Unicode (2 байти на один символ), із завершуючим нулем і з префіксом (4 байти), що зберігає довжину рядка (що дозволяє зберігати усередині рядка нульові символи). Є ряд функцій, що полегшують роботові з такими рядками (які для C++ будуть продемонстровані в наступних прикладах). І, нарешті, нагадаємо, що в реалізації цього прикладу засобами ТОП в описі класу CPublication був метод Display, який забезпечував висновок інформації про публікацію на термінал. У даному випадку мі описуємо інтерфейси, які будуть реалізовані в класах, розміщених на сервері. Розміщення самого сервера для клієнта прозоро - це може бути сервер в процесі клієнта, або інший процес на цій же машині, або процес на видаленому комп' ютері. У цих умовах методи інтерфейсу не повинні виконувати вивід на термінал, а повинні повертати результати своєї роботи клієнтові через параметри. У зв'язку з цим тут використовується метод GetInfo, семантика якого - повернення клієнтові рядка з повним описом публікації. Тепер визначимо інтерфейс IBook, похідний від IPub. // // // // IBook.h -- інтерфейс книги IBook ####ifndef _IBook_ ####define _IBook_ ####include "IPub.h" // IPub DECLARE_INTERFACE_(IBook, IPub) { STDMETHOD(BSTR bstrAuthor) PURE; }; ####endif Тут просто додається новий метод SetAuthor, що дозволяє задавати ім 'я автора книги, якого, в загальному випадку, могло і не бути у публікації. Аналогічно визначається інтерфейс IJournal, також похідний від IPub, розширяльний останній методом SetNumber, -завдання номери журналу. // // // // IJournal.h -- інтерфейс журналу IJournal ####ifndef _IJournal_ ####define _IJournal_ ####include "IPub.h" // IPub DECLARE_INTERFACE_(IJournal, IPub) { STDMETHOD(int nNumber) PURE; }; ####endif У рамках моделі COM кожен інтерфейс повинний мати унікальний у просторі та часі ідентифікатор - IID (Interface IDentifier). Ідентифікатор генерується і привласнюється інтерфейсу при його створенні і більше ніколи не міняється. Вусі реалізації цього інтерфейсу повинні використовувати цей ідентифікатор. Користувачі звертаються до цього інтерфейсу по його ідентифікатору. Вусі це дозволяє не турбуватися з приводу привласнення одного і того ж імені різними розробниками різним інтерфейсам. Існує специфікація DCE (Distributed Computing Environment - розподілене середовище обчислень) від Open Software Foundation, котрая визначає UUID - Universally Unique IDentifiers (універсально унікальні ідентифікатори). Ці ідентифікатори формуються на основі мережевої адреси машини і точного годині, що і забезпечує їх унікальність. У COM ці ідентифікатори дістали назву GUID - Globally Unique IDentifiers (глобально унікальні ідентифікатори). Кожен такий ідентифікатор представляється 128 - бітовим числом. У зв'язку з тим, що не усі мови програмування підтримувальні COM, можуть оперувати з такими великими числами, для зберігання GUID використовується наступна структура typedef struct _GUID { unsigned long Data1; unsigned short Data2; unsigned short Data3; unsigned char Data4[8]; } GUID Цю структуру зручно задавати за допомогою наступного макросу ####define DEFINE_GUID(name, \ l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ EXTERN_C const GUID name \ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } Нижче представлень файл iid.h в якому визначені GUID усіх трьох раніше певних інтерфейсів (пізніше в цей файл будуть додані і GUID класів, що реалізовують вказані інтерфейси). Для отримання GUID можна використовувати утиліту guidgen.exe з Visual Studio. Ця утиліта дозволяє отримати визначення нового GUID у вигляді макросу DEFINE_GUID, який можна скопіювати і вставити у файл визначень GUID. У закоментированных рядках цього файлу містяться значення GUID у виді, зручному для перегляданню людиною. Ім 'я ідентифікатора інтерфейсу стандартно формується таким чином - префікс IID_, за яким йде ім 'я інтерфейсу. Наприклад, IID_IPub. // // // // iid.h -- GUID для інтерфейсів // // // // {9A5DE9A0-7225-11d5-98C7-000001223694} DEFINE_GUID(IID_IPub 0000x9a5de9a0, 0x7225, 0x11d5, 0000x98, 0xc7, 0x0, 0x0, 0x1, 0x22, 0x36, 0x94); // // // // {9A5DE9A1-7225-11d5-98C7-000001223694} DEFINE_GUID(IID_IBook 0000x9a5de9a1, 0x7225, 0x11d5, 0000x98, 0xc7, 0x0, 0x0, 0x1, 0x22, 0x36, 0x94); // // // // {9A5DE9A2-7225-11d5-98C7-000001223694} DEFINE_GUID(IID_IJournal 0000x9a5de9a2, 0x7225, 0x11d5, 0000x98, 0xc7, 0x0, 0x0, 0x1, 0x22, 0x36, 0x94); |