Ручна корекція класу

Клас 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:

 

//===== Змінні, необхідні

для

реалізації інтерфейсу

OLE COLOR

m clrFillColor;

//

Колір фону вікна

int

m LightParamfll] ;

//

Параметри освітлення

int

m xPos, m yPos;

//

Поточна позиція миші

HGLRC

m hRC;

//

Контекст OPENGL

HDC

m hdc;

//

Контекст Windows

GLfloat

m ANGLEX;

//

Кут повороту довкола осі X

GLfloat

m ANGLEY;

//

Кут повороту довкола осі Y

GLfloat

m AngleView;

//

Кут перспективи

GLfloat

m fRangeX;

//

Розмір об'єкту уздовж X

GLfloat

m fRangeY;

//

Розмір об'єкту уподовж Y

GLfloat

m fRangeZ;

//

Розмір об'єкту уподовж Z

GLfloat

m dx;

//

Квант зсуву уздовж X

GLfloat

m dy;

//

Квант зсуву уподовж Y

GLfloat

m xTrans;

//

Зсув уздовж X

GLfloat

m yTrans;

//

Зсув уподовж Y

GLfloat

m zTrans;

//

Зсув уподовж Z

GLenum

m FillMode;

//

Режим заповнення полігонів

bool

m_bCaptured;

//

Ознака захвату миші

bool

m bRightButton;

//

Прапор правої кнопки миші

bool

m bQuad;

//

Прапор використання GL QUAD

UINT

m xSize;

//

Поточний розмір вікна уздовж X

UINT

m zSize;

//

Поточний розмір вікна уподовж Y

//====== Масив вершин поверхні

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. Ми бачимо, що в заготівці присутні наступні біти:

  • OLEMISC_RECOMPOSEONRESIZE - повідомляє контейнер, що при зміні розмірів вікна об'єкту останній хоче не просто змінити пропорції, але і виконати складнішу рекомпозицию. Чуйний контейнер повинен запустити сервер і викликати метод lOleObject: :SetExtent, передавши новий розмір вікна;
  • OLEMISC_CANTLINKINSIDE - говорить про те, що після передачі об'єкту контейнером він може бути вибраний, але при цьому не може відкритися в режимі для редагування, тобто при приміщенні об'єкту в буфер обміну контейнер може надати свій зв'язок (link), але не зв'язок з об'єктом;
  • OLEMISC__INSIDEOUT - об'єкт здібний до активізації на місці (in place), але при цьому не потрібно змінювати меню і інструментальну панель в рамках контейнера;
  • OLEMISC__ACTIVATEWHENVISIBLE - ця ознака встановлюється одночасно з попереднім і говорить про те, що об'єкт хоче бути активним всякий раз, коли він стає видимим. Деякі контейнери можуть і вважають за краще ігнорувати цю вказівку;
  • OLEMISC_SETCLIENTSITEFIRST - ця ознака характерна для всіх засобів управління (controls) і він говорить про те, що як функція ініціалізації слід викликати функцію lOleObject: : SetClientSite, яка дозволяє визначити властивості оточення (ambient properties), до того як будуть завантажена інформація з сховища (persistent storage). Далеко не всі контейнери здатні врахувати цю вказівку.

Карти інтерфейсів і властивостей

Далі по коду ви бачите карту макросів 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) інтерфейси.


Примітка

Інтерфейси, що розкриваються за допомогою розглянутого механізму Querylnterface, називаються такими, що входять (incoming), оскільки вони входять в об'єкт (запрошуються) з боку клієнта. Як відзначає Kraig Brockschmidt (у вже згадуваній книзі Inside OLE), вхідні інтерфейси є очима і вухами сом-об'єкту, які сприймають сигнали з навколишнього світу. Але деякі об'єкти можуть не лише слухати, але і сказати щось корисне. Це вимагає від клієнта здібності до діалогу. Двосторонній діалог має на увазі наявність витікаючих (outgoing) інтерфейсів і особливого механізму спілкування, заснованого на обробці подій (events), повідомлень (notifications) або запитів (requests).

Події і запити схожі з 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. За умовчанням запропонований набір з двох нерозлучних прапорів:

  • VIEWSTATUS_SOLIDBKGND - використовувати суцільний фон для вікна на відміну від фону, заснованого на візерунковій кисті (brush pattern);
  • VIEWSTATUS_OPAQUE - об'єкт не містить прозорих частин, тобто повністю непрозорий.

Макрос 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 выбирай уфа

::  Меню ::

Введення

Початок роботи з Visual Studio.Net

Режими відображення координат

Традиційне Windows-приложение

Аналізатор код помилок

Управління файловим деревом

Графіка OPENGL

Тривимірні графіки функцій

Від сирих COM API до проекту ATL

Тривимірна графіка в проекті ATL

З життя студентів

Вирішуємо краєву задачу

Деякі відомості про архітектуру Windows


:: Реклама ::

Створи сайт за допомогою MS Office AsenKat - каталог сайт

:: Статистика ::

Індекс цитування

:: Навигация ::

Головна
Додати у вишукане  

 

 

 


Copyright © Asentli, 2008