|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ручна
корекція класу
Клас COpenGL обслуговуватиме вікно упровадженого сом-об'єкту. Він повинен мати
достатню кількість даних і методів для управління змальовуваною поверхнею,
тому далі уручну введемо відразу багато змін у файл з описом класу
COpenGL. При зміні файлу заголовків класу ми порушимо стиль, заданий стартовою
заготівкою, і повернемося до звичнішому, прийнятому в MFC-приложениях. Перенесемо існуюче
тіло конструктора, а також функції OnDraw у файл реалізації класу OpenGLcpp.
У файлі OpenGLh залишаться лише декларації цих функцій. Нижче приведений повний
опис класу COpenGL з врахуванням нововведень, спрощень і виправлень. Вставте
його замість того тексту, який є у файлі OpenGLh. Після цього вставимо у
файл нові єства за допомогою інструментів Studio.Net: //
OPENGL.h : Declaration of the COpenGL #pragma
once #include
"resource.h" // main symbols #include
<atlctl.h> #include
"_IOpenGLEvents_CP.h" //==========
Допоміжний клас class
CPointSD public: fldat x; float
біля; float
z; // Координати точки в 3D //======
Набір конструкторів і операція привласнення CPoint3D
() { х = біля = z = 0; } CPoint3D
(float cl float c2 float c3) x
= с1; z
= c2; біля
= сЗ; CPoint3D&
operator=(const CPoint3D& pt) x = pt.x; z = pt. z ; Біля = pt.y; return
*this; } CPointSD
(const CPoint3D& pt) *this = pt; //==== Основний клас, що експонує інтерфейс IQpenGL class
ATL_NO_VTABLE COpenGL : p.ublic
CQomObjectRootEx<CComSingleThreadModel> public
CStockPropImpKCOpenGL, IOpenGL> public
IPersistStreamInitImpl<COpenGL> public
I01eControlImpl<COpenGL> public
I01eObjectImpl<COpenGL> public
I01eInPlaceActiveObjectImpl<COpenGL> public
IViewObjectExImpl<COpenGL> public
I01eInPlaceObjectWindowlessImpl<COpenGL> public
ISupportErrorlnfo public
IConnectionPointContainerImpl<COpenGL> public
CProxy_IOpenGLEvents<COpenGL> public
IPersistStorageImpl<COpenGL> public
ISpecifyPropertyPagesImpl<COpenGL> public
IQuickActivateImpl<COpenGL> public
IDataObjectImpl<COpenGL> public
IProvideClassInfo2Impl<&CLSID_OpenGL &_uuidof(_IOpenGLEvents)
&LIBID_ATLGLLib>, public CComCoClass<COpenGL &CLSID_OpenGL>, public CComControl<COpenGL> { public:
//======
Масив вершин поверхні vector
<CPoint3D> m_cPoints; //======
Функції, присутні в стартовій заготівці COpenGL(); HRESULT
OnDraw(ATL DRAWINFO& di); void
OnFillColorChangedO ; DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE OLEMISC_CANTLINKINSIDE
| OLEMISC_INSIDEOUT
| OLEMISC_ACTIVATEWHENVISIBLE
| OLEMISC_SETCLIENTSITEFIRST
| DECLARE_REGISTRY_RESOURCEID(IDR_OPENGL) BEGIN_COM_MAP(COpenGL) COM_INTERFACE_ENTRY(IQpenGL) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IViewObj
ectEx) COM_INTERFACE_ENTRY(IViewObj
ect2) COM_INTERFACE_ENTRY(IViewObj
ect) COM_INTERFACE_ENTRY(I01eInPlaceObjectWindowless) COM_INTERFACE_ENTRY(I01eInPlaceObject) COM_INTERFACE_ENTRY2(IQleWindow IQlelnPlaceObjectWindowless) COM_INTERFACE_ENTRY(lOlelnPlaceActiveObject) COM_INTERFACE_ENTRY(lOleControl) COM_INTERFACE_ENTRY(lOleObj
ect) COM_INTERFACE_ENTRY(IPersistStreamInit) COM_INTERFACE_ENTRY2(IPersist,
IPersistStreamlnit) COM_INTERFACE_ENTRY(ISupportErrorlnfo) COM_INTERFACE_ENTRY(IConnectionPointContainer) COM_INTERFACE_ENTRY(ISpecifyPropertyPages) COM_INTERFACE_ENTRY(IQuickActivate) COM_INTERFACE_ENTRY(IPersistStorage) COM_INTERFACE_ENTRY(IDataObject) COM_INTERFACE_ENTRY(IProvideClassInfo) COM_INTERFACE_ENTRY(IProvideClassInfo2)
END_COM_MAP() BEGIN_PROP_MAP(COpenGL) PROP_DATA_ENTRY("_cx", m_sizeExtent. ex, VTJJI4) PROP_DATA_ENTRY("_cy",
m_sizeExtent.cy, VTJJI4) PROP_ENTRY("FillColor",DISPID_FILLCOLOR, CLSID_StockColorPage) END_PROP_MAP() BEGIN_CONNECTION_POINT_MAP(COpenGL) CONNECTION_POINT_ENTRY(DIID_IQpenGLEvents) END_CONNECTION_POINT_MAP() BEGIN_MSG_MAP(COpenGL) CHAIN_MSG_MAP(CComControKCOpenGL>) DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP() //====== Підтримка інтерфейсу ISupportsErrorlnfо STDMETHOD(InterfaceSupportsErrorlnfo)(REFIID riid) { static const IID* arr[] = { &IID_IOpenGL }; for (int i=0; ixsizeof(arr)/sizeof(arr[0]); i++) { if
(InlineIsEqualGUID(*arr[i], riid)) return S_OK; } return S_FALSE; } //======
Підтримка інтерфейсу IViewObjectEx DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND
| VIEWSTATUS_OPAQUE) //======
Підтримка інтерфейсу IQpenGL public:
DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void
FinalRelease() {
} //======
Експоновані методи STDMETHODIMP GetLightParams(int* pPos); STDMETHODIMP SetLightParam(short Ip, int nPos); STDMETHODIMP
ReadData(void); //======
Нові методи класу //======
Установка параметрів освітлення void
SetLight (); //======
Створення демонстраційного графіка void
DefaultGraphic(); //======
Читання файлу з даними про графіку bool
DoRead(HANDLE hFile); // Заповнення координат точок графіка за даними з буфера void
SetGraphPoints(BYTE* buff, DWORD nSize); //======
Управління кольором фону вікна void
SetBkColor (); //== Створення зображення у вигляді списку команд OPENGL void DrawScene(); }; OBJECT
ENTRY AUTO (_uuidof (OPENGL), COpenGL) Огляд
класу COpenGL Початкові рядки коди
класу повинні здатися вам знайомими, оскільки ви вже знаєте, що майстер ATL ControlWizard
надає ко-классу безліч батьків для забезпечення тієї функціональності,
яка була замовлена при створенні стартової заготівки. Макрос DECLARE_OLEMISC_STATUS
задає набір бітових ознак, зібраних в типа перерахування OLEMISC
(miscellaneous - всілякі, такі, що не належать одній
стороні опису). Вони описують різні характеристики сом-об'єкту або класу.
Контейнер може з'ясувати ці параметри за допомогою методу lOleObject: :GetMiscStatus.
Деякі налаштування потрапляють в спеціальний розділ реєстру для сервера CLSiD\MiscStatus.
Ми бачимо, що в заготівці присутні наступні біти:
Карти
інтерфейсів і властивостей Далі по коду ви
бачите карту макросів COM map, яка приховує механізм надання клієнтові інтерфейсів
за допомогою методу Querylnterf асові (vtable-интерфейсы). Як ви можете бачити,
каркас сервера надає і підтримує досить багато інтерфейсів, не
вимагаючи від нас яких-небудь зусиль. За сом-картою слідує карта властивостей (див. BEGIN_PROP_MAP),
яка зберігає такі описи властивостей, як індекси диспетчеризації типа
DISPID, індекси сторінок властивостей (property pages) типа CLSID, а також індекс інтерфейсу
IDispatch типа iID. Якщо звернутися до документації, то там сказано, що
ім'я PROP_DATA_ ENTRY є ім'ям функції, а не макросом, як природно було
б передбачити. Виклик цієї функції робить дані, які задані параметрами, стійкими
(persistent). Це означає, що якщо додаток-клієнт зберігає свій
документ з упровадженим в його вікно елементом ACTIVEX, то розміри m_sizeExtent, задані
параметром функції, теж будуть збережені. Трохи нижче буде описано, як
вставити в карту елемент, що описує нову сторінку властивостей. Карта
точок з'єднання Наступна карта BEGIN_CONNECTION_POINT_MAP описує інтерфейси крапок з'єднання (або захвату), які характерні для сом-об'єктів, що сполучаються (connectable). Так називаються об'єкти, які надають клієнтові витікаючі (outgoing) інтерфейси.
Події і
запити схожі з Windows-сообщениями,
які також інформують вікно про якусь подію (WM_SIZE, WM_COMMAND) або
запрошують якісь дані (WM_CTLCOLOR, WM_QUERYENDSESSION). Точки зв'язку (connection
points) надаються об'єктом для кожного витікаючого з нього інтерфейсу.
Клієнт, що уміє слухати, реалізує ці інтерфейси за допомогою об'єкту, званого
sink (стік, злив). Його можна уявити собі у вигляді воронки, яку клієнт
підставляє для того, щоб об'єкт міг зливати в неї свої повідомлення. З точки
зору стоку витікаючі (outgoing) інтерфейси є такими, що входять (incoming).
Стік допомагає клієнтові слухати об'єкт. Можливі варіанти, коли одна воронка
підставляється для сприйняття інтерфейсів від декількох різних сом-об'єктів (multicasting)
і коли один клієнт надає декілька воронок для сприйняття інтерфейсів
від одного об'єкту. Кожна точка
з'єднання сом-об'єкту підтримує інтерфейс iConnect-ionPoint. За допомогою іншого
інтерфейсу - iConnectionPointContainer - об'єкт рекламує клієнтові свої точки
зв'язку. Клієнт користується інтерфейсом IConnectionPointContainer для здобуття
інформації про наявність і кількість витікаючих інтерфейсів або, що те ж саме,
точок з'єднання. Дізнавшись про наявність IConnectionPoint, клієнт використовує його для
передачі об'єкту покажчика на свій стік або декількох покажчиків на декілька
стоків. Більшість, і Kraig Brockschmidt у тому числі, відзначають, що все це
досить складно засвоїти відразу, тому не переживайте, якщо втратили нитку міркувань
в даній інформації. Поступово все уляжеться. Треба відзначити, що в цій частині СОМ використовується найбільше число жаргонних слів. Спробуємо з їх допомогою коротко описати механізм, а також сценарій спілкування між клієнтом і З Про м-об'єктом при задіюванні витікаючих інтерфейсів. Спочатку об'єкт безпорадний і не може сказати що-небудь клієнтові. Ініціатива має бути проявлена клієнтом - контейнером сом-об'єкту. Він звичайним дорогою запрошує біля сервера покажчик на інтерфейс IConnectionPointContainer, потім за допомогою методів цього інтерфейсу (EnumConnectionPoints, FindConnectionPoint) отримує покажчик на інтерфейс iConnectionPoint. Далі клієнт використовує метод Advise останнього інтерфейсу для того, щоб передати об'єкту покажчик на свій стік - воронку для слухання або зливу повідомлень. Починаючи з цього моменту об'єкт має можливість розмовляти, оскільки він має воронку або покажчик на інтерфейс посередника у вигляді sink. Змусити замовкнути об'єкт може знову ж таки клієнт. Для цього він користується методом Unadvise інтерфейсу IConnectionPoint. Зайва складність всієї конструкції пояснюється міркуваннями розширюваності (extensibility). Об'єкти, що сполучаються, можуть ускладнюватися незалежно від точок з'єднання, а точки зв'язку можуть розвиватися, не приносячи тривог об'єктам, що сполучаються. Мене подібний аргумент не переконав, але ми повинні жити на цьому світі, який би він не був. Карта
повідомлень
Карта повідомлень, яка повинна викликати у вас асоціацію з картою повідомлень MFC,
містить незнайомий макрос CHAIN_MSG_MAP. Він перенаправляє необроблені повідомлення в
карту повідомлень базового класу. Річ у тому, що ATL допускає
існування альтернативних карт повідомлень. Вони визначаються макросами ALT_MSG_MAP. Тоді
треба використовувати макрос CHAIN_ MSG_MAP_ALT. Ми не обговорюватимемо цю тему детальніше. Наступний
макрос - DEFAULT_ REFLECTION_HANDLER - забезпечує обробник за умовчанням
(у вигляді DefWindowProc) для дочірніх вікон елементу ACTIVEX, які отримують
відбиване (reflected) повідомлення, але не обробляють його. Інтерфейс
ISupportsErrorlnfо Підтримка цього інтерфейсу проста. У методі interfaceSupportsErrorinfo є статичний масив а г г, в якому зберігаються адреси ідентифікаторів новостворюваних інтерфейсів, поки він у нас один HD_iOpenGL. У цьому ж методі здійснюється пробіг по всьому масиву індексів і виклик функції inlinelsEqualGUio, яка доки не документована, але її сенс може бути виведений з її імені. Інтерфейс
IViewObjectEx Цей
інтерфейс є розширенням інтерфейсу iviewobject2. Він підтримує обробку
об'єктів непрямокутної форми. Наприклад, їх покращуване (flicker-free - що
не моргає) перемальовування, перевірку попадання курсора всередину об'єкту, зміна
розмірів і підлозі прозорість об'єктів. Моргання при перемальовуванні виникає через
те, що перед нею стирається весь вміст вікна. Боротися з цим можна,
наприклад, так: малювати в bitmap (растровий малюнок), не пов'язаний з екраном, а
потім копіювати весь bitmap на екран однією операцією. Нас ця проблема не хвилює, оскільки
ми використовуватимемо можливості OPENGL. Мабуть, можна відмовитися від послуг цього
інтерфейсу при оформленні замовлення у майстра ATL. Макрос DECLARE_VIEW_STATUS задає
прапори прозорості об'єкту, визначені в структурі VIEWSTATUS. За умовчанням
запропонований набір з двох нерозлучних прапорів:
Макрос DECLARE_PROTECT_FINAL_CONSTRUCT захищає об'єкт від видалення у випадку, якщо внутрішній (агрегований) об'єкт обнулить лічильник заслань на наш об'єкт. Метод CGomObjectRootEx: : FinalConstruct дозволяє створити агрегований об'єкт за допомогою функції CoCreatelnstance. Ми не користуватимемося цією можливістю. Карта
об'єктів У аналогічному
проекті, створеному в рамках Visual Studio би, ви могли бачити карту об'єктів
ов JECT_MAP, яка забезпечує підтримку реєстрації, ініціалізації і створення
об'єктів. Карта об'єктів має звичну структуру: BEGIN_OBJECT_MAP OBJECT_ENTRY(CLSID_MyClass, MyClass) END_OBJECT_MAP() де макрос ов JECT_ENTRY вводить внутрішній механізм відображень (тар) ідентифікаторів класів В їх імена. При виклику функції CComModule; :RegisterServer вона вносить до реєстру записи, відповідні кожному елементу в карті об'єктів. Тут в рамках Studio.Net, ви бачите інший макрос - OBJECT_ENTRY_AUTO, що виконує схожу функцію, але при цьому не потребує обрамлення з операторних дужок.
рекламодавці: / LF KS выбирай уфа |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||