Ручная коррекция класса
Обзор класса 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) и когда один клиент предоставляет несколько воронок для восприятия интерфейсов от одного объекта.
Каждая точка соединения СОМ-объекта поддерживает интерфейс iConnectionPoint. С помощью другого интерфейса – iConnectionPointContainer – объект рекламирует клиенту свои точки связи. Клиент пользуется интерфейсом IConnectionPointContainer для получения информации о наличии и количестве исходящих интерфейсов или, что то же самое, точек соединения. Узнав о наличии IConnectionPoint, клиент использует его для передачи объекту указателя на свой сток или нескольких указателей на несколько стоков. Большинство, и Kraig Brockschmidt в том числе, отмечают, что все это довольно сложно усвоить сразу, поэтому не переживайте, если потеряли нить рассуждений в данной информации. Постепенно все уляжется.