Меню сайта
Главная
Общие сведения
Архитектура Windows
Программируем на vs.net
Студенческие заметки
Статьи
Контакты
Интернет магазин
Visual Studio 2008 Standard
Переход на Visual Basic .NET
Тестирование и отладка приложений в VB.NET
Поддержка и оптимизация на VB.NET
Создание наборов данных ADO.NET
Сопровождение Web-приложений в VB.NET
Введение в ADO.NET
Editor.NET
MemPort.NET
Управление автономными данными

Весь каталог

Новости
Макроподстановка ASSERT_VALID в отладочной (Debug) версии проекта проверяет на осмысленность полученный указатель и дает сообщение об ошибке, в случае когда указатель равен нулю или в действительности не является адресом объекта класса, производного от класса CObject. Если вы просмотрите иерархию классов MFC, то увидите, что CObject является отцом-прародителем всех классов, потомки которых использованы в нашем приложении. Подробнее "Классы приложения"
При создании нового проекта Studio.Net автоматически создает рабочее пространство и помещает в него этот проект. Вот перечень шагов для создания нового проекта и нового рабочего пространства (solution), его содержащего. Подробнее "Создание нового проекта"
Откройте файл ChildView.cpp, который содержит коды реализации методов класса CChildView. Его имя содержит ложный намек на происхождение от CView. На самом деле он происходит от класса CWnd и инкапсулирует функциональность окна, оккупирующего клиентскую область окна рамки, которое управляется классом CMainFrame. Простое окно, как вы помните, для перерисовки своего содержимого, вместо метода OnDraw использует метод OnPaint. Найдите этот метод в классе CChildView и убедитесь, что в нем контекст устройства создается, а не приходит в качестве параметра от каркаса приложения, как это было в приложениях, поддерживающих архитектуру документ — представление. Подробнее "Класс окна для отображения графика"
Установка параметрпв освещения осуществляется подобно тому, как это делалось в предыдущем уроке. Но здесь мы храним все параметры для тога, чтобы можно было управлять освещенностью изображения. Немного позже разработаем диалог, с помощью которого пользователь программы сможет изменять настройки освещения, а сейчас введите коды функции SetLight. Подробнее "Параметры освещения"
Картинная галерея

Общие сведения

Программируем на vs.net

Архитектура программного комплекса

Результаты взаимодействия Visual Studio

Реализация

Архитектура Windows

Солирование

Использование материалов

Причины возникновения

Методы

Партнеры проекта

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

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

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, выполняющий сходную функцию, но при этом не нуждается в обрамлении из операторных скобок.

Интернет магазин

 

1510 руб.

Переход на Visual Basic .NET

Слушатели курса познакомятся с различиями между Visual Basic 6.0 и Visual Basic .NET, а также с новыми возможностями Visual Studio .NET. Целевая аудитория: разработчики, имеющие опыт работы с предыдущими версиями Microsoft Visual Basic и желающие перейти на Microsoft Visual Basic .NET. 

Список версий:

Переход на Visual Basic .NET


1510 руб.

Тестирование и отладка приложений в VB.NET

На курсе обсуждаются методы тестирования и отладки программ, использование классов Debug и Trace из библиотеки классов .NET Framework, и работа с отладчиками из Visual Studio .NET и .NET Framework SDK. Целевая аудитория: Web-разработчики, желающие обновить свои знания и навыки в области тестирования и отладки приложений в среде Visual Studio .NET или подготовиться к сертификации MCAD или MCSD .NET. 

Список версий:

Тестирование и отладка приложений в VB.NET


 

  Все права защищены.
  Копирование запрещено.

Rambler's Top100
  Студия профессионального дизайна
  Дизайн: Студия Onta.ru